diff options
Diffstat (limited to 'test')
304 files changed, 19706 insertions, 6349 deletions
diff --git a/test/mocks/pnfsimulator/.gitignore b/test/mocks/pnfsimulator/.gitignore index 3fa204a3b..daf6cf225 100644 --- a/test/mocks/pnfsimulator/.gitignore +++ b/test/mocks/pnfsimulator/.gitignore @@ -1,4 +1,3 @@ -.idea -target -*.iml -logs +**/*.iml +**/.idea +**/target
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/README.md b/test/mocks/pnfsimulator/README.md deleted file mode 100644 index 8c27bd474..000000000 --- a/test/mocks/pnfsimulator/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# PNF Simulator -Simulator that generates VES events related to PNF PNP integration. - -##Downloading simulator -Official version of simulator can be downloaded for public ONAP docker registry as image. -*docker login -u anonymous -p anonymous nexus3.onap.org:10003* - -Another option is to checkout PNF Simulator project from ONAP Git repository. - -##Usage of simulator - -###Configuration -The configuration for simulator is stored in */config/config.json* file. -It contains all parameters for simulation such as duration time,interval between messages and values of the configurable fields of VES message. -If you want to change duration or value of message sending to VES collector you just need to edit this file. -The message that is being sent to VES is built inside the simulator and it's content can be found in log of the simulator. -Proper config must contain *simulatorParams*, *commonEventHeaderParams* and *pnfRegistrationParams* or notificationParams. - -###Running simulator -The recommended way is to checkout PNF Simulator project from ONAP Git repository and use *simulator*.sh script. -If you copy *simulator.sh* script to another location, keep in mind to copy also *docker-compose.yml* and directories: *config,json_schema and netconf*. -In order to run simulator, invoke ./simulator.sh start -You may be asked for providing password for ypur user during startup. -Script downloads if necessary needed Docker images and runs instances of these images. -The easiest way is to download or generate PNF Simulator zip archive with all needed configuration files. - -###Logging -It is possible to get access to logs by invocation of *./simulator.sh* logs. -The content of the logs is related to the last simulator run. -Every start of simulator will generate new logs. - -###SFTP support -PNF Simulator allows to serve files via SFTP server. SFTP server has predefined user sftp-user. -Connection to SFTP server is being done with usage of SSH keys. Private key is stored in *ssh* directory. -In order to download *sftp-file.txt* file simply run *sftp -P 2222 -i ssh/ssh_host_rsa_key sftp-user@localhost:sftp/sftp-file.txt* -In order to add a new file (e.g. test.zip), put the file into *sftp* directory and run simulator. -After that again execute sftp command: *sftp -P 2222 -i ssh/ssh_host_rsa_key sftp-user@localhost:sftp/test.zip* -In order to disable usage of SSH keys and start using password, change in *docker-compose.yml* service *sftp-service* entry *command* from *sftp-user::1001* to *sftp-user:password:1001* - -###FTPES support -PNF Simulator allows to serve files via FTPES server. FTPES server has predefined user *onap* with password *pano*. - -####FTPES support with TLS enabled -By default TLS support is enabled. In order to verify connection, please use *FileZilla* for testing. - -####FTPES support for TLS disabled -For local testing TLS may be disabled, but it's not recommended. -In order to set up such configuration, comment or remove in *ftpes-server* service section in *docker-compose.yml* following entries: -- *./ftpes/tls/:/etc/ssl/private/* -- *ADDED_FLAGS: --tls=2* - -After that execute *./simulator.sh stop* and when it's finished *./simulator.sh start* . - -In order to connect execute command *ftp -p localhost 2221* and, when requested, provide user and password. -In order to download a file execute, while still being logged in, *get file-name-to-be-downloaded*. - -###FTPES support for VSFTPD server -PNF Simulator allows to serve files via FTPES VSFTPD server. VSFTPD server has predefined user *onap* with password *pano*. -By default TLS support is enabled. Required certificates and keys are generated via vsftpd_certs_keys_generator.sh and located in ./ftpes/vsftpd/tls/ . -We can generate our own certificates and keys using that script and passing 'secret' password when you are asked for entering keystore password. In other cases just press ENTER to go on. -Configuration of VSFTPD server is located in ./ftpes/vsftpd/configuration/vsftpd_ssl.conf . -Docker-compose contains VSFTPD server image with it's configurations. - -In order to verify connection, please use *FileZilla* for testing. - -###Developer mode -For development of PNF Simulator, run *simulator.sh* start-dev in order to run minimal necessary set of supporting services such as Netopeer of FTP servers. -After that it is possible to run PNF Simulator from IDE. diff --git a/test/mocks/pnfsimulator/checkstyle-suppressions.xml b/test/mocks/pnfsimulator/checkstyle-suppressions.xml new file mode 100644 index 000000000..8d9560789 --- /dev/null +++ b/test/mocks/pnfsimulator/checkstyle-suppressions.xml @@ -0,0 +1,46 @@ +<?xml version="1.0"?> +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + + +<!DOCTYPE suppressions PUBLIC + "-//Checkstyle//DTD SuppressionFilter Configuration 1.0//EN" + "https://checkstyle.org/dtds/suppressions_1_0.dtd"> + +<suppressions> + <suppress checks=".*" files="\.java" lines="1-20" + /> + <suppress checks=".*" files="\.properties" + /> + <suppress checks="javadoc" files="\.java" + /> + <suppress checks="LineLength" files="\.java" + /> + <suppress checks="HiddenField" files="\.java" + /> + <suppress checks="FinalClass" files="\.java" + /> + <suppress checks="FinalParameters" files="\.java" + /> + <suppress checks="AvoidInlineConditionals" files="\.java" + /> + <suppress checks="DesignForExtension" files="\.java" + /> +</suppressions> diff --git a/test/mocks/pnfsimulator/config/config.json b/test/mocks/pnfsimulator/config/config.json deleted file mode 100644 index 636e0132e..000000000 --- a/test/mocks/pnfsimulator/config/config.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "simulatorParams": { - "vesServerUrl": "http://VES-HOST:VES-PORT/eventListener/v7", - "testDuration": "10", - "messageInterval": "1" - }, - "commonEventHeaderParams": { - "eventName": "pnfRegistration_Nokia_5gDu", - "nfNamingCode": "gNB", - "nfcNamingCode": "oam", - "sourceName": "NOK6061ZW3", - "sourceId": "val13", - "reportingEntityName": "NOK6061ZW3" - }, - "pnfRegistrationParams": { - "serialNumber": "6061ZW3", - "vendorName": "Nokia", - "oamV4IpAddress": "val3", - "oamV6IpAddress": "val4", - "unitFamily": "BBU", - "modelNumber": "val6", - "softwareVersion": "val7", - "unitType": "val8", - "additionalFields": { - "attachmentPoint": "bla-bla-30-3", - "svlan": "1005", - "cvlan": "678" - } - }, - "notificationParams": { - "changeIdentifier": "PM_MEAS_FILES", - "changeType": "FileReady", - "arrayOfNamedHashMap": [ - { - "name": "A20161221.1031-1041.bin.gz", - "hashMap": { - "location": "ftpes://192.169.0.1:22/ftp/rop/A20161224.1030-1045.bin.gz", - "compression": "gzip", - "fileFormatType": "org.3GPP.32.435#measCollec", - "fileFormatVersion": "V10" - } - }, - { - "name": "A20161222.1042-1102.bin.gz", - "hashMap": { - "location": "ftpes://192.168.0.102:22/ftp/rop/A20161224.1045-1100.bin.gz", - "compression": "gzip", - "fileFormatType": "org.3GPP.32.435#measCollec", - "fileFormatVersion": "V10" - } - } - ] - } -} diff --git a/test/mocks/pnfsimulator/deployment/PnP_PNF_sim_heat_template_Ubuntu_16_04.yml b/test/mocks/pnfsimulator/deployment/PnP_PNF_sim_heat_template_Ubuntu_16_04.yml deleted file mode 100644 index 5dd8e6d58..000000000 --- a/test/mocks/pnfsimulator/deployment/PnP_PNF_sim_heat_template_Ubuntu_16_04.yml +++ /dev/null @@ -1,165 +0,0 @@ -description: Heat template that deploys PnP PNF simulator -heat_template_version: '2013-05-23' -outputs: - PNF_PnP_simualtor_private_ip: - description: IP address of PNF_PnP_simualtor in private network - value: - get_attr: [PNF_PnP_simualtor, first_address] - PNF_PnP_simualtor_public_ip: - description: Floating IP address of PNF_PnP_simualtor in public network - value: - get_attr: [PNF_PnP_simualtor_public, floating_ip_address] -parameters: - flavor_name: - description: Type of instance (flavor) to be used - label: Flavor - type: string - image_name: - description: Ubuntu 16.04 image to be used - label: Image name or ID - type: string - key_name: - description: Public/Private key pair name - label: Key pair name - type: string - private_net_id: - description: Private network id - label: Private network name or ID - type: string - private_subnet_id: - description: Private subnet id - label: Private subnetwork name or ID - type: string - public_net_id: - description: Public network that enables remote connection to VNF - label: Public network name or ID - type: string - security_group: - default: default - description: Security group to be used - label: Security Groups - type: string - proxy: - default: '' - description: Proxy - label: Proxy - type: string - correlation_id: - default: 'someId' - description: Correlation ID - label: Correlation ID - type: string - VES-HOST: - default: 'VES-HOST' - description: VES collector host ip - label: VES ip - type: string - VES-PORT: - default: 'VES-PORT' - description: VES collector host port - label: VES port - type: string -resources: - PNF_PnP_simualtor: - properties: - flavor: - get_param: flavor_name - image: - get_param: image_name - key_name: - get_param: key_name - networks: - - port: - get_resource: PNF_PnP_simualtor_port0 - user_data: - str_replace: - params: - $proxy: - get_param: proxy - $VES-PORT: - get_param: VES-PORT - $VES-HOST: - get_param: VES-HOST - $correlation_id: - get_param: correlation_id - template: | - #!/bin/bash - - set_versions () { - DOCKER_VERSION=17.03 - DOCKER_COMPOSE_VERSION=1.22.0 - PROTOBUF_VERSION=3.6.1 - } - - enable_root_ssh () { - sed -i 's/PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config - sed -i 's/PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config - service sshd restart - echo -e "onap\nonap" | passwd root - } - - update_os () { - rm -rf /var/lib/apt/lists/* - apt-get clean - apt-get update - } - - docker_install_and_configure () { - curl "https://releases.rancher.com/install-docker/$DOCKER_VERSION.sh" | sh - mkdir -p /etc/systemd/system/docker.service.d/ - cat > /etc/systemd/system/docker.service.d/docker.conf << EOF - [Service] - ExecStart= - ExecStart=/usr/bin/dockerd -H fd:// --insecure-registry=nexus3.onap.org:10003 - Environment="HTTP_PROXY=$proxy" - Environment="HTTPS_PROXY=$proxy" - EOF - systemctl daemon-reload - systemctl restart docker - apt-mark hold docker-ce - docker login -u docker -p docker nexus3.onap.org:10003 - } - - docker_compose_install () { - curl -L "https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - chmod +x /usr/local/bin/docker-compose - } - - pnf_sim_file_checkout () { - cd /root; git clone https://gerrit.onap.org/r/integration - printf "{\n \"simulatorParams\": {\n \"vesServerUrl\": \"http://$VES-HOST:$VES-PORT/eventListener/v7\",\n \"testDuration\": \"10\",\n \"messageInterval\": \"1\"\n },\n \"commonEventHeaderParams\": {\n \"eventName\": \"pnfRegistration_Nokia_5gDu\",\n \"nfNamingCode\": \"gNB\",\n \"nfcNamingCode\": \"oam\",\n \"sourceName\": \"$correlation_id\",\n \"sourceId\": \"val13\",\n \"reportingEntityName\": \"NOK6061ZW3\"\n },\n \"pnfRegistrationParams\": {\n \"serialNumber\": \"6061ZW3\",\n \"vendorName\": \"Nokia\",\n \"oamV4IpAddress\": \"val3\",\n \"oamV6IpAddress\": \"val4\",\n \"unitFamily\": \"BBU\",\n \"modelNumber\": \"val6\",\n \"softwareVersion\": \"val7\",\n \"unitType\": \"val8\"\n }\n}" > integration/test/mocks/pnfsimulator/config/config.json - } - - start_simulator () { - docker login -u docker -p docker nexus3.onap.org:10003 - cd ~/integration/test/mocks/pnfsimulator - ./simulator.sh start - } - - set_versions - enable_root_ssh - update_os - docker_install_and_configure - docker_compose_install - pnf_sim_file_checkout - start_simulator - - type: OS::Nova::Server - PNF_PnP_simualtor_port0: - properties: - fixed_ips: - - subnet_id: - get_param: private_subnet_id - network_id: - get_param: private_net_id - security_groups: - - get_param: security_group - type: OS::Neutron::Port - PNF_PnP_simualtor_public: - properties: - floating_network_id: - get_param: public_net_id - port_id: - get_resource: PNF_PnP_simualtor_port0 - type: OS::Neutron::FloatingIP - diff --git a/test/mocks/pnfsimulator/docker-compose.yml b/test/mocks/pnfsimulator/docker-compose.yml deleted file mode 100644 index bbb983fd4..000000000 --- a/test/mocks/pnfsimulator/docker-compose.yml +++ /dev/null @@ -1,83 +0,0 @@ -version: '3' - -services: - pnf-simulator: - container_name: pnf-simulator - image: nexus3.onap.org:10003/onap/pnf-simulator:4.0.0-SNAPSHOT - ports: - - "5000:5000" - volumes: - - ./logs:/var/log - - ./json_schema:/json_schema - env_file: - - ./config/netconf.env - restart: on-failure - depends_on: - - netopeer - - netopeer: - container_name: netopeer - image: sysrepo/sysrepo-netopeer2:latest - ports: - - "830:830" - - "6513:6513" - volumes: - - ./netconf:/netconf - - ./netopeer_tls_cfg:/netopeer_tls_cfg - env_file: - - ./config/netconf.env - restart: on-failure - depends_on: - - sftp-server - - ftpes-server-pure-ftpd - - ftpes-server-vsftpd - command: bash -c "/netopeer_tls_cfg/entrypoint.sh" - - sftp-server: - container_name: sftp-server - image: atmoz/sftp:alpine - ports: - - "2222:22" - volumes: - - ./sftp:/home/sftp-user/sftp - - ./ssh/ssh_host_rsa_key.pub:/home/sftp-user/.ssh/keys/ssh_host_rsa_key.pub:ro - restart: on-failure - command: sftp-user::1001 - - ftpes-server-pure-ftpd: - container_name: ftpes-server-pure-ftpd - image: stilliard/pure-ftpd:latest - ports: - - "2221:21" - - "30000-30009:30000-30009" - volumes: - - ./ftpes/files:/home/ftpusers/onap - - ./ftpes/pure-ftpd/userpass/:/etc/pure-ftpd/passwd/ - - ./ftpes/pure-ftpd/tls/:/etc/ssl/private/ - environment: - PUBLICHOST: localhost - ADDED_FLAGS: --tls=2 - FTP_USER_HOME: onap - restart: on-failure - - ftpes-server-vsftpd: - container_name: ftpes-server-vsftpd - image: docker.io/panubo/vsftpd - ports: - - "8221:21" - - "8001-8010:8001-8010" - environment: - FTP_USER: onap - FTP_PASSWORD: pano - PASV_ADDRESS: localhost - PASV_MIN_PORT: 8001 - PASV_MAX_PORT: 8010 - volumes: - - ./ftpes/vsftpd/tls/vsftpd.crt:/etc/ssl/private/vsftpd.crt:ro - - ./ftpes/vsftpd/tls/vsftpd.key:/etc/ssl/private/vsftpd.key:ro - - ./ftpes/vsftpd/configuration/vsftpd_ssl.conf:/etc/vsftpd_ssl.conf:ro - - ./ftpes/files/onap/ftpes-onap.txt:/home/vsftpd/onap/ftpes-onap.txt:ro - - ./ftpes/files/onap/ftpes-onap.txt:/srv/ftpes-onap.txt:ro - restart: on-failure - command: vsftpd /etc/vsftpd_ssl.conf - diff --git a/test/mocks/pnfsimulator/ftpes/files/ftpes-noone.txt b/test/mocks/pnfsimulator/ftpes/files/ftpes-noone.txt deleted file mode 100644 index 3f1caaed7..000000000 --- a/test/mocks/pnfsimulator/ftpes/files/ftpes-noone.txt +++ /dev/null @@ -1 +0,0 @@ -sample message
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/ftpes/files/onap/ftpes-onap.txt b/test/mocks/pnfsimulator/ftpes/files/onap/ftpes-onap.txt deleted file mode 100644 index 8e78dac41..000000000 --- a/test/mocks/pnfsimulator/ftpes/files/onap/ftpes-onap.txt +++ /dev/null @@ -1 +0,0 @@ -sample message v2
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/configuration/vsftpd_ssl.conf b/test/mocks/pnfsimulator/ftpes/vsftpd/configuration/vsftpd_ssl.conf deleted file mode 100644 index 3e9cd7c66..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/configuration/vsftpd_ssl.conf +++ /dev/null @@ -1,56 +0,0 @@ -# Server Config -anonymous_enable=NO -local_enable=YES -write_enable=YES -local_umask=022 -dirmessage_enable=YES - -# Security and User auth -chroot_local_user=YES -pam_service_name=vsftpd_virtual -virtual_use_local_privs=YES -chmod_enable=NO -user_config_dir=/etc/vsftpd/user_conf -user_sub_token=$USER -#local_root=/srv/$USER -local_root=/srv/ -userlist_enable=NO -allow_writeable_chroot=YES - -# Logging -log_ftp_protocol=YES -xferlog_enable=YES -xferlog_std_format=YES -#xferlog_file=/dev/stdout -syslog_enable=NO -dual_log_enable=YES - -# Remap all login users to this username -guest_enable=YES -guest_username=ftp -hide_ids=YES - -# Networking -connect_from_port_20=NO -listen=YES -tcp_wrappers=YES -pasv_min_port=8001 -pasv_max_port=8010 - -# SSL -ssl_enable=Yes -require_ssl_reuse=NO -force_local_data_ssl=YES -force_local_logins_ssl=YES -ssl_ciphers=HIGH -allow_anon_ssl=NO - -ssl_tlsv1=YES -ssl_sslv2=YES -ssl_sslv3=YES -rsa_cert_file=/etc/ssl/private/vsftpd.crt -rsa_private_key_file=/etc/ssl/private/vsftpd.key - -#require_cert=YES -#ssl_request_cert=YES -#ca_certs_file=/home/vsftpd/onap/client.crt
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/cert.der b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/cert.der Binary files differdeleted file mode 100644 index 24ac26c69..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/cert.der +++ /dev/null diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/cert.pkcs12 b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/cert.pkcs12 Binary files differdeleted file mode 100644 index 3983e748a..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/cert.pkcs12 +++ /dev/null diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/keystore.jks b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/keystore.jks Binary files differdeleted file mode 100644 index 6285f8e9e..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/keystore.jks +++ /dev/null diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/truststore.jks b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/truststore.jks Binary files differdeleted file mode 100644 index 81872195d..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/truststore.jks +++ /dev/null diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.crt b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.crt deleted file mode 100644 index 0aaee0eec..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.crt +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDvjCCAqagAwIBAgIJAJJp49NkLrvBMA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNV -BAYTAlBMMRQwEgYDVQQIDAtEb2xueSBTbGFzazEQMA4GA1UEBwwHV3JvY2xhdzEV -MBMGA1UECgwMUm9vdCBDb21wYW55MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQ4w -DAYDVQQDDAVOb2tpYTAeFw0xODEwMjYwOTE5NTFaFw0xOTEwMjYwOTE5NTFaMHQx -CzAJBgNVBAYTAlBMMRQwEgYDVQQIDAtEb2xueSBTbGFzazEQMA4GA1UEBwwHV3Jv -Y2xhdzEVMBMGA1UECgwMUm9vdCBDb21wYW55MRYwFAYDVQQLDA1JVCBEZXBhcnRt -ZW50MQ4wDAYDVQQDDAVOb2tpYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALvjq8cuNmfZe8S0ONp0LvSx1fgdWaARuGTcTgjLlV+8ng7f4eVodj8bn5BI -cChjMjMc+8YfCLdZJxOl36/8pdIOe1pHGBgjJ5uPIFg0ESuVSN15azodw5ESGA2v -Nhc4QlynLH/W5SsGRlkN0t9yRvGLb+uSrRqDtAFc448//qgTIsBYBl0cLoU4uMaj -iSaxqEpBZPJSAOnof1XV4ZEXTE2lm/HHepa5RozlgYgCzF21m5k2inGN3p9NYdkN -nq0ahl12j/GCuabwVblUnQPAUZzLtV9CtZkuPRdwnkLFGEMNVGsYWh+KAb2q7fr3 -9BNsqdWtIdX8CS30/KBMplSr/6UCAwEAAaNTMFEwHQYDVR0OBBYEFKTTrBaUlhXo -kaD2n2CbtVT/+vV8MB8GA1UdIwQYMBaAFKTTrBaUlhXokaD2n2CbtVT/+vV8MA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ8VwmT28OF5+wKooFbJ -oxhOp80dEaBHOuoBkIqiQFS3Bf3lhUcue+sqWWN2D/vSosQpIUImXPrnjAogGT8p -HCnh0eblY89Q62wtGtdhDWPdrmZ198MOQifaIKTDLDE0viLGtCC+aBOATEjm/K2O -e2lFxYVckZw7wEnbWoQCYxEE9qczxBjkStPhF3RqyorbxVQKfSKlo1bspTCwB3pW -LpXcY6OP8ZL0v46HExy1d9pAsh0gcWDyG812/86AdYEeoaV7QJh2B9fRRAuFve9S -GWEEtxPobvXfLL6QOFiacSwmyqckuMxgYGpAcJSVYoA1r9xNJA24SO68We9EaCty -7WU= ------END CERTIFICATE----- diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.key b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.key deleted file mode 100644 index 43af86505..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC746vHLjZn2XvE -tDjadC70sdX4HVmgEbhk3E4Iy5VfvJ4O3+HlaHY/G5+QSHAoYzIzHPvGHwi3WScT -pd+v/KXSDntaRxgYIyebjyBYNBErlUjdeWs6HcOREhgNrzYXOEJcpyx/1uUrBkZZ -DdLfckbxi2/rkq0ag7QBXOOPP/6oEyLAWAZdHC6FOLjGo4kmsahKQWTyUgDp6H9V -1eGRF0xNpZvxx3qWuUaM5YGIAsxdtZuZNopxjd6fTWHZDZ6tGoZddo/xgrmm8FW5 -VJ0DwFGcy7VfQrWZLj0XcJ5CxRhDDVRrGFofigG9qu369/QTbKnVrSHV/Akt9Pyg -TKZUq/+lAgMBAAECggEBALrgl9pkfHiOOCxNlL6zEIEQ4GEH0D0FYwHunS7iTpAK -aqsgwu4KGJJsRyia4/NHtoZgLYvBEkpKwjMoqHPCNqvW+5mvXKelT5/Jm8IfB3Tx -5qdiPORw9jM0a/gwbPxrWJYPMJN2ijlg5FdvCG52m1lj9s239bSJimBQo4W3gPJp -YXCN+cO7DMpaIsvTpFnQUyiRxzbqmWD/dI51/GdsQUkjM5VRTXtv9D+RCaVE/Gyd -cdzHOm6MuULEeuaWtoUKux6v94xoQDhf4p9AECDowzEeHmvJ6qEQzantnEUtJNsI -+47sP8IZE0qs9lCcrJHeK37aO1IS39VY2BeAR6XkR4ECgYEA48NfVTTmKN6sNDGa -aVgkDalATdHPFhitKAvBPBR1R/eCz37gdGX19DNYShiXBny2XEkuyY8chuhUmBMV -A5OrIMLoF0ByvsZXEaghhBirFsmXTjc3gAhFz6r6oSDM/dYs5pFYSR+gnnl/WALA -8Y82FxdKA9d5gkeAGY5GvmO9L7sCgYEA0y7Ny9s3VvDr2oU89ujdGviUkiDxstis -vajsg3BojJweid7WjL0Gv1/wtwiPtZkCZSnaKv6Q2zxSZ1OJpWvff5TbjG/WfzXu -fkITnkFzF8klQswkge7uRryI0NJBFLzgl3sWGJwHNuNmRaw7i5Ie9OhXE0NzH9B+ -Aixx3TwKKB8CgYEAjOBTHwjRM4ZHTSFBONdjtW9ybq/PPwOUVqiupNKimBjnuB/q -BRTrxFfdzDbZcxHAWeSKI/F425joegeTf9rehi0IERmz33webrVnxaTcbgPSqnZM -xcxYIdLHotH++SJ4M0TDLrd5SYwsz+skHEVQV4f4J9gnOAWxnhz6dNiMM/ECgYEA -pypkYxr62kpJGCfh0z0PULs2t9l2GXEkg9kEpyLCz5MBJXeMc8lpXvGt1OTlBQXC -fJu9g80Qk0pTnFDnI1eZih8mDyu0KexiBfV+HAaI+WoSoaaAu42LddjloA7ez3CX -g7E+E2rm1w74NOyaEegvswN7cdcxeRyLsmLGGy7ch1cCgYEAnbv8i9Mt0FzCqX5O -yr1JehLoQWz4RqIibtEcjk7cQFjhUUx5UqnRHS6DAinL9vh92G/3JYsX/Ur2k2f9 -nl/y3clx5hjQubEt18lu8oi76dRRD3HBb6JA4rnZBvG3cpu9zy3Ik3hxMLdxGvfN -ciDoTou+NnAuP0e3KTDyTe+1MMc= ------END PRIVATE KEY----- diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.pem b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.pem deleted file mode 100644 index 96e5ed63a..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd.pem +++ /dev/null @@ -1,50 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpgIBAAKCAQEAu+Orxy42Z9l7xLQ42nQu9LHV+B1ZoBG4ZNxOCMuVX7yeDt/h -5Wh2PxufkEhwKGMyMxz7xh8It1knE6Xfr/yl0g57WkcYGCMnm48gWDQRK5VI3Xlr -Oh3DkRIYDa82FzhCXKcsf9blKwZGWQ3S33JG8Ytv65KtGoO0AVzjjz/+qBMiwFgG -XRwuhTi4xqOJJrGoSkFk8lIA6eh/VdXhkRdMTaWb8cd6lrlGjOWBiALMXbWbmTaK -cY3en01h2Q2erRqGXXaP8YK5pvBVuVSdA8BRnMu1X0K1mS49F3CeQsUYQw1Uaxha -H4oBvart+vf0E2yp1a0h1fwJLfT8oEymVKv/pQIDAQABAoIBAQC64JfaZHx4jjgs -TZS+sxCBEOBhB9A9BWMB7p0u4k6QCmqrIMLuChiSbEcomuPzR7aGYC2LwRJKSsIz -KKhzwjar1vuZr1ynpU+fyZvCHwd08eanYjzkcPYzNGv4MGz8a1iWDzCTdoo5YORX -bwhudptZY/bNt/W0iYpgUKOFt4DyaWFwjfnDuwzKWiLL06RZ0FMokcc26plg/3SO -dfxnbEFJIzOVUU17b/Q/kQmlRPxsnXHcxzpujLlCxHrmlraFCrser/eMaEA4X+Kf -QBAg6MMxHh5ryeqhEM2p7ZxFLSTbCPuO7D/CGRNKrPZQnKyR3it+2jtSEt/VWNgX -gEel5EeBAoGBAOPDX1U05ijerDQxmmlYJA2pQE3RzxYYrSgLwTwUdUf3gs9+4HRl -9fQzWEoYlwZ8tlxJLsmPHIboVJgTFQOTqyDC6BdAcr7GVxGoIYQYqxbJl043N4AI -Rc+q+qEgzP3WLOaRWEkfoJ55f1gCwPGPNhcXSgPXeYJHgBmORr5jvS+7AoGBANMu -zcvbN1bw69qFPPbo3Rr4lJIg8bLYrL2o7INwaIycHone1oy9Br9f8LcIj7WZAmUp -2ir+kNs8UmdTiaVr33+U24xv1n817n5CE55BcxfJJULMJIHu7ka8iNDSQRS84Jd7 -FhicBzbjZkWsO4uSHvToVxNDcx/QfgIscd08CigfAoGBAIzgUx8I0TOGR00hQTjX -Y7Vvcm6vzz8DlFaorqTSopgY57gf6gUU68RX3cw22XMRwFnkiiPxeNuY6HoHk3/a -3oYtCBEZs998Hm61Z8Wk3G4D0qp2TMXMWCHSx6LR/vkieDNEwy63eUmMLM/rJBxF -UFeH+CfYJzgFsZ4c+nTYjDPxAoGBAKcqZGMa+tpKSRgn4dM9D1C7NrfZdhlxJIPZ -BKciws+TASV3jHPJaV7xrdTk5QUFwnybvYPNEJNKU5xQ5yNXmYofJg8rtCnsYgX1 -fhwGiPlqEqGmgLuNi3XY5aAO3s9wl4OxPhNq5tcO+DTsmhHoL7MDe3HXMXkci7Ji -xhsu3IdXAoGBAJ27/IvTLdBcwql+Tsq9SXoS6EFs+EaiIm7RHI5O3EBY4VFMeVKp -0R0ugwIpy/b4fdhv9yWLF/1K9pNn/Z5f8t3JceYY0LmxLdfJbvKIu+nUUQ9xwW+i -QOK52Qbxt3Kbvc8tyJN4cTC3cRr3zXIg6E6LvjZwLj9Htykw8k3vtTDH ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDvjCCAqagAwIBAgIJAJJp49NkLrvBMA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNV -BAYTAlBMMRQwEgYDVQQIDAtEb2xueSBTbGFzazEQMA4GA1UEBwwHV3JvY2xhdzEV -MBMGA1UECgwMUm9vdCBDb21wYW55MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQ4w -DAYDVQQDDAVOb2tpYTAeFw0xODEwMjYwOTE5NTFaFw0xOTEwMjYwOTE5NTFaMHQx -CzAJBgNVBAYTAlBMMRQwEgYDVQQIDAtEb2xueSBTbGFzazEQMA4GA1UEBwwHV3Jv -Y2xhdzEVMBMGA1UECgwMUm9vdCBDb21wYW55MRYwFAYDVQQLDA1JVCBEZXBhcnRt -ZW50MQ4wDAYDVQQDDAVOb2tpYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALvjq8cuNmfZe8S0ONp0LvSx1fgdWaARuGTcTgjLlV+8ng7f4eVodj8bn5BI -cChjMjMc+8YfCLdZJxOl36/8pdIOe1pHGBgjJ5uPIFg0ESuVSN15azodw5ESGA2v -Nhc4QlynLH/W5SsGRlkN0t9yRvGLb+uSrRqDtAFc448//qgTIsBYBl0cLoU4uMaj -iSaxqEpBZPJSAOnof1XV4ZEXTE2lm/HHepa5RozlgYgCzF21m5k2inGN3p9NYdkN -nq0ahl12j/GCuabwVblUnQPAUZzLtV9CtZkuPRdwnkLFGEMNVGsYWh+KAb2q7fr3 -9BNsqdWtIdX8CS30/KBMplSr/6UCAwEAAaNTMFEwHQYDVR0OBBYEFKTTrBaUlhXo -kaD2n2CbtVT/+vV8MB8GA1UdIwQYMBaAFKTTrBaUlhXokaD2n2CbtVT/+vV8MA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ8VwmT28OF5+wKooFbJ -oxhOp80dEaBHOuoBkIqiQFS3Bf3lhUcue+sqWWN2D/vSosQpIUImXPrnjAogGT8p -HCnh0eblY89Q62wtGtdhDWPdrmZ198MOQifaIKTDLDE0viLGtCC+aBOATEjm/K2O -e2lFxYVckZw7wEnbWoQCYxEE9qczxBjkStPhF3RqyorbxVQKfSKlo1bspTCwB3pW -LpXcY6OP8ZL0v46HExy1d9pAsh0gcWDyG812/86AdYEeoaV7QJh2B9fRRAuFve9S -GWEEtxPobvXfLL6QOFiacSwmyqckuMxgYGpAcJSVYoA1r9xNJA24SO68We9EaCty -7WU= ------END CERTIFICATE----- diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_crt.pem b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_crt.pem deleted file mode 100644 index 0aaee0eec..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_crt.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDvjCCAqagAwIBAgIJAJJp49NkLrvBMA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNV -BAYTAlBMMRQwEgYDVQQIDAtEb2xueSBTbGFzazEQMA4GA1UEBwwHV3JvY2xhdzEV -MBMGA1UECgwMUm9vdCBDb21wYW55MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQ4w -DAYDVQQDDAVOb2tpYTAeFw0xODEwMjYwOTE5NTFaFw0xOTEwMjYwOTE5NTFaMHQx -CzAJBgNVBAYTAlBMMRQwEgYDVQQIDAtEb2xueSBTbGFzazEQMA4GA1UEBwwHV3Jv -Y2xhdzEVMBMGA1UECgwMUm9vdCBDb21wYW55MRYwFAYDVQQLDA1JVCBEZXBhcnRt -ZW50MQ4wDAYDVQQDDAVOb2tpYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALvjq8cuNmfZe8S0ONp0LvSx1fgdWaARuGTcTgjLlV+8ng7f4eVodj8bn5BI -cChjMjMc+8YfCLdZJxOl36/8pdIOe1pHGBgjJ5uPIFg0ESuVSN15azodw5ESGA2v -Nhc4QlynLH/W5SsGRlkN0t9yRvGLb+uSrRqDtAFc448//qgTIsBYBl0cLoU4uMaj -iSaxqEpBZPJSAOnof1XV4ZEXTE2lm/HHepa5RozlgYgCzF21m5k2inGN3p9NYdkN -nq0ahl12j/GCuabwVblUnQPAUZzLtV9CtZkuPRdwnkLFGEMNVGsYWh+KAb2q7fr3 -9BNsqdWtIdX8CS30/KBMplSr/6UCAwEAAaNTMFEwHQYDVR0OBBYEFKTTrBaUlhXo -kaD2n2CbtVT/+vV8MB8GA1UdIwQYMBaAFKTTrBaUlhXokaD2n2CbtVT/+vV8MA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ8VwmT28OF5+wKooFbJ -oxhOp80dEaBHOuoBkIqiQFS3Bf3lhUcue+sqWWN2D/vSosQpIUImXPrnjAogGT8p -HCnh0eblY89Q62wtGtdhDWPdrmZ198MOQifaIKTDLDE0viLGtCC+aBOATEjm/K2O -e2lFxYVckZw7wEnbWoQCYxEE9qczxBjkStPhF3RqyorbxVQKfSKlo1bspTCwB3pW -LpXcY6OP8ZL0v46HExy1d9pAsh0gcWDyG812/86AdYEeoaV7QJh2B9fRRAuFve9S -GWEEtxPobvXfLL6QOFiacSwmyqckuMxgYGpAcJSVYoA1r9xNJA24SO68We9EaCty -7WU= ------END CERTIFICATE----- diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_key.pem b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_key.pem deleted file mode 100644 index 2003df7c7..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpgIBAAKCAQEAu+Orxy42Z9l7xLQ42nQu9LHV+B1ZoBG4ZNxOCMuVX7yeDt/h -5Wh2PxufkEhwKGMyMxz7xh8It1knE6Xfr/yl0g57WkcYGCMnm48gWDQRK5VI3Xlr -Oh3DkRIYDa82FzhCXKcsf9blKwZGWQ3S33JG8Ytv65KtGoO0AVzjjz/+qBMiwFgG -XRwuhTi4xqOJJrGoSkFk8lIA6eh/VdXhkRdMTaWb8cd6lrlGjOWBiALMXbWbmTaK -cY3en01h2Q2erRqGXXaP8YK5pvBVuVSdA8BRnMu1X0K1mS49F3CeQsUYQw1Uaxha -H4oBvart+vf0E2yp1a0h1fwJLfT8oEymVKv/pQIDAQABAoIBAQC64JfaZHx4jjgs -TZS+sxCBEOBhB9A9BWMB7p0u4k6QCmqrIMLuChiSbEcomuPzR7aGYC2LwRJKSsIz -KKhzwjar1vuZr1ynpU+fyZvCHwd08eanYjzkcPYzNGv4MGz8a1iWDzCTdoo5YORX -bwhudptZY/bNt/W0iYpgUKOFt4DyaWFwjfnDuwzKWiLL06RZ0FMokcc26plg/3SO -dfxnbEFJIzOVUU17b/Q/kQmlRPxsnXHcxzpujLlCxHrmlraFCrser/eMaEA4X+Kf -QBAg6MMxHh5ryeqhEM2p7ZxFLSTbCPuO7D/CGRNKrPZQnKyR3it+2jtSEt/VWNgX -gEel5EeBAoGBAOPDX1U05ijerDQxmmlYJA2pQE3RzxYYrSgLwTwUdUf3gs9+4HRl -9fQzWEoYlwZ8tlxJLsmPHIboVJgTFQOTqyDC6BdAcr7GVxGoIYQYqxbJl043N4AI -Rc+q+qEgzP3WLOaRWEkfoJ55f1gCwPGPNhcXSgPXeYJHgBmORr5jvS+7AoGBANMu -zcvbN1bw69qFPPbo3Rr4lJIg8bLYrL2o7INwaIycHone1oy9Br9f8LcIj7WZAmUp -2ir+kNs8UmdTiaVr33+U24xv1n817n5CE55BcxfJJULMJIHu7ka8iNDSQRS84Jd7 -FhicBzbjZkWsO4uSHvToVxNDcx/QfgIscd08CigfAoGBAIzgUx8I0TOGR00hQTjX -Y7Vvcm6vzz8DlFaorqTSopgY57gf6gUU68RX3cw22XMRwFnkiiPxeNuY6HoHk3/a -3oYtCBEZs998Hm61Z8Wk3G4D0qp2TMXMWCHSx6LR/vkieDNEwy63eUmMLM/rJBxF -UFeH+CfYJzgFsZ4c+nTYjDPxAoGBAKcqZGMa+tpKSRgn4dM9D1C7NrfZdhlxJIPZ -BKciws+TASV3jHPJaV7xrdTk5QUFwnybvYPNEJNKU5xQ5yNXmYofJg8rtCnsYgX1 -fhwGiPlqEqGmgLuNi3XY5aAO3s9wl4OxPhNq5tcO+DTsmhHoL7MDe3HXMXkci7Ji -xhsu3IdXAoGBAJ27/IvTLdBcwql+Tsq9SXoS6EFs+EaiIm7RHI5O3EBY4VFMeVKp -0R0ugwIpy/b4fdhv9yWLF/1K9pNn/Z5f8t3JceYY0LmxLdfJbvKIu+nUUQ9xwW+i -QOK52Qbxt3Kbvc8tyJN4cTC3cRr3zXIg6E6LvjZwLj9Htykw8k3vtTDH ------END RSA PRIVATE KEY----- diff --git a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_keys_generator.sh b/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_keys_generator.sh deleted file mode 100644 index ef66bd0b4..000000000 --- a/test/mocks/pnfsimulator/ftpes/vsftpd/tls/vsftpd_keys_generator.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -echo 'Generating credetials for FTPES server and DFC client...' - -#ganerate certificate&privatekey (vsftpd.crt, vsftpd.key) with password: secret -openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout vsftpd.key -out vsftpd.crt -subj "/C=PL/ST=Dolny Slask/L=Wroclaw/O=Root Company/OU=IT Department/CN=Nokia" -#convert crt to pem -openssl x509 -in vsftpd.crt -out vsftpd_crt.pem -outform PEM -#convert key to pem -openssl rsa -in vsftpd.key -out vsftpd_key.pem -outform PEM -#marge key and cert into one pem file -cat vsftpd_key.pem vsftpd_crt.pem > vsftpd.pem - -#generate keystore -openssl pkcs12 -export -out cert.pkcs12 -in vsftpd_crt.pem -inkey vsftpd_key.pem -java -cp ./jetty-6.1.26.jar org.mortbay.jetty.security.PKCS12Import cert.pkcs12 keystore.jks - -#generate truststore -openssl x509 -in vsftpd_crt.pem -out cert.der -outform der -keytool -importcert -alias cert -file cert.der -keystore truststore.jks - -sudo chown root * -sudo chmod 664 * - -echo "You have generated your key in the keystore, and your certificate in the truststore." - -##WITH PASSPHRASE -#echo 'Generating credetials for FTPES server and DFC client...' -# -##ganerate certificate&privatekey (vsftpd.crt, vsftpd.key) with password: secret -#openssl req -x509 -days 365 -newkey rsa:2048 -keyout vsftpd.key -out vsftpd.crt -subj "/C=PL/ST=Dolny Slask/L=Wroclaw/O=Root Company/OU=IT Department/CN=Nokia" --passout pass:secret -##convert crt to pem -#openssl x509 -in vsftpd.crt -out vsftpd_crt.pem -outform PEM -##convert key to pem -#openssl rsa -in vsftpd.key -out vsftpd_key.pem -outform PEM -passin pass:secret -##marge key and cert into one pem file -#cat vsftpd_key.pem vsftpd_crt.pem > vsftpd.pem -# -##generate keystore -#openssl pkcs12 -export -out cert.pkcs12 -in vsftpd_crt.pem -inkey vsftpd_key.pem -passout pass:secret -#java -cp ./jetty-6.1.26.jar org.mortbay.jetty.security.PKCS12Import cert.pkcs12 keystore.jks -# -##generate truststore -#openssl x509 -in vsftpd_crt.pem -out cert.der -outform der -#keytool -importcert -alias cert -file cert.der -keystore truststore.jks -storepass secret -# -#sudo chown root * -#sudo chmod 664 * -# -#echo "You have generated your key in the keystore, and your certificate in the truststore."
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/json_schema/input_validator.json b/test/mocks/pnfsimulator/json_schema/input_validator.json deleted file mode 100644 index 679e11abf..000000000 --- a/test/mocks/pnfsimulator/json_schema/input_validator.json +++ /dev/null @@ -1,198 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "type": "object", - "properties": { - "simulatorParams": { - "type": "object", - "properties": { - "vesServerUrl": { - "type": "string" - }, - "testDuration": { - "type": "string" - }, - "messageInterval": { - "type": "string" - } - }, - "required": [ - "vesServerUrl", - "testDuration", - "messageInterval" - ] - }, - "commonEventHeaderParams": { - "type": "object", - "properties": { - "eventName": { - "type": "string" - }, - "nfNamingCode": { - "type": "string" - }, - "nfcNamingCode": { - "type": "string" - }, - "sourceName": { - "type": "string" - }, - "sourceId": { - "type": "string" - }, - "reportingEntityName": { - "type": "string" - } - }, - "required": [ - "eventName", - "sourceName", - "sourceId", - "reportingEntityName" - ] - }, - - - "pnfRegistrationParams": { - "type": "object", - "properties": { - "serialNumber": { - "type": "string" - }, - "vendorName": { - "type": "string" - }, - "oamV4IpAddress": { - "type": "string" - }, - "oamV6IpAddress": { - "type": "string" - }, - "unitFamily": { - "type": "string" - }, - "modelNumber": { - "type": "string" - }, - "softwareVersion": { - "type": "string" - }, - "unitType": { - "type": "string" - }, - "additionalFields": { - "type": "object" - } - } - }, - "notificationParams": { - "type": "object", - "properties": { - "changeIdentifier": { - "type": "string" - }, - "changeType": { - "type": "string" - }, - "arrayOfNamedHashMap": { - "type": "array", - "items": [ - { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "hashMap": { - "type": "object", - "properties": { - "location": { - "type": "string" - }, - "compression": { - "type": "string" - }, - "fileFormatType": { - "type": "string" - }, - "fileFormatVersion": { - "type": "string" - } - }, - "required": [ - "location", - "compression", - "fileFormatType", - "fileFormatVersion" - ] - } - }, - "required": [ - "name", - "hashMap" - ] - }, - { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "hashMap": { - "type": "object", - "properties": { - "location": { - "type": "string" - }, - "compression": { - "type": "string" - }, - "fileFormatType": { - "type": "string" - }, - "fileFormatVersion": { - "type": "string" - } - }, - "required": [ - "location", - "compression", - "fileFormatType", - "fileFormatVersion" - ] - } - }, - "required": [ - "name", - "hashMap" - ] - } - ] - } - }, - "required": [ - "changeIdentifier", - "changeType", - "arrayOfNamedHashMap" - ] - } - }, - - "oneOf": [ - { - "required": [ - "simulatorParams", - "commonEventHeaderParams", - "pnfRegistrationParams" - ] - }, - { - "required": [ - "simulatorParams", - "commonEventHeaderParams", - "notificationParams" - ] - } - ] - - -} diff --git a/test/mocks/pnfsimulator/json_schema/output_validator_ves_schema_30.0.1.json b/test/mocks/pnfsimulator/json_schema/output_validator_ves_schema_30.0.1.json deleted file mode 100644 index 385ba25e3..000000000 --- a/test/mocks/pnfsimulator/json_schema/output_validator_ves_schema_30.0.1.json +++ /dev/null @@ -1,2432 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "VES Event Listener Common Event Format", - "type": "object", - "properties": { - "event": {"$ref": "#/definitions/event"}, - "eventList": {"$ref": "#/definitions/eventList"} - }, - - "definitions": { - "schemaHeaderBlock": { - "description": "schema date, version, author and associated API", - "type": "object", - "properties": { - "associatedApi": { - "description": "VES Event Listener", - "type": "string" - }, - "lastUpdatedBy": { - "description": "re2947", - "type": "string" - }, - "schemaDate": { - "description": "July 31, 2018", - "type": "string" - }, - "schemaVersion": { - "description": "30.0.1", - "type": "number" - } - } - }, - "schemaLicenseAndCopyrightNotice": { - "description": "Copyright (c) 2018, AT&T Intellectual Property. All rights reserved", - "type": "object", - "properties": { - "apacheLicense2.0": { - "description": "Licensed under the Apache License, Version 2.0 (the 'License'); you may not use this file except in compliance with the License. You may obtain a copy of the License at:", - "type": "string" - }, - "licenseUrl": { - "description": "http://www.apache.org/licenses/LICENSE-2.0", - "type": "string" - }, - "asIsClause": { - "description": "Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", - "type": "string" - }, - "permissionsAndLimitations": { - "description": "See the License for the specific language governing permissions and limitations under the License.", - "type": "string" - } - } - }, - "arrayOfJsonObject": { - "description": "array of json objects described by name, schema and other meta-information", - "type": "array", - "items": { - "$ref": "#/definitions/jsonObject" - } - }, - "arrayOfNamedHashMap": { - "description": "array of named hashMaps", - "type": "array", - "items": { - "$ref": "#/definitions/namedHashMap" - } - }, - "codecsInUse": { - "description": "number of times an identified codec was used over the measurementInterval", - "type": "object", - "properties": { - "codecIdentifier": { "type": "string" }, - "numberInUse": { "type": "integer" } - }, - "additionalProperties": false, - "required": [ "codecIdentifier", "numberInUse" ] - }, - "commonEventHeader": { - "description": "fields common to all events", - "type": "object", - "properties": { - "domain": { - "description": "the eventing domain associated with the event", - "type": "string", - "enum": [ - "fault", - "heartbeat", - "measurement", - "mobileFlow", - "notification", - "other", - "pnfRegistration", - "sipSignaling", - "stateChange", - "syslog", - "thresholdCrossingAlert", - "voiceQuality" - ] - }, - "eventId": { - "description": "event key that is unique to the event source", - "type": "string" - }, - "eventName": { - "description": "unique event name", - "type": "string" - }, - "eventType": { - "description": "for example - applicationNf, guestOS, hostOS, platform", - "type": "string" - }, - "internalHeaderFields": { "$ref": "#/definitions/internalHeaderFields" }, - "lastEpochMicrosec": { - "description": "the latest unix time aka epoch time associated with the event from any component--as microseconds elapsed since 1 Jan 1970 not including leap seconds", - "type": "number" - }, - "nfcNamingCode": { - "description": "3 character network function component type, aligned with vfc naming standards", - "type": "string" - }, - "nfNamingCode": { - "description": "4 character network function type, aligned with nf naming standards", - "type": "string" - }, - "nfVendorName": { - "description": "network function vendor name", - "type": "string" - }, - "priority": { - "description": "processing priority", - "type": "string", - "enum": [ - "High", - "Medium", - "Normal", - "Low" - ] - }, - "reportingEntityId": { - "description": "UUID identifying the entity reporting the event, for example an OAM VM; must be populated by the ATT enrichment process", - "type": "string" - }, - "reportingEntityName": { - "description": "name of the entity reporting the event, for example, an EMS name; may be the same as sourceName", - "type": "string" - }, - "sequence": { - "description": "ordering of events communicated by an event source instance or 0 if not needed", - "type": "integer" - }, - "sourceId": { - "description": "UUID identifying the entity experiencing the event issue; must be populated by the ATT enrichment process", - "type": "string" - }, - "sourceName": { - "description": "name of the entity experiencing the event issue", - "type": "string" - }, - "startEpochMicrosec": { - "description": "the earliest unix time aka epoch time associated with the event from any component--as microseconds elapsed since 1 Jan 1970 not including leap seconds", - "type": "number" - }, - "timeZoneOffset": { - "description": "UTC offset for the local time zone of the device as UTC+/-hh.mm", - "type": "string" - }, - "version": { - "description": "version of the event header", - "type": "string", - "enum": [ "4.0.1" ] - }, - "vesEventListenerVersion": { - "description": "version of the VES Event Listener API", - "type": "string", - "enum": [ "7.0.1" ] - } - }, - "additionalProperties": false, - "required": [ "domain", "eventId", "eventName", "lastEpochMicrosec", - "priority", "reportingEntityName", "sequence", "sourceName", - "startEpochMicrosec", "version", "vesEventListenerVersion" ] - }, - "counter": { - "description": "performance counter", - "type": "object", - "properties": { - "criticality": { "type": "string", "enum": [ "CRIT", "MAJ" ] }, - "hashMap": { "$ref": "#/definitions/hashMap" }, - "thresholdCrossed": { "type": "string" } - }, - "additionalProperties": false, - "required": [ "criticality", "hashMap", "thresholdCrossed" ] - }, - "cpuUsage": { - "description": "usage of an identified CPU", - "type": "object", - "properties": { - "cpuCapacityContention": { - "description": "the amount of time the CPU cannot run due to contention, in milliseconds over the measurementInterval", - "type": "number" - }, - "cpuDemandAvg": { - "description": "the total CPU time that the NF/NFC/VM could use if there was no contention, in milliseconds over the measurementInterval", - "type": "number" - }, - "cpuDemandMhz": { - "description": "CPU demand in megahertz", - "type": "number" - }, - "cpuDemandPct": { - "description": "CPU demand as a percentage of the provisioned capacity", - "type": "number" - }, - "cpuIdentifier": { - "description": "cpu identifer", - "type": "string" - }, - "cpuIdle": { - "description": "percentage of CPU time spent in the idle task", - "type": "number" - }, - "cpuLatencyAvg": { - "description": "percentage of time the VM is unable to run because it is contending for access to the physical CPUs", - "type": "number" - }, - "cpuOverheadAvg": { - "description": "the overhead demand above available allocations and reservations, in milliseconds over the measurementInterval", - "type": "number" - }, - "cpuSwapWaitTime": { - "description": "swap wait time. in milliseconds over the measurementInterval", - "type": "number" - }, - "cpuUsageInterrupt": { - "description": "percentage of time spent servicing interrupts", - "type": "number" - }, - "cpuUsageNice": { - "description": "percentage of time spent running user space processes that have been niced", - "type": "number" - }, - "cpuUsageSoftIrq": { - "description": "percentage of time spent handling soft irq interrupts", - "type": "number" - }, - "cpuUsageSteal": { - "description": "percentage of time spent in involuntary wait which is neither user, system or idle time and is effectively time that went missing", - "type": "number" - }, - "cpuUsageSystem": { - "description": "percentage of time spent on system tasks running the kernel", - "type": "number" - }, - "cpuUsageUser": { - "description": "percentage of time spent running un-niced user space processes", - "type": "number" - }, - "cpuWait": { - "description": "percentage of CPU time spent waiting for I/O operations to complete", - "type": "number" - }, - "percentUsage": { - "description": "aggregate cpu usage of the virtual machine on which the xNFC reporting the event is running", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "cpuIdentifier", "percentUsage" ] - }, - "diskUsage": { - "description": "usage of an identified disk", - "type": "object", - "properties": { - "diskBusResets": { - "description": "number of bus resets over the measurementInterval", - "type": "number" - }, - "diskCommandsAborted": { - "description": "number of disk commands aborted over the measurementInterval", - "type": "number" - }, - "diskCommandsAvg": { - "description": "average number of commands per second over the measurementInterval", - "type": "number" - }, - "diskFlushRequests": { - "description": "total flush requests of the disk cache over the measurementInterval", - "type": "number" - }, - "diskFlushTime": { - "description": "milliseconds spent on disk cache flushing over the measurementInterval", - "type": "number" - }, - "diskIdentifier": { - "description": "disk identifier", - "type": "string" - }, - "diskIoTimeAvg": { - "description": "milliseconds spent doing input/output operations over 1 sec; treat this metric as a device load percentage where 1000ms matches 100% load; provide the average over the measurement interval", - "type": "number" - }, - "diskIoTimeLast": { - "description": "milliseconds spent doing input/output operations over 1 sec; treat this metric as a device load percentage where 1000ms matches 100% load; provide the last value measurement within the measurement interval", - "type": "number" - }, - "diskIoTimeMax": { - "description": "milliseconds spent doing input/output operations over 1 sec; treat this metric as a device load percentage where 1000ms matches 100% load; provide the maximum value measurement within the measurement interval", - "type": "number" - }, - "diskIoTimeMin": { - "description": "milliseconds spent doing input/output operations over 1 sec; treat this metric as a device load percentage where 1000ms matches 100% load; provide the minimum value measurement within the measurement interval", - "type": "number" - }, - "diskMergedReadAvg": { - "description": "number of logical read operations that were merged into physical read operations, e.g., two logical reads were served by one physical disk access; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskMergedReadLast": { - "description": "number of logical read operations that were merged into physical read operations, e.g., two logical reads were served by one physical disk access; provide the last value measurement within the measurement interval", - "type": "number" - }, - "diskMergedReadMax": { - "description": "number of logical read operations that were merged into physical read operations, e.g., two logical reads were served by one physical disk access; provide the maximum value measurement within the measurement interval", - "type": "number" - }, - "diskMergedReadMin": { - "description": "number of logical read operations that were merged into physical read operations, e.g., two logical reads were served by one physical disk access; provide the minimum value measurement within the measurement interval", - "type": "number" - }, - "diskMergedWriteAvg": { - "description": "number of logical write operations that were merged into physical write operations, e.g., two logical writes were served by one physical disk access; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskMergedWriteLast": { - "description": "number of logical write operations that were merged into physical write operations, e.g., two logical writes were served by one physical disk access; provide the last value measurement within the measurement interval", - "type": "number" - }, - "diskMergedWriteMax": { - "description": "number of logical write operations that were merged into physical write operations, e.g., two logical writes were served by one physical disk access; provide the maximum value measurement within the measurement interval", - "type": "number" - }, - "diskMergedWriteMin": { - "description": "number of logical write operations that were merged into physical write operations, e.g., two logical writes were served by one physical disk access; provide the minimum value measurement within the measurement interval", - "type": "number" - }, - "diskOctetsReadAvg": { - "description": "number of octets per second read from a disk or partition; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskOctetsReadLast": { - "description": "number of octets per second read from a disk or partition; provide the last measurement within the measurement interval", - "type": "number" - }, - "diskOctetsReadMax": { - "description": "number of octets per second read from a disk or partition; provide the maximum measurement within the measurement interval", - "type": "number" - }, - "diskOctetsReadMin": { - "description": "number of octets per second read from a disk or partition; provide the minimum measurement within the measurement interval", - "type": "number" - }, - "diskOctetsWriteAvg": { - "description": "number of octets per second written to a disk or partition; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskOctetsWriteLast": { - "description": "number of octets per second written to a disk or partition; provide the last measurement within the measurement interval", - "type": "number" - }, - "diskOctetsWriteMax": { - "description": "number of octets per second written to a disk or partition; provide the maximum measurement within the measurement interval", - "type": "number" - }, - "diskOctetsWriteMin": { - "description": "number of octets per second written to a disk or partition; provide the minimum measurement within the measurement interval", - "type": "number" - }, - "diskOpsReadAvg": { - "description": "number of read operations per second issued to the disk; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskOpsReadLast": { - "description": "number of read operations per second issued to the disk; provide the last measurement within the measurement interval", - "type": "number" - }, - "diskOpsReadMax": { - "description": "number of read operations per second issued to the disk; provide the maximum measurement within the measurement interval", - "type": "number" - }, - "diskOpsReadMin": { - "description": "number of read operations per second issued to the disk; provide the minimum measurement within the measurement interval", - "type": "number" - }, - "diskOpsWriteAvg": { - "description": "number of write operations per second issued to the disk; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskOpsWriteLast": { - "description": "number of write operations per second issued to the disk; provide the last measurement within the measurement interval", - "type": "number" - }, - "diskOpsWriteMax": { - "description": "number of write operations per second issued to the disk; provide the maximum measurement within the measurement interval", - "type": "number" - }, - "diskOpsWriteMin": { - "description": "number of write operations per second issued to the disk; provide the minimum measurement within the measurement interval", - "type": "number" - }, - "diskPendingOperationsAvg": { - "description": "queue size of pending I/O operations per second; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskPendingOperationsLast": { - "description": "queue size of pending I/O operations per second; provide the last measurement within the measurement interval", - "type": "number" - }, - "diskPendingOperationsMax": { - "description": "queue size of pending I/O operations per second; provide the maximum measurement within the measurement interval", - "type": "number" - }, - "diskPendingOperationsMin": { - "description": "queue size of pending I/O operations per second; provide the minimum measurement within the measurement interval", - "type": "number" - }, - "diskReadCommandsAvg": { - "description": "average number of read commands issued per second to the disk over the measurementInterval", - "type": "number" - }, - "diskTime": { - "description": "nanoseconds spent on disk cache reads/writes within the measurement interval", - "type": "number" - }, - "diskTimeReadAvg": { - "description": "milliseconds a read operation took to complete; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskTimeReadLast": { - "description": "milliseconds a read operation took to complete; provide the last measurement within the measurement interval", - "type": "number" - }, - "diskTimeReadMax": { - "description": "milliseconds a read operation took to complete; provide the maximum measurement within the measurement interval", - "type": "number" - }, - "diskTimeReadMin": { - "description": "milliseconds a read operation took to complete; provide the minimum measurement within the measurement interval", - "type": "number" - }, - "diskTimeWriteAvg": { - "description": "milliseconds a write operation took to complete; provide the average measurement within the measurement interval", - "type": "number" - }, - "diskTimeWriteLast": { - "description": "milliseconds a write operation took to complete; provide the last measurement within the measurement interval", - "type": "number" - }, - "diskTimeWriteMax": { - "description": "milliseconds a write operation took to complete; provide the maximum measurement within the measurement interval", - "type": "number" - }, - "diskTimeWriteMin": { - "description": "milliseconds a write operation took to complete; provide the minimum measurement within the measurement interval", - "type": "number" - }, - "diskTotalReadLatencyAvg": { - "description": "average read time from the perspective of a Guest OS: sum of the Kernel Read Latency and Physical Device Read Latency in milliseconds over the measurement interval", - "type": "number" - }, - "diskTotalWriteLatencyAvg": { - "description": "average write time from the perspective of a Guest OS: sum of the Kernel Write Latency and Physical Device Write Latency in milliseconds over the measurement interval", - "type": "number" - }, - "diskWeightedIoTimeAvg": { - "description": "measure in ms over 1 sec of both I/O completion time and the backlog that may be accumulating; value is the average within the collection interval", - "type": "number" - }, - "diskWeightedIoTimeLast": { - "description": "measure in ms over 1 sec of both I/O completion time and the backlog that may be accumulating; value is the last within the collection interval", - "type": "number" - }, - "diskWeightedIoTimeMax": { - "description": "measure in ms over 1 sec of both I/O completion time and the backlog that may be accumulating; value is the maximum within the collection interval", - "type": "number" - }, - "diskWeightedIoTimeMin": { - "description": "measure in ms over 1 sec of both I/O completion time and the backlog that may be accumulating; value is the minimum within the collection interval", - "type": "number" - }, - "diskWriteCommandsAvg": { - "description": "average number of write commands issued per second to the disk over the measurementInterval", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "diskIdentifier" ] - }, - "endOfCallVqmSummaries": { - "description": "provides end of call voice quality metrics", - "type": "object", - "properties": { - "adjacencyName": { - "description": " adjacency name", - "type": "string" - }, - "endpointAverageJitter": { - "description": "endpoint average jitter", - "type": "number" - }, - "endpointDescription": { - "description": "either Caller or Callee", - "type": "string", - "enum": ["Caller", "Callee"] - }, - "endpointMaxJitter": { - "description": "endpoint maximum jitter", - "type": "number" - }, - "endpointRtpOctetsDiscarded": { - "description": "", - "type": "number" - }, - "endpointRtpOctetsLost": { - "description": "endpoint RTP octets lost", - "type": "number" - }, - "endpointRtpOctetsReceived": { - "description": "", - "type": "number" - }, - "endpointRtpOctetsSent": { - "description": "", - "type": "number" - }, - "endpointRtpPacketsDiscarded": { - "description": "", - "type": "number" - }, - "endpointRtpPacketsLost": { - "description": "endpoint RTP packets lost", - "type": "number" - }, - "endpointRtpPacketsReceived": { - "description": "", - "type": "number" - }, - "endpointRtpPacketsSent": { - "description": "", - "type": "number" - }, - "localAverageJitter": { - "description": "Local average jitter", - "type": "number" - }, - "localAverageJitterBufferDelay": { - "description": "Local average jitter delay", - "type": "number" - }, - "localMaxJitter": { - "description": "Local maximum jitter", - "type": "number" - }, - "localMaxJitterBufferDelay": { - "description": "Local maximum jitter delay", - "type": "number" - }, - "localRtpOctetsDiscarded": { - "description": "", - "type": "number" - }, - "localRtpOctetsLost": { - "description": "Local RTP octets lost", - "type": "number" - }, - "localRtpOctetsReceived": { - "description": "", - "type": "number" - }, - "localRtpOctetsSent": { - "description": "", - "type": "number" - }, - "localRtpPacketsDiscarded": { - "description": "", - "type": "number" - }, - "localRtpPacketsLost": { - "description": "Local RTP packets lost", - "type": "number" - }, - "localRtpPacketsReceived": { - "description": "", - "type": "number" - }, - "localRtpPacketsSent": { - "description": "", - "type": "number" - }, - "mosCqe": { - "description": "1-5 1dp", - "type": "number" - }, - "oneWayDelay": { - "description": "one-way path delay in milliseconds", - "type": "number" - }, - "packetLossPercent": { - "description" : "Calculated percentage packet loss based on Endpoint RTP packets lost (as reported in RTCP) and Local RTP packets sent. Direction is based on Endpoint description (Caller, Callee). Decimal (2 dp)", - "type": "number" - }, - "rFactor": { - "description": "0-100", - "type": "number" - }, - "roundTripDelay": { - "description": "millisecs", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "adjacencyName", "endpointDescription" ] - }, - "event": { - "description": "the root level of the common event format", - "type": "object", - "properties": { - "commonEventHeader": { "$ref": "#/definitions/commonEventHeader" }, - "faultFields": { "$ref": "#/definitions/faultFields" }, - "heartbeatFields": { "$ref": "#/definitions/heartbeatFields" }, - "measurementFields": { "$ref": "#/definitions/measurementFields" }, - "mobileFlowFields": { "$ref": "#/definitions/mobileFlowFields" }, - "notificationFields": { "$ref": "#/definitions/notificationFields" }, - "otherFields": { "$ref": "#/definitions/otherFields" }, - "pnfRegistrationFields": { "$ref": "#/definitions/pnfRegistrationFields" }, - "sipSignalingFields": { "$ref": "#/definitions/sipSignalingFields" }, - "stateChangeFields": { "$ref": "#/definitions/stateChangeFields" }, - "syslogFields": { "$ref": "#/definitions/syslogFields" }, - "thresholdCrossingAlertFields": { "$ref": "#/definitions/thresholdCrossingAlertFields" }, - "voiceQualityFields": { "$ref": "#/definitions/voiceQualityFields" } - }, - "additionalProperties": false, - "required": [ "commonEventHeader" ] - }, - "eventList": { - "description": "array of events", - "type": "array", - "items": { - "$ref": "#/definitions/event" - } - }, - "faultFields": { - "description": "fields specific to fault events", - "type": "object", - "properties": { - "alarmAdditionalInformation": { "$ref": "#/definitions/hashMap" }, - "alarmCondition": { - "description": "alarm condition reported by the device", - "type": "string" - }, - "alarmInterfaceA": { - "description": "card, port, channel or interface name of the device generating the alarm", - "type": "string" - }, - "eventCategory": { - "description": "Event category, for example: license, link, routing, security, signaling", - "type": "string" - }, - "eventSeverity": { - "description": "event severity", - "type": "string", - "enum": [ - "CRITICAL", - "MAJOR", - "MINOR", - "WARNING", - "NORMAL" - ] - }, - "eventSourceType": { - "description": "type of event source; examples: card, host, other, port, portThreshold, router, slotThreshold, switch, virtualMachine, virtualNetworkFunction", - "type": "string" - }, - "faultFieldsVersion": { - "description": "version of the faultFields block", - "type": "string", - "enum": [ "4.0" ] - }, - "specificProblem": { - "description": "short description of the alarm or problem", - "type": "string" - }, - "vfStatus": { - "description": "virtual function status enumeration", - "type": "string", - "enum": [ - "Active", - "Idle", - "Preparing to terminate", - "Ready to terminate", - "Requesting termination" - ] - } - }, - "additionalProperties": false, - "required": [ "alarmCondition", "eventSeverity", "eventSourceType", - "faultFieldsVersion", "specificProblem", "vfStatus" ] - }, - "filesystemUsage": { - "description": "disk usage of an identified virtual machine in gigabytes and/or gigabytes per second", - "type": "object", - "properties": { - "blockConfigured": { "type": "number" }, - "blockIops": { "type": "number" }, - "blockUsed": { "type": "number" }, - "ephemeralConfigured": { "type": "number" }, - "ephemeralIops": { "type": "number" }, - "ephemeralUsed": { "type": "number" }, - "filesystemName": { "type": "string" } - }, - "additionalProperties": false, - "required": [ "blockConfigured", "blockIops", "blockUsed", "ephemeralConfigured", - "ephemeralIops", "ephemeralUsed", "filesystemName" ] - }, - "gtpPerFlowMetrics": { - "description": "Mobility GTP Protocol per flow metrics", - "type": "object", - "properties": { - "avgBitErrorRate": { - "description": "average bit error rate", - "type": "number" - }, - "avgPacketDelayVariation": { - "description": "Average packet delay variation or jitter in milliseconds for received packets: Average difference between the packet timestamp and time received for all pairs of consecutive packets", - "type": "number" - }, - "avgPacketLatency": { - "description": "average delivery latency", - "type": "number" - }, - "avgReceiveThroughput": { - "description": "average receive throughput", - "type": "number" - }, - "avgTransmitThroughput": { - "description": "average transmit throughput", - "type": "number" - }, - "durConnectionFailedStatus": { - "description": "duration of failed state in milliseconds, computed as the cumulative time between a failed echo request and the next following successful error request, over this reporting interval", - "type": "number" - }, - "durTunnelFailedStatus": { - "description": "Duration of errored state, computed as the cumulative time between a tunnel error indicator and the next following non-errored indicator, over this reporting interval", - "type": "number" - }, - "flowActivatedBy": { - "description": "Endpoint activating the flow", - "type": "string" - }, - "flowActivationEpoch": { - "description": "Time the connection is activated in the flow (connection) being reported on, or transmission time of the first packet if activation time is not available", - "type": "number" - }, - "flowActivationMicrosec": { - "description": "Integer microseconds for the start of the flow connection", - "type": "number" - }, - "flowActivationTime": { - "description": "time the connection is activated in the flow being reported on, or transmission time of the first packet if activation time is not available; with RFC 2822 compliant format: Sat, 13 Mar 2010 11:29:05 -0800", - "type": "string" - }, - "flowDeactivatedBy": { - "description": "Endpoint deactivating the flow", - "type": "string" - }, - "flowDeactivationEpoch": { - "description": "Time for the start of the flow connection, in integer UTC epoch time aka UNIX time", - "type": "number" - }, - "flowDeactivationMicrosec": { - "description": "Integer microseconds for the start of the flow connection", - "type": "number" - }, - "flowDeactivationTime": { - "description": "Transmission time of the first packet in the flow connection being reported on; with RFC 2822 compliant format: Sat, 13 Mar 2010 11:29:05 -0800", - "type": "string" - }, - "flowStatus": { - "description": "connection status at reporting time as a working / inactive / failed indicator value", - "type": "string" - }, - "gtpConnectionStatus": { - "description": "Current connection state at reporting time", - "type": "string" - }, - "gtpTunnelStatus": { - "description": "Current tunnel state at reporting time", - "type": "string" - }, - "ipTosCountList": { "$ref": "#/definitions/hashMap" }, - "ipTosList": { - "description": "Array of unique IP Type-of-Service values observed in the flow where values range from '0' to '255'", - "type": "array", - "items": { - "type": "string" - } - }, - "largePacketRtt": { - "description": "large packet round trip time", - "type": "number" - }, - "largePacketThreshold": { - "description": "large packet threshold being applied", - "type": "number" - }, - "maxPacketDelayVariation": { - "description": "Maximum packet delay variation or jitter in milliseconds for received packets: Maximum of the difference between the packet timestamp and time received for all pairs of consecutive packets", - "type": "number" - }, - "maxReceiveBitRate": { - "description": "maximum receive bit rate", - "type": "number" - }, - "maxTransmitBitRate": { - "description": "maximum transmit bit rate", - "type": "number" - }, - "mobileQciCosCountList": { "$ref": "#/definitions/hashMap" }, - "mobileQciCosList": { - "description": "Array of unique LTE QCI or UMTS class-of-service values observed in the flow", - "type": "array", - "items": { - "type": "string" - } - }, - "numActivationFailures": { - "description": "Number of failed activation requests, as observed by the reporting node", - "type": "number" - }, - "numBitErrors": { - "description": "number of errored bits", - "type": "number" - }, - "numBytesReceived": { - "description": "number of bytes received, including retransmissions", - "type": "number" - }, - "numBytesTransmitted": { - "description": "number of bytes transmitted, including retransmissions", - "type": "number" - }, - "numDroppedPackets": { - "description": "number of received packets dropped due to errors per virtual interface", - "type": "number" - }, - "numGtpEchoFailures": { - "description": "Number of Echo request path failures where failed paths are defined in 3GPP TS 29.281 sec 7.2.1 and 3GPP TS 29.060 sec. 11.2", - "type": "number" - }, - "numGtpTunnelErrors": { - "description": "Number of tunnel error indications where errors are defined in 3GPP TS 29.281 sec 7.3.1 and 3GPP TS 29.060 sec. 11.1", - "type": "number" - }, - "numHttpErrors": { - "description": "Http error count", - "type": "number" - }, - "numL7BytesReceived": { - "description": "number of tunneled layer 7 bytes received, including retransmissions", - "type": "number" - }, - "numL7BytesTransmitted": { - "description": "number of tunneled layer 7 bytes transmitted, excluding retransmissions", - "type": "number" - }, - "numLostPackets": { - "description": "number of lost packets", - "type": "number" - }, - "numOutOfOrderPackets": { - "description": "number of out-of-order packets", - "type": "number" - }, - "numPacketErrors": { - "description": "number of errored packets", - "type": "number" - }, - "numPacketsReceivedExclRetrans": { - "description": "number of packets received, excluding retransmission", - "type": "number" - }, - "numPacketsReceivedInclRetrans": { - "description": "number of packets received, including retransmission", - "type": "number" - }, - "numPacketsTransmittedInclRetrans": { - "description": "number of packets transmitted, including retransmissions", - "type": "number" - }, - "numRetries": { - "description": "number of packet retries", - "type": "number" - }, - "numTimeouts": { - "description": "number of packet timeouts", - "type": "number" - }, - "numTunneledL7BytesReceived": { - "description": "number of tunneled layer 7 bytes received, excluding retransmissions", - "type": "number" - }, - "roundTripTime": { - "description": "round trip time", - "type": "number" - }, - "tcpFlagCountList": { "$ref": "#/definitions/hashMap" }, - "tcpFlagList": { - "description": "Array of unique TCP Flags observed in the flow", - "type": "array", - "items": { - "type": "string" - } - }, - "timeToFirstByte": { - "description": "Time in milliseconds between the connection activation and first byte received", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "avgBitErrorRate", "avgPacketDelayVariation", "avgPacketLatency", - "avgReceiveThroughput", "avgTransmitThroughput", - "flowActivationEpoch", "flowActivationMicrosec", - "flowDeactivationEpoch", "flowDeactivationMicrosec", - "flowDeactivationTime", "flowStatus", - "maxPacketDelayVariation", "numActivationFailures", - "numBitErrors", "numBytesReceived", "numBytesTransmitted", - "numDroppedPackets", "numL7BytesReceived", - "numL7BytesTransmitted", "numLostPackets", - "numOutOfOrderPackets", "numPacketErrors", - "numPacketsReceivedExclRetrans", - "numPacketsReceivedInclRetrans", - "numPacketsTransmittedInclRetrans", - "numRetries", "numTimeouts", "numTunneledL7BytesReceived", - "roundTripTime", "timeToFirstByte" - ] - }, - "hashMap": { - "description": "an associative array which is an array of key:value pairs", - "type": "object", - "additionalProperties": { "type": "string" }, - "default": {} - }, - "heartbeatFields": { - "description": "optional field block for fields specific to heartbeat events", - "type": "object", - "properties": { - "additionalFields": { "$ref": "#/definitions/hashMap" }, - "heartbeatFieldsVersion": { - "description": "version of the heartbeatFields block", - "type": "string", - "enum": [ "3.0" ] - }, - "heartbeatInterval": { - "description": "current heartbeat interval in seconds", - "type": "integer" - } - }, - "additionalProperties": false, - "required": [ "heartbeatFieldsVersion", "heartbeatInterval" ] - }, - "hugePages": { - "description": "metrics on system hugepages", - "type": "object", - "properties": { - "bytesFree": { - "description": "number of free hugepages in bytes", - "type": "number" - }, - "bytesUsed": { - "description": "number of used hugepages in bytes", - "type": "number" - }, - "hugePagesIdentifier": { - "description": "hugePages identifier", - "type": "number" - }, - "percentFree": { - "description": "number of free hugepages in percent", - "type": "number" - }, - "percentUsed": { - "description": "number of free hugepages in percent", - "type": "number" - }, - "vmPageNumberFree": { - "description": "number of free vmPages in numbers", - "type": "number" - }, - "vmPageNumberUsed": { - "description": "number of used vmPages in numbers", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "hugePagesIdentifier" ] - }, - "internalHeaderFields": { - "description": "enrichment fields for internal VES Event Listener service use only, not supplied by event sources", - "type": "object" - }, - "ipmi": { - "description": "intelligent platform management interface metrics", - "type": "object", - "properties": { - "exitAirTemperature": { - "description": "system fan exit air flow temperature in celsius", - "type": "number" - }, - "frontPanelTemperature": { - "description": "front panel temperature in celsius", - "type": "number" - }, - "ioModuleTemperature": { - "description": "io module temperature in celsius", - "type": "number" - }, - "ipmiBaseboardTemperatureArray": { - "description": "array of ipmiBaseboardTemperature objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiBaseboardTemperature" - } - }, - "ipmiBaseboardVoltageRegulatorArray": { - "description": "array of ipmiBaseboardVoltageRegulator objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiBaseboardVoltageRegulator" - } - }, - "ipmiBatteryArray": { - "description": "array of ipmiBattery objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiBattery" - } - }, - "ipmiFanArray": { - "description": "array of ipmiFan objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiFan" - } - }, - "ipmiHsbpArray": { - "description": "array of ipmiHsbp objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiHsbp" - } - }, - "ipmiGlobalAggregateTemperatureMarginArray": { - "description": "array of ipmiGlobalAggregateTemperatureMargin objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiGlobalAggregateTemperatureMargin" - } - }, - "ipmiNicArray": { - "description": "array of ipmiNic objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiNic" - } - }, - "ipmiPowerSupplyArray": { - "description": "array of ipmiPowerSupply objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiPowerSupply" - } - }, - "ipmiProcessorArray": { - "description": "array of ipmiProcessor objects", - "type": "array", - "items": { - "$ref": "#/definitions/ipmiProcessor" - } - }, - "systemAirflow": { - "description": "airfflow in cubic feet per minute (cfm)", - "type": "number" - } - }, - "additionalProperties": false - }, - "ipmiBaseboardTemperature": { - "description": "intelligent platform management interface (ipmi) baseboard temperature metrics", - "type": "object", - "properties": { - "baseboardTemperatureIdentifier": { - "description": "identifier for the location where the temperature is taken", - "type": "string" - }, - "baseboardTemperature": { - "description": "baseboard temperature in celsius", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "baseboardTemperatureIdentifier" ] - }, - "ipmiBaseboardVoltageRegulator": { - "description": "intelligent platform management interface (ipmi) baseboard voltage regulator metrics", - "type": "object", - "properties": { - "baseboardVoltageRegulatorIdentifier": { - "description": "identifier for the baseboard voltage regulator", - "type": "string" - }, - "voltageRegulatorTemperature": { - "description": "voltage regulator temperature in celsius", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "baseboardVoltageRegulatorIdentifier" ] - }, - "ipmiBattery": { - "description": "intelligent platform management interface (ipmi) battery metrics", - "type": "object", - "properties": { - "batteryIdentifier": { - "description": "identifier for the battery", - "type": "string" - }, - "batteryType": { - "description": "type of battery", - "type": "string" - }, - "batteryVoltageLevel": { - "description": "battery voltage level", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "batteryIdentifier" ] - }, - "ipmiFan": { - "description": "intelligent platform management interface (ipmi) fan metrics", - "type": "object", - "properties": { - "fanIdentifier": { - "description": "identifier for the fan", - "type": "string" - }, - "fanSpeed": { - "description": "fan speed in revolutions per minute (rpm)", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "fanIdentifier" ] - }, - "ipmiGlobalAggregateTemperatureMargin": { - "description": "intelligent platform management interface (ipmi) global aggregate temperature margin", - "type": "object", - "properties": { - "ipmiGlobalAggregateTemperatureMarginIdentifier": { - "description": "identifier for the ipmi global aggregate temperature margin metrics", - "type": "string" - }, - "globalAggregateTemperatureMargin": { - "description": "the difference between the current global aggregate temperature, in celsius, and the global aggregate throttling thermal trip point", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "ipmiGlobalAggregateTemperatureMarginIdentifier", "globalAggregateTemperatureMargin" ] - }, - "ipmiHsbp": { - "description": "intelligent platform management interface (ipmi) hot swap backplane power metrics", - "type": "object", - "properties": { - "hsbpIdentifier": { - "description": "identifier for the hot swap backplane power unit", - "type": "string" - }, - "hsbpTemperature": { - "description": "hot swap backplane power temperature in celsius", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "hsbpIdentifier" ] - }, - "ipmiNic": { - "description": "intelligent platform management interface (ipmi) network interface control card (nic) metrics", - "type": "object", - "properties": { - "nicIdentifier": { - "description": "identifier for the network interface control card", - "type": "string" - }, - "nicTemperature": { - "description": "nic temperature in celsius", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "nicIdentifier" ] - }, - "ipmiPowerSupply": { - "description": "intelligent platform management interface (ipmi) power supply metrics", - "type": "object", - "properties": { - "powerSupplyIdentifier": { - "description": "identifier for the power supply", - "type": "string" - }, - "powerSupplyInputPower": { - "description": "input power in watts", - "type": "number" - }, - "powerSupplyCurrentOutputPercent": { - "description": "current output voltage as a percentage of the design specified level", - "type": "number" - }, - "powerSupplyTemperature": { - "description": "power supply temperature in celsius", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "powerSupplyIdentifier" ] - }, - "ipmiProcessor": { - "description": "intelligent platform management interface processor metrics", - "type": "object", - "properties": { - "processorIdentifier": { - "description": "identifier for an ipmi processor", - "type": "string" - }, - "processorThermalControlPercent": { - "description": "io module temperature in celsius", - "type": "number" - }, - "processorDtsThermalMargin": { - "description": "front panel temperature in celsius", - "type": "number" - }, - "processorDimmAggregateThermalMarginArray": { - "description": "array of processorDimmAggregateThermalMargin objects", - "type": "array", - "items": { - "$ref": "#/definitions/processorDimmAggregateThermalMargin" - } - } - }, - "additionalProperties": false, - "required": [ "processorIdentifier" ] - }, - "jsonObject": { - "description": "json object schema, name and other meta-information along with one or more object instances", - "type": "object", - "properties": { - "objectInstances": { - "description": "one or more instances of the jsonObject", - "type": "array", - "items": { - "$ref": "#/definitions/jsonObjectInstance" - } - }, - "objectName": { - "description": "name of the JSON Object", - "type": "string" - }, - "objectSchema": { - "description": "json schema for the object", - "type": "string" - }, - "objectSchemaUrl": { - "description": "Url to the json schema for the object", - "type": "string" - }, - "nfSubscribedObjectName": { - "description": "name of the object associated with the nfSubscriptonId", - "type": "string" - }, - "nfSubscriptionId": { - "description": "identifies an openConfig telemetry subscription on a network function, which configures the network function to send complex object data associated with the jsonObject", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "objectInstances", "objectName" ] - }, - "jsonObjectInstance": { - "description": "meta-information about an instance of a jsonObject along with the actual object instance", - "type": "object", - "properties": { - "jsonObject": { "$ref": "#/definitions/jsonObject" }, - "objectInstance": { - "description": "an instance conforming to the jsonObject objectSchema", - "type": "object" - }, - "objectInstanceEpochMicrosec": { - "description": "the unix time aka epoch time associated with this objectInstance--as microseconds elapsed since 1 Jan 1970 not including leap seconds", - "type": "number" - }, - "objectKeys": { - "description": "an ordered set of keys that identifies this particular instance of jsonObject", - "type": "array", - "items": { - "$ref": "#/definitions/key" - } - } - }, - "additionalProperties": false - }, - "key": { - "description": "tuple which provides the name of a key along with its value and relative order", - "type": "object", - "properties": { - "keyName": { - "description": "name of the key", - "type": "string" - }, - "keyOrder": { - "description": "relative sequence or order of the key with respect to other keys", - "type": "integer" - }, - "keyValue": { - "description": "value of the key", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "keyName" ] - }, - "latencyBucketMeasure": { - "description": "number of counts falling within a defined latency bucket", - "type": "object", - "properties": { - "countsInTheBucket": { "type": "number" }, - "highEndOfLatencyBucket": { "type": "number" }, - "lowEndOfLatencyBucket": { "type": "number" } - }, - "additionalProperties": false, - "required": [ "countsInTheBucket" ] - }, - "load": { - "description": "/proc/loadavg cpu utilization and io utilization metrics", - "type": "object", - "properties": { - "longTerm": { - "description": "number of jobs in the run queue (state R, cpu utilization) or waiting for disk I/O (state D, io utilization) averaged over 15 minutes using /proc/loadavg", - "type": "number" - }, - "midTerm": { - "description": "number of jobs in the run queue (state R, cpu utilization) or waiting for disk I/O (state D, io utilization) averaged over 5 minutes using /proc/loadavg", - "type": "number" - }, - "shortTerm": { - "description": "number of jobs in the run queue (state R, cpu utilization) or waiting for disk I/O (state D, io utilization) averaged over 1 minute using /proc/loadavg", - "type": "number" - } - }, - "additionalProperties": false - }, - "machineCheckException": { - "description": "metrics on vm machine check exceptions", - "type": "object", - "properties": { - "correctedMemoryErrors": { - "description": "total hardware errors that were corrected by the hardware (e.g. data corruption corrected via  ECC) over the measurementInterval", - "type": "number" - }, - "correctedMemoryErrorsIn1Hr": { - "description": "total hardware errors that were corrected by the hardware over the last one hour", - "type": "number" - }, - "uncorrectedMemoryErrors": { - "description": "total uncorrected hardware errors that were detected by the hardware (e.g., causing data corruption) over the measurementInterval", - "type": "number" - }, - "uncorrectedMemoryErrorsIn1Hr": { - "description": "total uncorrected hardware errors that were detected by the hardware over the last one hour", - "type": "number" - }, - "vmIdentifier": { - "description": "virtual machine identifier associated with the machine check exception", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "vmIdentifier" ] - }, - "measurementFields": { - "description": "measurement fields", - "type": "object", - "properties": { - "additionalFields": { "$ref": "#/definitions/hashMap" }, - "additionalMeasurements": {"$ref": "#/definitions/arrayOfNamedHashMap"}, - "additionalObjects": {"$ref": "#/definitions/arrayOfJsonObject"}, - "codecUsageArray": { - "description": "array of codecs in use", - "type": "array", - "items": { - "$ref": "#/definitions/codecsInUse" - } - }, - "concurrentSessions": { - "description": "peak concurrent sessions for the VM or xNF over the measurementInterval", - "type": "integer" - }, - "configuredEntities": { - "description": "over the measurementInterval, peak total number of: users, subscribers, devices, adjacencies, etc., for the VM, or subscribers, devices, etc., for the xNF", - "type": "integer" - }, - "cpuUsageArray": { - "description": "usage of an array of CPUs", - "type": "array", - "items": { - "$ref": "#/definitions/cpuUsage" - } - }, - "diskUsageArray": { - "description": "usage of an array of disks", - "type": "array", - "items": { - "$ref": "#/definitions/diskUsage" - } - }, - "featureUsageArray": { "$ref": "#/definitions/hashMap" }, - "filesystemUsageArray": { - "description": "filesystem usage of the VM on which the xNFC reporting the event is running", - "type": "array", - "items": { - "$ref": "#/definitions/filesystemUsage" - } - }, - "hugePagesArray": { - "description": "array of metrics on hugepPages", - "type": "array", - "items": { - "$ref": "#/definitions/hugePages" - } - }, - "ipmi": { "$ref": "#/definitions/ipmi" }, - "latencyDistribution": { - "description": "array of integers representing counts of requests whose latency in milliseconds falls within per-xNF configured ranges", - "type": "array", - "items": { - "$ref": "#/definitions/latencyBucketMeasure" - } - }, - "loadArray": { - "description": "array of system load metrics", - "type": "array", - "items": { - "$ref": "#/definitions/load" - } - }, - "machineCheckExceptionArray": { - "description": "array of machine check exceptions", - "type": "array", - "items": { - "$ref": "#/definitions/machineCheckException" - } - }, - "meanRequestLatency": { - "description": "mean seconds required to respond to each request for the VM on which the xNFC reporting the event is running", - "type": "number" - }, - "measurementInterval": { - "description": "interval over which measurements are being reported in seconds", - "type": "number" - }, - "measurementFieldsVersion": { - "description": "version of the measurementFields block", - "type": "string", - "enum": [ "4.0" ] - }, - "memoryUsageArray": { - "description": "memory usage of an array of VMs", - "type": "array", - "items": { - "$ref": "#/definitions/memoryUsage" - } - }, - "numberOfMediaPortsInUse": { - "description": "number of media ports in use", - "type": "integer" - }, - "requestRate": { - "description": "peak rate of service requests per second to the xNF over the measurementInterval", - "type": "number" - }, - "nfcScalingMetric": { - "description": "represents busy-ness of the network function from 0 to 100 as reported by the xNFC", - "type": "integer" - }, - "nicPerformanceArray": { - "description": "usage of an array of network interface cards", - "type": "array", - "items": { - "$ref": "#/definitions/nicPerformance" - } - }, - "processStatsArray": { - "description": "array of metrics on system processes", - "type": "array", - "items": { - "$ref": "#/definitions/processStats" - } - } - }, - "additionalProperties": false, - "required": [ "measurementInterval", "measurementFieldsVersion" ] - }, - "memoryUsage": { - "description": "memory usage of an identified virtual machine", - "type": "object", - "properties": { - "memoryBuffered": { - "description": "kibibytes of temporary storage for raw disk blocks", - "type": "number" - }, - "memoryCached": { - "description": "kibibytes of memory used for cache", - "type": "number" - }, - "memoryConfigured": { - "description": "kibibytes of memory configured in the virtual machine on which the xNFC reporting the event is running", - "type": "number" - }, - "memoryDemand": { - "description": "host demand in kibibytes", - "type": "number" - }, - "memoryFree": { - "description": "kibibytes of physical RAM left unused by the system", - "type": "number" - }, - "memoryLatencyAvg": { - "description": "Percentage of time the VM is waiting to access swapped or compressed memory", - "type": "number" - }, - "memorySharedAvg": { - "description": "shared memory in kilobytes", - "type": "number" - }, - "memorySlabRecl": { - "description": "the part of the slab that can be reclaimed such as caches measured in kibibytes", - "type": "number" - }, - "memorySlabUnrecl": { - "description": "the part of the slab that cannot be reclaimed even when lacking memory measured in kibibytes", - "type": "number" - }, - "memorySwapInAvg": { - "description": "Amount of memory swapped-in from host cache in kibibytes", - "type": "number" - }, - "memorySwapInRateAvg": { - "description": "rate at which memory is swapped from disk into active memory during the interval in kilobytes per second", - "type": "number" - }, - "memorySwapOutAvg": { - "description": "Amount of memory swapped-out to host cache in kibibytes", - "type": "number" - }, - "memorySwapOutRateAvg": { - "description": "rate at which memory is being swapped from active memory to disk during the current interval in kilobytes per second", - "type": "number" - }, - "memorySwapUsedAvg": { - "description": "space used for caching swapped pages in the host cache in kibibytes", - "type": "number" - }, - "memoryUsed": { - "description": "total memory minus the sum of free, buffered, cached and slab memory measured in kibibytes", - "type": "number" - }, - "percentMemoryUsage": { - "description": "Percentage of memory usage; value = (memoryUsed / (memoryUsed + memoryFree) x 100 if denomintor is nonzero, or 0, if otherwise", - "type": "number" - }, - "vmIdentifier": { - "description": "virtual machine identifier associated with the memory metrics", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "memoryFree", "memoryUsed", "vmIdentifier" ] - }, - "mobileFlowFields": { - "description": "mobileFlow fields", - "type": "object", - "properties": { - "additionalFields": { "$ref": "#/definitions/hashMap" }, - "applicationType": { - "description": "Application type inferred", - "type": "string" - }, - "appProtocolType": { - "description": "application protocol", - "type": "string" - }, - "appProtocolVersion": { - "description": "application protocol version", - "type": "string" - }, - "cid": { - "description": "cell id", - "type": "string" - }, - "connectionType": { - "description": "Abbreviation referencing a 3GPP reference point e.g., S1-U, S11, etc", - "type": "string" - }, - "ecgi": { - "description": "Evolved Cell Global Id", - "type": "string" - }, - "flowDirection": { - "description": "Flow direction, indicating if the reporting node is the source of the flow or destination for the flow", - "type": "string" - }, - "gtpPerFlowMetrics": { "$ref": "#/definitions/gtpPerFlowMetrics" }, - "gtpProtocolType": { - "description": "GTP protocol", - "type": "string" - }, - "gtpVersion": { - "description": "GTP protocol version", - "type": "string" - }, - "httpHeader": { - "description": "HTTP request header, if the flow connects to a node referenced by HTTP", - "type": "string" - }, - "imei": { - "description": "IMEI for the subscriber UE used in this flow, if the flow connects to a mobile device", - "type": "string" - }, - "imsi": { - "description": "IMSI for the subscriber UE used in this flow, if the flow connects to a mobile device", - "type": "string" - }, - "ipProtocolType": { - "description": "IP protocol type e.g., TCP, UDP, RTP...", - "type": "string" - }, - "ipVersion": { - "description": "IP protocol version e.g., IPv4, IPv6", - "type": "string" - }, - "lac": { - "description": "location area code", - "type": "string" - }, - "mcc": { - "description": "mobile country code", - "type": "string" - }, - "mnc": { - "description": "mobile network code", - "type": "string" - }, - "mobileFlowFieldsVersion": { - "description": "version of the mobileFlowFields block", - "type": "string", - "enum": [ "4.0" ] - }, - "msisdn": { - "description": "MSISDN for the subscriber UE used in this flow, as an integer, if the flow connects to a mobile device", - "type": "string" - }, - "otherEndpointIpAddress": { - "description": "IP address for the other endpoint, as used for the flow being reported on", - "type": "string" - }, - "otherEndpointPort": { - "description": "IP Port for the reporting entity, as used for the flow being reported on", - "type": "integer" - }, - "otherFunctionalRole": { - "description": "Functional role of the other endpoint for the flow being reported on e.g., MME, S-GW, P-GW, PCRF...", - "type": "string" - }, - "rac": { - "description": "routing area code", - "type": "string" - }, - "radioAccessTechnology": { - "description": "Radio Access Technology e.g., 2G, 3G, LTE", - "type": "string" - }, - "reportingEndpointIpAddr": { - "description": "IP address for the reporting entity, as used for the flow being reported on", - "type": "string" - }, - "reportingEndpointPort": { - "description": "IP port for the reporting entity, as used for the flow being reported on", - "type": "integer" - }, - "sac": { - "description": "service area code", - "type": "string" - }, - "samplingAlgorithm": { - "description": "Integer identifier for the sampling algorithm or rule being applied in calculating the flow metrics if metrics are calculated based on a sample of packets, or 0 if no sampling is applied", - "type": "integer" - }, - "tac": { - "description": "transport area code", - "type": "string" - }, - "tunnelId": { - "description": "tunnel identifier", - "type": "string" - }, - "vlanId": { - "description": "VLAN identifier used by this flow", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "flowDirection", "gtpPerFlowMetrics", "ipProtocolType", "ipVersion", - "mobileFlowFieldsVersion", "otherEndpointIpAddress", "otherEndpointPort", - "reportingEndpointIpAddr", "reportingEndpointPort" ] - }, - "namedHashMap": { - "description": "a hashMap which is associated with and described by a name", - "type": "object", - "properties": { - "name": { "type": "string" }, - "hashMap": { "$ref": "#/definitions/hashMap" } - }, - "additionalProperties": false, - "required": [ "name", "hashMap" ] - }, - "nicPerformance": { - "description": "describes the performance and errors of an identified network interface card", - "type": "object", - "properties": { - "administrativeState": { - "description": "administrative state", - "type": "string", - "enum": [ "inService", "outOfService" ] - }, - "nicIdentifier": { - "description": "nic identification", - "type": "string" - }, - "operationalState": { - "description": "operational state", - "type": "string", - "enum": [ "inService", "outOfService" ] - }, - "receivedBroadcastPacketsAccumulated": { - "description": "Cumulative count of broadcast packets received as read at the end of the measurement interval", - "type": "number" - }, - "receivedBroadcastPacketsDelta": { - "description": "Count of broadcast packets received within the measurement interval", - "type": "number" - }, - "receivedDiscardedPacketsAccumulated": { - "description": "Cumulative count of discarded packets received as read at the end of the measurement interval", - "type": "number" - }, - "receivedDiscardedPacketsDelta": { - "description": "Count of discarded packets received within the measurement interval", - "type": "number" - }, - "receivedErrorPacketsAccumulated": { - "description": "Cumulative count of error packets received as read at the end of the measurement interval", - "type": "number" - }, - "receivedErrorPacketsDelta": { - "description": "Count of error packets received within the measurement interval", - "type": "number" - }, - "receivedMulticastPacketsAccumulated": { - "description": "Cumulative count of multicast packets received as read at the end of the measurement interval", - "type": "number" - }, - "receivedMulticastPacketsDelta": { - "description": "Count of multicast packets received within the measurement interval", - "type": "number" - }, - "receivedOctetsAccumulated": { - "description": "Cumulative count of octets received as read at the end of the measurement interval", - "type": "number" - }, - "receivedOctetsDelta": { - "description": "Count of octets received within the measurement interval", - "type": "number" - }, - "receivedTotalPacketsAccumulated": { - "description": "Cumulative count of all packets received as read at the end of the measurement interval", - "type": "number" - }, - "receivedPercentDiscard": { - "description": "Percentage of discarded packets received; value = (receivedDiscardedPacketsDelta / receivedTotalPacketsDelta) x 100, if denominator is nonzero, or 0, if otherwise", - "type": "number" - }, - "receivedPercentError": { - "description": "Percentage of error packets received; value = (receivedErrorPacketsDelta / receivedTotalPacketsDelta) x 100, if denominator is nonzero, or 0, if otherwise.", - "type": "number" - }, - "receivedTotalPacketsDelta": { - "description": "Count of all packets received within the measurement interval", - "type": "number" - }, - "receivedUnicastPacketsAccumulated": { - "description": "Cumulative count of unicast packets received as read at the end of the measurement interval", - "type": "number" - }, - "receivedUnicastPacketsDelta": { - "description": "Count of unicast packets received within the measurement interval", - "type": "number" - }, - "receivedUtilization": { - "description": "Percentage of utilization received; value = (receivedOctetsDelta / (speed x (lastEpochMicrosec - startEpochMicrosec))) x 100, if denominator is nonzero, or 0, if otherwise", - "type": "number" - }, - "speed": { - "description": "Speed configured in mbps", - "type": "number" - }, - "transmittedBroadcastPacketsAccumulated": { - "description": "Cumulative count of broadcast packets transmitted as read at the end of the measurement interval", - "type": "number" - }, - "transmittedBroadcastPacketsDelta": { - "description": "Count of broadcast packets transmitted within the measurement interval", - "type": "number" - }, - "transmittedDiscardedPacketsAccumulated": { - "description": "Cumulative count of discarded packets transmitted as read at the end of the measurement interval", - "type": "number" - }, - "transmittedDiscardedPacketsDelta": { - "description": "Count of discarded packets transmitted within the measurement interval", - "type": "number" - }, - "transmittedErrorPacketsAccumulated": { - "description": "Cumulative count of error packets transmitted as read at the end of the measurement interval", - "type": "number" - }, - "transmittedErrorPacketsDelta": { - "description": "Count of error packets transmitted within the measurement interval", - "type": "number" - }, - "transmittedMulticastPacketsAccumulated": { - "description": "Cumulative count of multicast packets transmitted as read at the end of the measurement interval", - "type": "number" - }, - "transmittedMulticastPacketsDelta": { - "description": "Count of multicast packets transmitted within the measurement interval", - "type": "number" - }, - "transmittedOctetsAccumulated": { - "description": "Cumulative count of octets transmitted as read at the end of the measurement interval", - "type": "number" - }, - "transmittedOctetsDelta": { - "description": "Count of octets transmitted within the measurement interval", - "type": "number" - }, - "transmittedTotalPacketsAccumulated": { - "description": "Cumulative count of all packets transmitted as read at the end of the measurement interval", - "type": "number" - }, - "transmittedTotalPacketsDelta": { - "description": "Count of all packets transmitted within the measurement interval", - "type": "number" - }, - "transmittedUnicastPacketsAccumulated": { - "description": "Cumulative count of unicast packets transmitted as read at the end of the measurement interval", - "type": "number" - }, - "transmittedUnicastPacketsDelta": { - "description": "Count of unicast packets transmitted within the measurement interval", - "type": "number" - }, - "transmittedPercentDiscard": { - "description": "Percentage of discarded packets transmitted; value = (transmittedDiscardedPacketsDelta / transmittedTotalPacketsDelta) x 100, if denominator is nonzero, or 0, if otherwise", - "type": "number" - }, - "transmittedPercentError": { - "description": "Percentage of error packets received; value = (transmittedErrorPacketsDelta / transmittedTotalPacketsDelta) x 100, if denominator is nonzero, or 0, if otherwise", - "type": "number" - }, - "transmittedUtilization": { - "description": "Percentage of utilization transmitted; value = (transmittedOctetsDelta / (speed x (lastEpochMicrosec - startEpochMicrosec))) x 100, if denominator is nonzero, or 0, if otherwise.", - "type": "number" - }, - "valuesAreSuspect": { - "description": "Indicates whether vNicPerformance values are likely inaccurate due to counter overflow or other condtions", - "type": "string", - "enum": [ "true", "false" ] - } - }, - "additionalProperties": false, - "required": [ "nicIdentifier", "valuesAreSuspect" ] - }, - "notificationFields": { - "description": "notification fields", - "type": "object", - "properties": { - "additionalFields": { "$ref": "#/definitions/hashMap" }, - "arrayOfNamedHashMap": {"$ref": "#/definitions/arrayOfNamedHashMap"}, - "changeContact": { - "description": "identifier for a contact related to the change", - "type": "string" - }, - "changeIdentifier": { - "description": "system or session identifier associated with the change", - "type": "string" - }, - "changeType": { - "description": "describes what has changed for the entity", - "type": "string" - }, - "newState": { - "description": "new state of the entity", - "type": "string" - }, - "oldState": { - "description": "previous state of the entity", - "type": "string" - }, - "notificationFieldsVersion": { - "description": "version of the notificationFields block", - "type": "string", - "enum": [ "2.0" ] - }, - "stateInterface": { - "description": "card or port name of the entity that changed state", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "changeIdentifier", "changeType", "notificationFieldsVersion" ] - }, - "otherFields": { - "description": "fields for events belonging to the 'other' domain of the commonEventHeader domain enumeration", - "type": "object", - "properties": { - "arrayOfNamedHashMap": {"$ref": "#/definitions/arrayOfNamedHashMap"}, - "hashMap": {"$ref": "#/definitions/hashMap"}, - "jsonObjects": {"$ref": "#/definitions/arrayOfJsonObject"}, - "otherFieldsVersion": { - "description": "version of the otherFields block", - "type": "string", - "enum": [ "3.0" ] - } - }, - "additionalProperties": false, - "required": [ "otherFieldsVersion" ] - }, - "pnfRegistrationFields": { - "description": "hardware device registration fields", - "type": "object", - "properties": { - "additionalFields": { "$ref": "#/definitions/hashMap" }, - "lastServiceDate": { - "description": "TS 32.692 dateOfLastService = date of last service; e.g. 15022017", - "type": "string" - }, - "macAddress": { - "description": "MAC address of OAM interface of the unit", - "type": "string" - }, - "manufactureDate": { - "description": "TS 32.692 dateOfManufacture = manufacture date of the unit; 24032016", - "type": "string" - }, - "modelNumber": { - "description": "TS 32.692 versionNumber = version of the unit from vendor; e.g. AJ02. Maps to AAI equip-model", - "type": "string" - }, - "oamV4IpAddress": { - "description": "IPv4 m-plane IP address to be used by the manager to contact the PNF", - "type": "string" - }, - "oamV6IpAddress": { - "description": "IPv6 m-plane IP address to be used by the manager to contact the PNF", - "type": "string" - }, - "pnfRegistrationFieldsVersion": { - "description": "version of the pnfRegistrationFields block", - "type": "string", - "enum": [ "2.0" ] - }, - "serialNumber": { - "description": "TS 32.692 serialNumber = serial number of the unit; e.g. 6061ZW3", - "type": "string" - }, - "softwareVersion": { - "description": "TS 32.692 swName = active SW running on the unit; e.g. 5gDUv18.05.201", - "type": "string" - }, - "unitFamily": { - "description": "TS 32.692 vendorUnitFamilyType = general type of HW unit; e.g. BBU", - "type": "string" - }, - "unitType": { - "description": "TS 32.692 vendorUnitTypeNumber = vendor name for the unit; e.g. Airscale", - "type": "string" - }, - "vendorName": { - "description": "TS 32.692 vendorName = name of manufacturer; e.g. Nokia. Maps to AAI equip-vendor", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "pnfRegistrationFieldsVersion" ] - }, - "processorDimmAggregateThermalMargin": { - "description": "intelligent platform management interface (ipmi) processor dual inline memory module aggregate thermal margin metrics", - "type": "object", - "properties": { - "processorDimmAggregateThermalMarginIdentifier": { - "description": "identifier for the aggregate thermal margin metrics from the processor dual inline memory module", - "type": "string" - }, - "thermalMargin": { - "description": "the difference between the DIMM's current temperature, in celsius, and the DIMM's throttling thermal trip point", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "processorDimmAggregateThermalMarginIdentifier", "thermalMargin" ] - }, - "processStats": { - "description": "metrics on system processes", - "type": "object", - "properties": { - "forkRate": { - "description": "the number of threads created since the last reboot", - "type": "number" - }, - "processIdentifier": { - "description": "processIdentifier", - "type": "string" - }, - "psStateBlocked": { - "description": "the number of processes in a blocked state", - "type": "number" - }, - "psStatePaging": { - "description": "the number of processes in a paging state", - "type": "number" - }, - "psStateRunning": { - "description": "the number of processes in a running state", - "type": "number" - }, - "psStateSleeping": { - "description": "the number of processes in a sleeping state", - "type": "number" - }, - "psStateStopped": { - "description": "the number of processes in a stopped state", - "type": "number" - }, - "psStateZombie": { - "description": "the number of processes in a zombie state", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "processIdentifier" ] - }, - "requestError": { - "description": "standard request error data structure", - "type": "object", - "properties": { - "messageId": { - "description": "Unique message identifier of the format ABCnnnn where ABC is either SVC for Service Exceptions or POL for Policy Exception", - "type": "string" - }, - "text": { - "description": "Message text, with replacement variables marked with %n, where n is an index into the list of <variables> elements, starting at 1", - "type": "string" - }, - "url": { - "description": "Hyperlink to a detailed error resource e.g., an HTML page for browser user agents", - "type": "string" - }, - "variables": { - "description": "List of zero or more strings that represent the contents of the variables used by the message text", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "messageId", "text" ] - }, - "sipSignalingFields": { - "description": "sip signaling fields", - "type": "object", - "properties": { - "additionalInformation": { "$ref": "#/definitions/hashMap"}, - "compressedSip": { - "description": "the full SIP request/response including headers and bodies", - "type": "string" - }, - "correlator": { - "description": "this is the same for all events on this call", - "type": "string" - }, - "localIpAddress": { - "description": "IP address on xNF", - "type": "string" - }, - "localPort": { - "description": "port on xNF", - "type": "string" - }, - "remoteIpAddress": { - "description": "IP address of peer endpoint", - "type": "string" - }, - "remotePort": { - "description": "port of peer endpoint", - "type": "string" - }, - "sipSignalingFieldsVersion": { - "description": "version of the sipSignalingFields block", - "type": "string", - "enum": [ "3.0" ] - }, - "summarySip": { - "description": "the SIP Method or Response ('INVITE', '200 OK', 'BYE', etc)", - "type": "string" - }, - "vendorNfNameFields": { - "$ref": "#/definitions/vendorNfNameFields" - } - }, - "additionalProperties": false, - "required": [ "correlator", "localIpAddress", "localPort", "remoteIpAddress", - "remotePort", "sipSignalingFieldsVersion", "vendorNfNameFields" ] - }, - "stateChangeFields": { - "description": "stateChange fields", - "type": "object", - "properties": { - "additionalFields": { "$ref": "#/definitions/hashMap" }, - "newState": { - "description": "new state of the entity", - "type": "string", - "enum": [ - "inService", - "maintenance", - "outOfService" - ] - }, - "oldState": { - "description": "previous state of the entity", - "type": "string", - "enum": [ - "inService", - "maintenance", - "outOfService" - ] - }, - "stateChangeFieldsVersion": { - "description": "version of the stateChangeFields block", - "type": "string", - "enum": [ "4.0" ] - }, - "stateInterface": { - "description": "card or port name of the entity that changed state", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "newState", "oldState", "stateChangeFieldsVersion", "stateInterface" ] - }, - "syslogFields": { - "description": "sysLog fields", - "type": "object", - "properties": { - "additionalFields": { "$ref": "#/definitions/hashMap" }, - "eventSourceHost": { - "description": "hostname of the device", - "type": "string" - }, - "eventSourceType": { - "description": "type of event source; examples: other, router, switch, host, card, port, slotThreshold, portThreshold, virtualMachine, virtualNetworkFunction", - "type": "string" - }, - "syslogFacility": { - "description": "numeric code from 0 to 23 for facility--see table in documentation", - "type": "integer" - }, - "syslogFieldsVersion": { - "description": "version of the syslogFields block", - "type": "string", - "enum": [ "4.0" ] - }, - "syslogMsg": { - "description": "syslog message", - "type": "string" - }, - "syslogMsgHost": { - "description": "hostname parsed from non-VES syslog message", - "type": "string" - }, - "syslogPri": { - "description": "0-192 combined severity and facility", - "type": "integer" - }, - "syslogProc": { - "description": "identifies the application that originated the message", - "type": "string" - }, - "syslogProcId": { - "description": "a change in the value of this field indicates a discontinuity in syslog reporting", - "type": "number" - }, - "syslogSData": { - "description": "syslog structured data consisting of a structured data Id followed by a set of key value pairs", - "type": "string" - }, - "syslogSdId": { - "description": "0-32 char in format name@number for example ourSDID@32473", - "type": "string" - }, - "syslogSev": { - "description": "numerical Code for severity derived from syslogPri as remaider of syslogPri / 8", - "type": "string", - "enum": [ - "Alert", - "Critical", - "Debug", - "Emergency", - "Error", - "Info", - "Notice", - "Warning" - ] - }, - "syslogTag": { - "description": "msgId indicating the type of message such as TCPOUT or TCPIN; NILVALUE should be used when no other value can be provided", - "type": "string" - }, - "syslogTs": { - "description": "timestamp parsed from non-VES syslog message", - "type": "string" - }, - "syslogVer": { - "description": "IANA assigned version of the syslog protocol specification - typically 1", - "type": "number" - } - }, - "additionalProperties": false, - "required": [ "eventSourceType", "syslogFieldsVersion", "syslogMsg", "syslogTag" ] - }, - "thresholdCrossingAlertFields": { - "description": "fields specific to threshold crossing alert events", - "type": "object", - "properties": { - "additionalFields": { "$ref": "#/definitions/hashMap"}, - "additionalParameters": { - "description": "performance counters", - "type": "array", - "items": { - "$ref": "#/definitions/counter" - } - }, - "alertAction": { - "description": "Event action", - "type": "string", - "enum": [ - "CLEAR", - "CONT", - "SET" - ] - }, - "alertDescription": { - "description": "Unique short alert description such as IF-SHUB-ERRDROP", - "type": "string" - }, - "alertType": { - "description": "Event type", - "type": "string", - "enum": [ - "CARD-ANOMALY", - "ELEMENT-ANOMALY", - "INTERFACE-ANOMALY", - "SERVICE-ANOMALY" - ] - }, - "alertValue": { - "description": "Calculated API value (if applicable)", - "type": "string" - }, - "associatedAlertIdList": { - "description": "List of eventIds associated with the event being reported", - "type": "array", - "items": { "type": "string" } - }, - "collectionTimestamp": { - "description": "Time when the performance collector picked up the data; with RFC 2822 compliant format: Sat, 13 Mar 2010 11:29:05 -0800", - "type": "string" - }, - "dataCollector": { - "description": "Specific performance collector instance used", - "type": "string" - }, - "elementType": { - "description": "type of network element - internal ATT field", - "type": "string" - }, - "eventSeverity": { - "description": "event severity or priority", - "type": "string", - "enum": [ - "CRITICAL", - "MAJOR", - "MINOR", - "WARNING", - "NORMAL" - ] - }, - "eventStartTimestamp": { - "description": "Time closest to when the measurement was made; with RFC 2822 compliant format: Sat, 13 Mar 2010 11:29:05 -0800", - "type": "string" - }, - "interfaceName": { - "description": "Physical or logical port or card (if applicable)", - "type": "string" - }, - "networkService": { - "description": "network name - internal ATT field", - "type": "string" - }, - "possibleRootCause": { - "description": "Reserved for future use", - "type": "string" - }, - "thresholdCrossingFieldsVersion": { - "description": "version of the thresholdCrossingAlertFields block", - "type": "string", - "enum": [ "4.0" ] - } - }, - "additionalProperties": false, - "required": [ - "additionalParameters", - "alertAction", - "alertDescription", - "alertType", - "collectionTimestamp", - "eventSeverity", - "eventStartTimestamp", - "thresholdCrossingFieldsVersion" - ] - }, - "vendorNfNameFields": { - "description": "provides vendor, nf and nfModule identifying information", - "type": "object", - "properties": { - "vendorName": { - "description": "network function vendor name", - "type": "string" - }, - "nfModuleName": { - "description": "name of the nfModule generating the event", - "type": "string" - }, - "nfName": { - "description": "name of the network function generating the event", - "type": "string" - } - }, - "additionalProperties": false, - "required": [ "vendorName" ] - }, - "voiceQualityFields": { - "description": "provides statistics related to customer facing voice products", - "type": "object", - "properties": { - "additionalInformation": { "$ref": "#/definitions/hashMap"}, - "calleeSideCodec": { - "description": "callee codec for the call", - "type": "string" - }, - "callerSideCodec": { - "description": "caller codec for the call", - "type": "string" - }, - "correlator": { - "description": "this is the same for all events on this call", - "type": "string" - }, - "endOfCallVqmSummaries": { - "$ref": "#/definitions/endOfCallVqmSummaries" - }, - "phoneNumber": { - "description": "phone number associated with the correlator", - "type": "string" - }, - "midCallRtcp": { - "description": "Base64 encoding of the binary RTCP data excluding Eth/IP/UDP headers", - "type": "string" - }, - "vendorNfNameFields": { - "$ref": "#/definitions/vendorNfNameFields" - }, - "voiceQualityFieldsVersion": { - "description": "version of the voiceQualityFields block", - "type": "string", - "enum": [ "4.0" ] - } - }, - "additionalProperties": false, - "required": [ "calleeSideCodec", "callerSideCodec", "correlator", "midCallRtcp", - "vendorNfNameFields", "voiceQualityFieldsVersion" ] - } - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/netconf/pnf-simulator.data.xml b/test/mocks/pnfsimulator/netconf/pnf-simulator.data.xml deleted file mode 100644 index 9d648bba7..000000000 --- a/test/mocks/pnfsimulator/netconf/pnf-simulator.data.xml +++ /dev/null @@ -1,4 +0,0 @@ -<config xmlns="http://nokia.com/pnf-simulator"> - <itemValue1>42</itemValue1> - <itemValue2>35</itemValue2> -</config> diff --git a/test/mocks/pnfsimulator/netconfsimulator/README.md b/test/mocks/pnfsimulator/netconfsimulator/README.md new file mode 100644 index 000000000..94bcd760f --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/README.md @@ -0,0 +1,276 @@ +# Netconf Simulator +A simulator that is able to receive and print history of CM configurations. + +## Required software +To run the simulator, the following software should be installed: +- JDK 1.8 +- Maven +- docker +- docker-compose + +### API +Simulator exposes both HTTP and native netconf interface. + +### Running simulator +In order to run simulator, invoke *mvn clean install docker:build* to build required images. +Add executable permission to initialize_netopeer.sh (by executing `sudo chmod +x netconf/initialize_netopeer.sh`) +and then invoke *docker-compose up* command. +In case of copying simulator files to another location, keep in mind to copy also *docker-compose.yml* and directories: *config, templates, netopeer-change-saver-native and netconf*. + +#### Restarting +Restarting simulator can be done by first typing *docker-compose restart* in terminal. + +#### Shutting down +The command *docker-compose down* can be used to shut the simulator down. + +## Usage of simulator + +### Netconf TLS support +Embedded netconf server supports connections over TLS on port 6513. Default server and CA certificate have been taken from Netopeer2 repository: https://github.com/CESNET/Netopeer2/tree/master/server/configuration/tls + +Mentioned Github repository contains sample client certificate, which works out of the box. +#### Replacing server certificates +In order to replace TLS certificates with third-party ones, the following naming schema must be followed: +* CA certificate file should be named 'ca.crt' +* Netconf server certificate file should be named 'server_cert.crt' +* Netconf server keyfile file should be named 'server_key.pem' + +Certificates and keys should follow PEM formatting guidelines. +Prepared files should be placed under _tls/_ directory (existing files must be overwritten). +After copying, it is necessary to restart the Netconf Simulator (please refer to [restarting simulator](restarting) guide). + +This is a sample curl command to test client connection (the example assumes that Netconf Simulator runs on 127.0.0.1): +``` +curl -k -v https://127.0.0.1:6513 --cacert ca.crt --key client.key --cert client.crt +``` + + +### Capturing netconf configuration changes + +The netconfsimulator tool will intercept changes in netconf configuration, done by edit-config command (invoked through simulator's edit-configuration endpoint or directly through exposed netconf-compliant interface). The following changes are intercepted: +- creating new item +- moving an item +- modifying an item +- deleting an item + +Each captured change contains fully qualified parameter name (including xpath - namespace and container name) + +#### REST API usage with examples + +Application of native netconf operations on YANG model is covered by REST API layer. +Example invocation of operations with its requests and results are presented below. +For basic edit-config and get config actions, response is in plain XML format, whereas stored data that can be accessed via API is returned in JSON format. + +**Load new YANG model** +http method: POST +``` +URL: http:<simulator_ip>:9000/netconf/model/<moduleName> +``` +request: file content to be sent as multipart (form data) +``` +module pnf-simulator { + namespace "http://onap.org/pnf-simulator"; + prefix config; + container config { + config true; + leaf itemValue1 {type uint32;} + leaf itemValue2 {type uint32;} + leaf itemValue3 {type uint32;} + leaf-list allow-user { + type string; + ordered-by user; + description "A sample list of user names."; + } + } +} +``` + +**Delete existing YANG model** +http method: DELETE +``` +URL: http:<simulator_ip>:9000/netconf/model/<moduleName> +``` +request body should be empty. +response: a HTTP 200 code indicating successful operation or 400/500 in case of errors. + +**Get all running configurations** +http method: GET +``` +URL: http:<simulator_ip>:9000/netconf/get +``` +response: plain XML +``` +<config xmlns="http://onap.org/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>2781</itemValue1> + <itemValue2>3782</itemValue2> + <itemValue3>3333</itemValue3> +</config> +<config2 xmlns="http://onap.org/pnf-simulator2" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>2781</itemValue1> + <itemValue2>3782</itemValue2> + <itemValue3>3333</itemValue3> +</config2> +``` + +**Get running configuration** +http method: GET +``` +URL: http:<simulator_ip>:9000/netconf/get/'moduleName'/'container' +``` +response: plain XML +``` +<config xmlns="http://onap.org/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>2781</itemValue1> + <itemValue2>3782</itemValue2> + <itemValue3>3333</itemValue3> +</config> +``` + +**Edit configuration** +To edit configuration XML file must be prepared. No plain request body is used here, +request content must be passed as multipart file (form data) with file name/key='editConfigXml' and file content in XML format + +http method: POST +``` +URL: http:<simulator_ip>:9000/netconf/edit-config +``` +request: file content to be sent as multipart (form data) +``` +<config xmlns="http://onap.org/pnf-simulator"> + <itemValue1>2781</itemValue1> + <itemValue2>3782</itemValue2> + <itemValue3>3333</itemValue3> +</config> +``` + +response: actual, running configuration after editing config: +``` +<config xmlns="http://onap.org/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>2781</itemValue1> + <itemValue2>3782</itemValue2> + <itemValue3>3333</itemValue3> +</config>" +``` + +Captured change, that can be obtained from db also via REST API: + +http method: GET +``` +URL: http://<simulator_ip>:9000/store/less?offset=1 +``` +response: +``` +[{"timestamp": 1542877413979, "configuration": "CREATED: /pnf-simulator:config/itemValue3 = 3333"}] +``` + +Notice: if new value is the same as the old one, the change won’t be intercepted (because there is no state change). This is a limitation of used netconf implementation (Netopeer2). + +**Modify request** +http method: POST +``` +URL: http:<simulator_ip>:9000/netconf/edit-config +``` +file content to be sent as multipart (form data): +``` +<config xmlns="http://onap.org/pnf-simulator" > + <itemValue1>111</itemValue1> + <itemValue2>222</itemValue2> +</config> +``` + +response: actual, running configuration after editing config: +``` +<config xmlns="http://onap.org/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>111</itemValue1> + <itemValue2>222</itemValue2> +</config>" +``` + +Captured change: +http method: GET +``` +URL: http://<simulator_ip>:9000/store/less?offset=2 +``` +``` +[{"timestamp": 1542877413979, "configuration": "MODIFIED: : old value: /pnf-simulator:config/itemValue1 = 2781, new value: /pnf-simulator:config/itemValue1 = 111", + {"timestamp": 1542877413979, "configuration": "MODIFIED: : old value: /pnf-simulator:config/itemValue2 = 3782, new value: /pnf-simulator:config/itemValue2 = 222"}] +``` + +**Move request** (inserting a value into leaf-list which in turn rearranges remaining elements) +http method: POST +``` +URL: http:<simulator_ip>:9000/netconf/edit-config +``` +file content to be sent as multipart (form data): +``` +<config xmlns="http://onap.org/pnf-simulator" xmlns:yang="urn:ietf:params:xml:ns:yang:1" xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <allow-user xc:operation="create" yang:insert="before" yang:value="bob">mike</allow-user> +</config> +``` + +Captured change: +http method: GET +``` +URL: http://<simulator_ip>:9000/store/less?offset=2 +``` +``` +[{"timestamp": 1542877413979, "configuration": "CREATED: /pnf-simulator:config/allow-user = mike"}, + {"timestamp": 1542877413979, "configuration": "MOVED: /pnf-simulator:config/allow-user = mike after /pnf-simulator:config/allow-user = alice"}] +``` + +**Delete request** +http method: POST +``` +URL: http:<simulator_ip>:9000/netconf/edit-config +``` +file content to be sent as multipart (form data): +``` +<config xmlns="http://onap.org/pnf-simulator"> + <itemValue1>1111</itemValue1> + <itemValue2 xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0" xc:operation="delete"/> +</config> +``` + +Captured change: +http method: GET +``` +URL: http://<simulator_ip>:9000/store/less?offset=1 +``` +``` +[{"timestamp": 1542877413979, "configuration": "DELETED: /pnf-simulator:config/itemValue2 = 222"}] +``` + +Getting all configuration changes: +http method: GET +``` +URL: http://<simulator_ip>:9000/store/cm-history +``` +response: +``` +[{"timestamp":1542877413979,"configuration":"MODIFIED: : old value: /pnf-simulator:config/itemValue1 = 2781, new value: /pnf-simulator:config/itemValue1 = 111"}, + {"timestamp":1542877413979,"configuration":"MODIFIED: : old value: /pnf-simulator:config/itemValue2 = 3782, new value: /pnf-simulator:config/itemValue2 = 222"}, + {"timestamp":1542877414000,"configuration":"CREATED: : /pnf-simulator:config/itemValue3 = 3333"}, + {"timestamp":1542877414104,"configuration":"CREATED: : CREATED: /pnf-simulator:config/allow-user = mike"} + {"timestamp":1542877414107,"configuration":"MOVED: /pnf-simulator:config/allow-user = mike after /pnf-simulator:config/allow-user = alice"}, + {"timestamp":1542877414275,"configuration":"DELETED: /pnf-simulator:config/itemValue2 = 222"}] +``` + +### Logging + +### Swagger + +## Developers Guide + +### Integration tests +Integration tests use docker-compose for setting up cluster with all services. +Those tests are not part of build pipeline, but can be run manually by invoking *mvn verify -DskipITs=false* from project command line. +Tests can be found in netconfsimulator project in src/integration directory. + +## Troubleshooting +Q: Simulator throws errors after shutting down with *docker-compose down* or *docker-compose restart* + +A: Remove docker containers that were left after stopping the simulator with the following commands: +``` +docker stop $(docker ps | grep netconfsimulator | awk '{print $1;}') +docker rm $(docker ps -a | grep netconfsimulator | awk '{print $1;}') +``` diff --git a/test/mocks/pnfsimulator/config/netconf.env b/test/mocks/pnfsimulator/netconfsimulator/config/netconf.env index 6cf310a27..6cf310a27 100644 --- a/test/mocks/pnfsimulator/config/netconf.env +++ b/test/mocks/pnfsimulator/netconfsimulator/config/netconf.env diff --git a/test/mocks/pnfsimulator/netconfsimulator/docker-compose.yml b/test/mocks/pnfsimulator/netconfsimulator/docker-compose.yml new file mode 100644 index 000000000..fd3339162 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/docker-compose.yml @@ -0,0 +1,96 @@ +version: '3' + +services: + zookeeper: + image: wurstmeister/zookeeper + ports: + - "2181:2181" + networks: + - netconfnetwork + + kafka1: + image: wurstmeister/kafka:1.1.0 + ports: + - "9092:9092" + hostname: kafka1 + networks: + - netconfnetwork + environment: + KAFKA_ADVERTISED_PORT: 9092 + KAFKA_ADVERTISED_HOST_NAME: kafka1 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + KAFKA_CREATE_TOPICS: "config:1:1" + KAFKA_DELETE_RETENTION_MS: 604800000 + KAFKA_LOG_CLEANER_DELETE_RETENTION_MS: 604800000 + depends_on: + - zookeeper + + netconf-simulator: + image: nexus3.onap.org:10003/onap/netconfsimulator:5.0.0-SNAPSHOT + ports: + - "9000:8080" + restart: on-failure + hostname: netconf-simulator + networks: + - netconfnetwork + depends_on: + - zookeeper + - kafka1 + - netopeer + + netopeer: + image: sysrepo/sysrepo-netopeer2:latest + ports: + - "830:830" + - "5002:5002" + - "6513:6513" + volumes: + - ./netconf:/netconf + - ./netopeer-change-saver-native:/netopeer-change-saver + - ./tls:/tls + env_file: + - ./config/netconf.env + restart: on-failure + networks: + - netconfnetwork + depends_on: + - sftp-server + - ftpes-server + environment: + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + command: + - /netconf/initialize_netopeer.sh + + sftp-server: + image: atmoz/sftp:alpine + ports: + - "2222:22" + volumes: + - ./sftp:/home/sftp-user/sftp + - ./ssh/ssh_host_rsa_key.pub:/home/sftp-user/.ssh/keys/ssh_host_rsa_key.pub + networks: + - netconfnetwork + restart: on-failure + command: sftp-user::1001 + + ftpes-server: + image: stilliard/pure-ftpd:latest + ports: + - "2221:21" + - "30000-30009:30000-30009" + volumes: + - ./ftpes/files:/home/ftpusers/onap + - ./ftpes/userpass/:/etc/pure-ftpd/passwd/ + - ./ftpes/tls/:/etc/ssl/private/ + networks: + - netconfnetwork + environment: + PUBLICHOST: localhost + ADDED_FLAGS: --tls=2 + FTP_USER_HOME: onap + restart: on-failure + +networks: + netconfnetwork: + driver: bridge diff --git a/test/mocks/pnfsimulator/netconfsimulator/docker/Dockerfile b/test/mocks/pnfsimulator/netconfsimulator/docker/Dockerfile new file mode 100644 index 000000000..0e25fd310 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/docker/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:8-jre-alpine +ADD libs /app/libs +ADD netconfsimulator-5.0.0-SNAPSHOT.jar /app/netconf-simulator.jar +CMD java -cp /app/libs/*:/app/netconf-simulator.jar org.onap.netconfsimulator.Main diff --git a/test/mocks/pnfsimulator/netconfsimulator/ftpes/files/ftpes-noone.txt b/test/mocks/pnfsimulator/netconfsimulator/ftpes/files/ftpes-noone.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/ftpes/files/ftpes-noone.txt diff --git a/test/mocks/pnfsimulator/netconfsimulator/ftpes/files/onap/ftpes-onap.txt b/test/mocks/pnfsimulator/netconfsimulator/ftpes/files/onap/ftpes-onap.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/ftpes/files/onap/ftpes-onap.txt diff --git a/test/mocks/pnfsimulator/ftpes/pure-ftpd/tls/pure-ftpd.pem b/test/mocks/pnfsimulator/netconfsimulator/ftpes/tls/pure-ftpd.pem index 0ce676efa..0ce676efa 100755 --- a/test/mocks/pnfsimulator/ftpes/pure-ftpd/tls/pure-ftpd.pem +++ b/test/mocks/pnfsimulator/netconfsimulator/ftpes/tls/pure-ftpd.pem diff --git a/test/mocks/pnfsimulator/ftpes/pure-ftpd/userpass/pureftpd.passwd b/test/mocks/pnfsimulator/netconfsimulator/ftpes/userpass/pureftpd.passwd index 7961e710d..7961e710d 100755 --- a/test/mocks/pnfsimulator/ftpes/pure-ftpd/userpass/pureftpd.passwd +++ b/test/mocks/pnfsimulator/netconfsimulator/ftpes/userpass/pureftpd.passwd diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/__init__.py b/test/mocks/pnfsimulator/netconfsimulator/netconf/__init__.py new file mode 100644 index 000000000..0f144c21e --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/__init__.py @@ -0,0 +1,19 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/initialize_netopeer.sh b/test/mocks/pnfsimulator/netconfsimulator/netconf/initialize_netopeer.sh new file mode 100755 index 000000000..71c1f215b --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/initialize_netopeer.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +cat > /etc/apt/apt.conf << EOF +Acquire::http { + No-Cache "true"; + No-Store "true"; + Pipeline-Depth "0"; +}; +EOF + +NETOPEER_CHANGE_SAVER=netopeer-change-saver + +cp /tls/* /usr/local/etc/keystored/keys/ +cp /netconf/*.xml /tmp/ + +chmod +x /netconf/set-up-xmls.py +/netconf/set-up-xmls.py /tls ca.crt server_cert.crt server_key.pem /tmp/load_server_certs.xml /tmp/tls_listen.xml + +/usr/bin/supervisord -c /etc/supervisord.conf & +sysrepoctl --install --yang=/netconf/pnf-simulator.yang --owner=netconf:nogroup --permissions=777 +sysrepocfg --import=/netconf/pnf-simulator.data.xml --datastore=startup --format=xml --level=3 pnf-simulator +sysrepocfg --merge=/tmp/load_server_certs.xml --format=xml --datastore=startup ietf-keystore +sysrepocfg --merge=/tmp/tls_listen.xml --format=xml --datastore=startup ietf-netconf-server + +apt-get update +apt-get install -y python3 python3-pip librdkafka-dev +pip3 install flask flask_restful +nohup python3 /netconf/yang_loader_server.py & + +/bin/cp -R /$NETOPEER_CHANGE_SAVER /opt/dev/ +ln -s /opt/dev/sysrepo/build/src/libsysrepo.so /$NETOPEER_CHANGE_SAVER/libsysrepo.so +cd /opt/dev/$NETOPEER_CHANGE_SAVER && cmake . +cd /opt/dev/$NETOPEER_CHANGE_SAVER && make +/opt/dev/$NETOPEER_CHANGE_SAVER/bin/netopeer-change-saver pnf-simulator kafka1 config diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/load_server_certs.xml b/test/mocks/pnfsimulator/netconfsimulator/netconf/load_server_certs.xml new file mode 100644 index 000000000..2524e08b0 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/load_server_certs.xml @@ -0,0 +1,40 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<keystore xmlns="urn:ietf:params:xml:ns:yang:ietf-keystore"> + <private-keys> + <private-key> + <name>SERVER_KEY_NAME</name> + <certificate-chains> + <certificate-chain> + <name>SERVER_CERT_NAME</name> + <certificate>SERVER_CERTIFICATE_HERE</certificate> + </certificate-chain> + </certificate-chains> + </private-key> + </private-keys> + <trusted-certificates> + <name>test_trusted_ca_list</name> + <trusted-certificate> + <name>CA_CERT_NAME</name> + <certificate>CA_CERTIFICATE_HERE</certificate> + </trusted-certificate> + </trusted-certificates> +</keystore> diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/newmodel.xml b/test/mocks/pnfsimulator/netconfsimulator/netconf/newmodel.xml new file mode 100644 index 000000000..90a3451d4 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/newmodel.xml @@ -0,0 +1,24 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<config2 xmlns="http://onap.org/pnf-simulator2"> + <item1>500</item1> + <item2>1000</item2> +</config2> diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/newmodel.yang b/test/mocks/pnfsimulator/netconfsimulator/netconf/newmodel.yang new file mode 100644 index 000000000..544f46725 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/newmodel.yang @@ -0,0 +1,9 @@ +module newmodel { + namespace "http://onap.org/pnf-simulator2"; + prefix config2; + container config2 { + config true; + leaf item1 {type uint32;} + leaf item2 {type uint32;} + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/pnf-simulator.data.xml b/test/mocks/pnfsimulator/netconfsimulator/netconf/pnf-simulator.data.xml new file mode 100644 index 000000000..c235f6405 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/pnf-simulator.data.xml @@ -0,0 +1,24 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<config xmlns="http://onap.org/pnf-simulator"> + <itemValue1>42</itemValue1> + <itemValue2>35</itemValue2> +</config> diff --git a/test/mocks/pnfsimulator/netconf/pnf-simulator.yang b/test/mocks/pnfsimulator/netconfsimulator/netconf/pnf-simulator.yang index d7fc2f26e..ba1158560 100644 --- a/test/mocks/pnfsimulator/netconf/pnf-simulator.yang +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/pnf-simulator.yang @@ -1,5 +1,5 @@ module pnf-simulator { - namespace "http://nokia.com/pnf-simulator"; + namespace "http://onap.org/pnf-simulator"; prefix config; container config { config true; diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/set-up-xmls.py b/test/mocks/pnfsimulator/netconfsimulator/netconf/set-up-xmls.py new file mode 100755 index 000000000..d46ff91f9 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/set-up-xmls.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python + +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +import os +import sys +import logging +import logging.config + +logging.basicConfig() +logger = logging.getLogger() +logger.setLevel(logging.INFO) + +# Placeholders definition - this needs to match placeholders in +# load_server_certs_xml_file and tls_listen_xml_file +SERVER_KEY_NAME = "SERVER_KEY_NAME" +SERVER_CERT_NAME = "SERVER_CERT_NAME" +SERVER_CERTIFICATE_HERE = "SERVER_CERTIFICATE_HERE" +CA_CERT_NAME = "CA_CERT_NAME" +CA_CERTIFICATE_HERE = "CA_CERTIFICATE_HERE" +CA_FINGERPRINT_HERE = "CA_FINGERPRINT_HERE" +CA_FINGERPRINT_ENV = "CA_FINGERPRINT" +SERVER_CERTIFICATE_ENV = "SERVER_CERTIFICATE_ENV" +CA_CERTIFICATE_ENV = "CA_CERTIFICATE_ENV" + + +class FileHelper(object): + @classmethod + def get_file_contents(cls, filename): + with open(filename, "r") as f: + return f.read() + + @classmethod + def write_file_contents(cls, filename, data): + with open(filename, "w+") as f: + f.write(data) + + +class CertHelper(object): + @classmethod + def get_pem_content_stripped(cls, pem_dir, pem_filename): + cmd = "cat {}/{} | grep -v '^-'".format(pem_dir, pem_filename) + content = CertHelper.system(cmd) + return content + + @classmethod + def get_cert_fingerprint(cls, directory, cert_filename): + cmd = "openssl x509 -fingerprint -noout -in {}/{} | sed -e " \ + "'s/SHA1 Fingerprint//; s/=//; s/=//p'" \ + .format(directory, cert_filename) + fingerprint = CertHelper.system(cmd) + return fingerprint + + @classmethod + def print_certs_info(cls, ca_cert, ca_fingerprint, server_cert): + logger.info("Will use server certificate: " + server_cert) + logger.info("Will use CA certificate: " + ca_cert) + logger.info("CA certificate fingerprint: " + ca_fingerprint) + + @classmethod + def system(cls, cmd): + return os.popen(cmd).read().replace("\n", "") + + +class App(object): + @classmethod + def patch_server_certs(cls, data, server_key_filename_noext, + server_cert_filename_noext, ca_cert_filename_noext, + server_cert, ca_cert): + data = data.replace(SERVER_KEY_NAME, server_key_filename_noext) + data = data.replace(SERVER_CERT_NAME, server_cert_filename_noext) + data = data.replace(CA_CERT_NAME, ca_cert_filename_noext) + data = data.replace(SERVER_CERTIFICATE_HERE, server_cert) + data = data.replace(CA_CERTIFICATE_HERE, ca_cert) + return data + + @classmethod + def patch_tls_listen(cls, data, server_cert_filename_noext, ca_fingerprint, + server_cert, ca_cert): + data = data.replace(SERVER_CERT_NAME, server_cert_filename_noext) + data = data.replace(CA_FINGERPRINT_HERE, ca_fingerprint) + data = data.replace(SERVER_CERTIFICATE_HERE, server_cert) + data = data.replace(CA_CERTIFICATE_HERE, ca_cert) + return data + + @classmethod + def run(cls): + # name things + cert_dir = sys.argv[1] + ca_cert_filename = sys.argv[2] + server_cert_filename = sys.argv[3] + server_key_filename = sys.argv[4] + load_server_certs_xml_file = sys.argv[5] + tls_listen_xml_file = sys.argv[6] + + # strip extensions + ca_cert_filename_noext = ca_cert_filename.replace(".crt", "") + server_cert_filename_noext = server_cert_filename.replace(".crt", "") + server_key_filename_noext = server_key_filename.replace(".pem", "") + + # get certificates from files + server_cert = CertHelper.get_pem_content_stripped(cert_dir, + server_cert_filename) + ca_cert = CertHelper.get_pem_content_stripped(cert_dir, + ca_cert_filename) + ca_fingerprint = CertHelper.get_cert_fingerprint(cert_dir, + ca_cert_filename) + CertHelper.print_certs_info(ca_cert, ca_fingerprint, server_cert) + + # patch TLS configuration files + data_srv = FileHelper.get_file_contents(load_server_certs_xml_file) + patched_srv = App.patch_server_certs(data_srv, server_key_filename_noext, + server_cert_filename_noext, + ca_cert_filename_noext, + server_cert, ca_cert) + FileHelper.write_file_contents(load_server_certs_xml_file, patched_srv) + + data_tls = FileHelper.get_file_contents(tls_listen_xml_file) + patched_tls = App.patch_tls_listen(data_tls, server_cert_filename_noext, + ca_fingerprint, server_cert, ca_cert) + FileHelper.write_file_contents(tls_listen_xml_file, patched_tls) + + +def main(): + if len(sys.argv) is not 7: + print("Usage: {1} <cert_dir> <ca_cert_filename> <server_cert_filename> " + "<server_key_filename> <load_server_certs_xml_full_path> " + "<tls_listen_full_path>", sys.argv[0]) + return 1 + App.run() + logger.info("XML files patched successfully") + + +if __name__ == '__main__': + main() diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/test_yang_loader_server.py b/test/mocks/pnfsimulator/netconfsimulator/netconf/test_yang_loader_server.py new file mode 100644 index 000000000..f282517b2 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/test_yang_loader_server.py @@ -0,0 +1,121 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +import unittest + +from unittest import mock +from werkzeug.datastructures import FileStorage + +from yang_loader_server import YangLoaderHelper, YangModelServer + + +class TestYangLoaderHelper(unittest.TestCase): + + def test_should_save_file_and_return_path(self): + helper = YangLoaderHelper() + mocked_file = mock.Mock(FileStorage) + mocked_file.filename = "sample" + + path = helper.save_file(mocked_file) + + self.assertEqual(path, "/tmp/sample") + mocked_file.save.assert_called_once_with("/tmp/sample") + + @mock.patch('yang_loader_server.check_output') + def test_should_install_new_yang_model(self, mocked_output): + helper = YangLoaderHelper() + + helper.install_new_model("path") + + mocked_output.assert_called_with( + ['sysrepoctl', '--install', '--yang=path', + '--owner=netconf:nogroup', '--permissions=777'], + stderr=-2, universal_newlines=True) + + @mock.patch('yang_loader_server.check_output') + def test_should_delete_yang_model(self, mocked_output): + helper = YangLoaderHelper() + + helper.uninstall_a_model("modelName") + + mocked_output.assert_called_with( + ['sysrepoctl', '--uninstall', '--module=modelName'], + stderr=-2, universal_newlines=True) + + @mock.patch('yang_loader_server.check_output') + def test_should_set_default_configuration(self, mocked_output): + helper = YangLoaderHelper() + + helper.set_default_configuration("samplePath", "sampleModuleName") + + mocked_output.assert_called_with( + ['sysrepocfg', '--import=samplePath', '--datastore=startup', + '--format=xml', '--level=3', 'sampleModuleName'], + stderr=-2, universal_newlines=True) + + @mock.patch('yang_loader_server.subprocess.Popen') + @mock.patch('yang_loader_server.check_output') + def test_should_verify_change_listener_for_model_properly(self, mocked_output, mocked_popen): + helper = YangLoaderHelper() + + helper.start_change_listener_for_model("sampleModule") + + mocked_output.assert_called_with( + ['pgrep', '-f', '/opt/dev/netopeer-change-saver/bin/netopeer-change-saver sampleModule kafka1 config'], + stderr=-2, universal_newlines=True) + + @mock.patch('yang_loader_server.check_output') + def test_should_raise_exception_when_error_occurred_in_output(self, + mocked_output): + helper = YangLoaderHelper() + mocked_output.return_value = "abcd ERR" + with self.assertRaises(RuntimeError) as context: + helper._run_bash_command("sample command") + + self.assertEqual('abcd ERR', str(context.exception)) + + +class TestYangModelServer(unittest.TestCase): + + def __init__(self, methodName='runTest'): + super().__init__(methodName) + self._mocked_file = mock.Mock(FileStorage) + + def test_should_properly_apply_and_start_new_model(self): + with mock.patch.object(YangModelServer, '_parse_request', + new=self._mock_request): + helper = mock.Mock(YangLoaderHelper) + helper.save_file.return_value = "sampleFile" + server = YangModelServer(helper) + + server.post() + + self.assertEqual(helper.save_file.call_count, 2) + helper.install_new_model.assert_called_once_with('sampleFile') + helper.set_default_configuration.assert_called_once_with( + 'sampleFile', 'sampleModuleName') + helper.start_change_listener_for_model.assert_called_once_with('sampleModuleName') + + def _mock_request(self): + return { + 'yangModel': self._mocked_file, + 'initialConfig': self._mocked_file, + 'moduleName': "sampleModuleName" + } diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/tls_listen.xml b/test/mocks/pnfsimulator/netconfsimulator/netconf/tls_listen.xml new file mode 100644 index 000000000..4f45b28a2 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/tls_listen.xml @@ -0,0 +1,48 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<netconf-server xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-server"> + <listen> + <endpoint> + <name>test_tls_listen_endpt</name> + <tls> + <address>0.0.0.0</address> + <port>6513</port> + <certificates> + <certificate> + <name>SERVER_CERT_NAME</name> + </certificate> + </certificates> + <client-auth> + <trusted-ca-certs>test_trusted_ca_list</trusted-ca-certs> + <cert-maps> + <cert-to-name> + <id>1</id> + <!-- This is not a typo - 0x02 should stay there --> + <fingerprint>02:CA_FINGERPRINT_HERE</fingerprint> + <map-type xmlns:x509c2n="urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name">x509c2n:specified</map-type> + <name>test</name> + </cert-to-name> + </cert-maps> + </client-auth> + </tls> + </endpoint> + </listen> +</netconf-server> diff --git a/test/mocks/pnfsimulator/netconfsimulator/netconf/yang_loader_server.py b/test/mocks/pnfsimulator/netconfsimulator/netconf/yang_loader_server.py new file mode 100644 index 000000000..716d0712e --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netconf/yang_loader_server.py @@ -0,0 +1,172 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +import logging +import subprocess +import os +from subprocess import check_output, CalledProcessError +from flask import Flask +from flask_restful import Resource, Api, reqparse +from werkzeug.datastructures import FileStorage +import time + +app = Flask(__name__) +api = Api(app) +logger = logging.getLogger("yang-loader") +logger.addHandler(logging.StreamHandler()) +KAFKA_BROKER_NAME="kafka1" +KAFKA_TOPIC_NAME="config" + + +class YangLoaderHelper(object): + + @classmethod + def save_file(cls, yang_model_file: FileStorage) -> str: + path = "/tmp/" + yang_model_file.filename + yang_model_file.save(path) + return path + + @classmethod + def install_new_model(cls, yang_model_path: str): + logger.info("Installing new model: %s", yang_model_path) + command = "sysrepoctl --install --yang={} --owner=netconf:nogroup --permissions=777" \ + .format(yang_model_path) + cls._run_bash_command(command) + + @classmethod + def uninstall_a_model(cls, yang_model_name: str): + logger.info("Uninstalling a model: %s", yang_model_name) + command = "sysrepoctl --uninstall --module={}" \ + .format(yang_model_name) + cls._run_bash_command(command) + + + @classmethod + def set_default_configuration(cls, init_conf_path: str, module_name: str): + logger.info("Attempting to set default configuration %s for module %s", init_conf_path, module_name) + command = "sysrepocfg --import={} --datastore=startup --format=xml --level=3 {}" \ + .format(init_conf_path, module_name) + cls._run_bash_command(command) + + @classmethod + def start_change_listener_for_model(cls, module_name: str): + logger.info("Starting listener for model: %s", module_name) + command = "/opt/dev/netopeer-change-saver/bin/netopeer-change-saver {} {} {}" \ + .format(module_name, KAFKA_BROKER_NAME, KAFKA_TOPIC_NAME) + try: + check_output(["pgrep", "-f" , command], stderr=subprocess.STDOUT, universal_newlines=True) + logger.info("Change listener for {} already exist.".format(module_name)) + except CalledProcessError: + subprocess.Popen(command.split(), stdout=subprocess.PIPE) + + @classmethod + def stop_change_listener_for_model(cls, model_name): + logger.info("Stopping listener for model %s", model_name) + pid = cls.get_pid_by_name(model_name) + logger.info("pid is %s", pid) + command = "kill -2 {}".format(pid) + cls._run_bash_command(command) + + @classmethod + def _run_bash_command(cls, command: str): + try: + logger.info("Attempts to invoke %s", command) + output = check_output(command.split(), stderr=subprocess.STDOUT, + universal_newlines=True) + logger.info("Output: %s", output) + if "ERR" in output: + raise RuntimeError(str(output)) + except subprocess.CalledProcessError as e: + raise RuntimeError(e, str(e.stdout)) + + @classmethod + def get_pid_by_name(cls, name): + for dirname in os.listdir('/proc'): + if not dirname.isdigit(): + continue + try: + with open('/proc/{}/cmdline'.format(dirname), mode='rb') as fd: + content = fd.read().decode().split('\x00') + except Exception as e: + print(e) + continue + + if name in content: + return dirname + + +class YangModelServer(Resource): + logger = logging.getLogger('YangModelServer') + + def __init__(self, yang_loader_helper: YangLoaderHelper = YangLoaderHelper()): + self._yang_loader_helper = yang_loader_helper + + def post(self): + args = self._parse_request() + yang_model_file = args['yangModel'] + initial_config_file = args['initialConfig'] + module_name = args['moduleName'] + model_path = self._yang_loader_helper.save_file(yang_model_file) + conf_path = self._yang_loader_helper.save_file(initial_config_file) + + try: + self._yang_loader_helper.install_new_model(model_path) + self._yang_loader_helper.set_default_configuration(conf_path, + module_name) + self._yang_loader_helper.start_change_listener_for_model(module_name) + except RuntimeError as e: + self.logger.error(e.args, exc_info=True) + return str(e.args), 400 + return "Successfully started" + + def delete(self): + args = self._parse_request() + yang_model_name = args['yangModelName'] + + try: + self._yang_loader_helper.stop_change_listener_for_model(yang_model_name) + time.sleep(5) + self._yang_loader_helper.uninstall_a_model(yang_model_name) + except RuntimeError as e: + self.logger.error(e.args, exc_info=True) + return str(e.args), 400 + return "Successfully deleted" + + @classmethod + def _parse_request(cls) -> reqparse.Namespace: + parse = reqparse.RequestParser() + parse.add_argument('yangModel', + type=FileStorage, + location='files') + parse.add_argument('initialConfig', + type=FileStorage, + location='files') + parse.add_argument('moduleName', type=str) + parse.add_argument('yangModelName', type=str) + return parse.parse_args() + + +api.add_resource(YangModelServer, '/model') + +if __name__ == '__main__': + logging.basicConfig(filename=os.path.dirname(__file__) + "/yang_loader.log", + filemode="w", + level=logging.DEBUG) + app.run(host='0.0.0.0', port='5002') diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/Application.cpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/Application.cpp new file mode 100644 index 000000000..56c33f0de --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/Application.cpp @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +#include "Application.h" +#include <cstdio> +#include <unistd.h> +#include "sysrepo/Session.hpp" +#include "SysrepoCallback.h" + +Application::~Application() { + this->subscriber->unsubscribe(); + this->session->session_stop(); + sr_disconnect(this->connection->_conn); + std::cout << "Application closed correctly " << std::endl; +} + +void Application::run() { + /*create kafka wrapper object*/ + auto kafkaWrapper = std::make_shared<KafkaWrapper>(this->brokers,this->topic_name); + + std::cout << "Application will watch for changes in " << module_name << std::endl; + /* connect to sysrepo */ + this->connection = new sysrepo::Connection("example_application"); + sysrepo::S_Connection conn(new sysrepo::Connection("example_application")); + + /* start session */ + sysrepo::S_Session sess(new sysrepo::Session(conn)); + + this->session = sess; + /* subscribe for changes in running config */ + sysrepo::S_Subscribe subscribe(new sysrepo::Subscribe(sess)); + std::shared_ptr<SysrepoCallback> cb(new SysrepoCallback(kafkaWrapper)); + + subscribe->module_change_subscribe(module_name, cb); + this->subscriber = subscribe; + + /* read startup config */ + std::cout << "\n ========== READING STARTUP CONFIG: ==========\n" << std::endl; + + cb->print_current_config(sess, module_name); + + std::cout << "\n ========== STARTUP CONFIG APPLIED AS RUNNING ==========\n" << std::endl; + + /* loop until ctrl-c is pressed / SIGINT is received */ + while (!exit_application) { + sleep(1000); /* or do some more useful work... */ + } + + std::cout << "Application exit requested, exiting." << std::endl; + +} + +Application::Application(const char *module_name, const char *brokers, const char *topic_name) { + this->module_name = module_name; + this->brokers = brokers; + this->topic_name = topic_name; +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/Application.h b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/Application.h new file mode 100644 index 000000000..c41f7e28b --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/Application.h @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +#ifndef NETOPEER_CHANGE_SAVER_CPP_APPLICATION_H +#define NETOPEER_CHANGE_SAVER_CPP_APPLICATION_H +#include "sysrepo/Sysrepo.hpp" + +extern volatile int exit_application; + +class Application { +private: + const char *module_name; + const char *brokers; + const char *topic_name; + sysrepo::S_Session session; + sysrepo::S_Subscribe subscriber; + sysrepo::Connection *connection; + +public: + Application(const char *module_name, const char *brokers, const char *topic_name); + ~Application(); + void run(); + +}; + +#endif //NETOPEER_CHANGE_SAVER_CPP_APPLICATION_H diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/CMakeLists.txt b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/CMakeLists.txt new file mode 100644 index 000000000..35a3a85ad --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.7) +project(netopeer-change-saver) + +set(CMAKE_CXX_STANDARD 11) +set(THREADS_PREFER_PTHREAD_FLAG ON) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set (CMAKE_EXE_LINKER_FLAGS "-Wl,--unresolved-symbols=ignore-all") +link_directories(.) + +find_package(Threads REQUIRED) + +add_executable(netopeer-change-saver main.cpp sysrepo.h Application.cpp Application.h KafkaWrapper.cpp KafkaWrapper.h + SysrepoCallback.cpp SysrepoCallback.h) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/libsysrepo-cpp.so + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/bin) + +target_link_libraries(netopeer-change-saver libsysrepo-cpp.so) +target_link_libraries(netopeer-change-saver libsysrepo.so) +target_link_libraries(netopeer-change-saver Threads::Threads) +target_link_libraries(netopeer-change-saver librdkafka.so)
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/KafkaWrapper.cpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/KafkaWrapper.cpp new file mode 100644 index 000000000..cd018a33f --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/KafkaWrapper.cpp @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +#include "KafkaWrapper.h" +#include <cstdlib> +#include <cinttypes> +#include <iostream> + +extern "C" { + rd_kafka_resp_err_t rd_kafka_last_error (void); + rd_kafka_resp_err_t rd_kafka_flush (rd_kafka_t *rk, int timeout_ms); +} + +extern "C" { +void kafka_delivery_report_callback(rd_kafka_t *rk, const rd_kafka_message_t *rkmessage, void *opaque) { +#ifdef DEBUG + if (rkmessage->err) + std::cout<<"%% Message delivery failed: %s\n"<<rd_kafka_err2str(rkmessage->err)<<std::endl; + else + std::cout<< + "%% Message delivered ("<<rkmessage->len <<" bytes, partition " << rkmessage->partition <<")" << std::endl; + /* The rkmessage is destroyed automatically by librdkafka */ +#endif +} +} + +KafkaWrapper::KafkaWrapper(const char *brokers, const char *topic_name) { + this->brokers = brokers; + this->topic_name = topic_name; + + init(); +} + +KafkaWrapper::~KafkaWrapper() { + std::cerr<<"%% Flushing final messages..."<<std::endl; + rd_kafka_flush(rk, 10 * 1000); + rd_kafka_destroy(rk); +} + +void KafkaWrapper::init() { + /*Kafka stuff*/ + conf = rd_kafka_conf_new(); + if (rd_kafka_conf_set(conf, "bootstrap.servers", brokers, errstr, sizeof(errstr)) != RD_KAFKA_CONF_OK) { + perror(errstr); + exit(1); + } + + rd_kafka_conf_set_dr_msg_cb(conf, kafka_delivery_report_callback); + rk = rd_kafka_new(RD_KAFKA_PRODUCER, conf, errstr, sizeof(errstr)); + if (!rk) { + std::cerr<<"%% Failed to create new producer: %s\n"<<errstr<<std::endl; + exit(1); + } + + rkt = rd_kafka_topic_new(rk, topic_name, nullptr); + if (!rkt) { + std::cerr<<"%% Failed to create topic object: %s\n"<< + rd_kafka_err2str(rd_kafka_last_error())<<std::endl; + rd_kafka_destroy(rk); + exit(1); + } +} + +void KafkaWrapper::kafka_send_message(std::string message) { + size_t len = message.length(); + int retry = 1; + while (retry) { +#ifdef DEBUG + std::cout<<"Sending the message to topic...\n"<<std::endl; +#endif + if (rd_kafka_produce(rkt, RD_KAFKA_PARTITION_UA, RD_KAFKA_MSG_F_COPY, (void *) message.c_str(), len, nullptr, 0, + nullptr)) { + retry = 1; + rd_kafka_resp_err_t last_error = rd_kafka_last_error(); + std::cerr<<"%% Failed to produce to topic %s: %s\n"<<topic_name<<rd_kafka_err2str(last_error)<<std::endl; + if (last_error == RD_KAFKA_RESP_ERR__QUEUE_FULL) { + rd_kafka_poll(rk, 1000); + } else { + std::cerr<<"%% Enqueued message (%zd bytes) for topic %s\n"<<len<<topic_name<<std::endl; + } + } else { + retry = 0; + } + } + rd_kafka_poll(rk, 0/*non-blocking*/); +} + + diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/KafkaWrapper.h b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/KafkaWrapper.h new file mode 100644 index 000000000..804afa758 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/KafkaWrapper.h @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +#ifndef NETOPEER_CHANGE_SAVER_CPP_KAFKAWRAPPER_H +#define NETOPEER_CHANGE_SAVER_CPP_KAFKAWRAPPER_H +#include "librdkafka/rdkafka.h" +#include <string> + +class KafkaWrapper { +private: + char errstr[512]; + const char *brokers; + const char *topic_name; + rd_kafka_t *rk; + rd_kafka_topic_t *rkt; + rd_kafka_conf_t *conf; + + void init(); + +public: + KafkaWrapper(const char *brokers, const char *topic_name); + ~KafkaWrapper(); + void kafka_send_message(std::string message); +}; + + +#endif //NETOPEER_CHANGE_SAVER_CPP_KAFKAWRAPPER_H diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/SysrepoCallback.cpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/SysrepoCallback.cpp new file mode 100644 index 000000000..225fe03a4 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/SysrepoCallback.cpp @@ -0,0 +1,108 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +#include "SysrepoCallback.h" +#define CREATED "CREATED" +#define DELETED "DELETED" +#define MODIFIED "MODIFIED" +#define MOVED "MOVED" +#define XPATH_MAX_LEN 100 + + +int SysrepoCallback::module_change(sysrepo::S_Session sess, const char *module_name, sr_notif_event_t event, void *private_ctx) { + { + if (event == SR_EV_APPLY) { + char change_path[XPATH_MAX_LEN]; + + try { +#ifdef DEBUG + std::cout << "\n ========== CHANGES: =============================================\n" << std::endl; +#endif + snprintf(change_path, XPATH_MAX_LEN, "/%s:*", module_name); + auto it = sess->get_changes_iter(&change_path[0]); + while (auto change = sess->get_change_next(it)) { + std::string message = create_message(change); + std::cout<<message<<std::endl; + kafkaWrapper->kafka_send_message(message); + } +#ifdef DEBUG + std::cout << "\n ========== END OF CHANGES =======================================\n" << std::endl; +#endif + } catch( const std::exception& e ) { + std::cerr << e.what() << std::endl; + } + } + return SR_ERR_OK; + } +} + +SysrepoCallback::SysrepoCallback(std::shared_ptr<KafkaWrapper> wrapper) { + this->kafkaWrapper = wrapper; +} + +std::string SysrepoCallback::create_message(sysrepo::S_Change change) { + std::string change_details; + sysrepo::S_Val new_val = change->new_val(); + sysrepo::S_Val old_val = change->old_val(); + + switch (change->oper()) { + case SR_OP_CREATED: + if (nullptr != new_val) { + change_details.append(CREATED).append(": ").append(new_val->to_string()); + } + break; + case SR_OP_DELETED: + if (nullptr != old_val) { + change_details.append(DELETED).append(": ").append(old_val->to_string()); + } + break; + case SR_OP_MODIFIED: + if (nullptr != old_val && nullptr != new_val) { + change_details.append(MODIFIED).append(": ").append(": old value: ").append(old_val->to_string()) + .append(", new value: ").append(new_val->to_string()); + } + break; + case SR_OP_MOVED: + if (nullptr != old_val && nullptr != new_val) { + change_details.append(MOVED).append(": ").append(new_val->to_string()) + .append(" after ").append(old_val->to_string()); + } else if (nullptr != new_val) { + change_details.append(MOVED).append(": ").append(new_val->xpath()).append(" last"); + } + break; + } + return change_details; +} + +void SysrepoCallback::print_current_config(sysrepo::S_Session session, const char *module_name) { + char select_xpath[XPATH_MAX_LEN]; + try { + snprintf(select_xpath, XPATH_MAX_LEN, "/%s:*//*", module_name); + + auto values = session->get_items(&select_xpath[0]); + if (values == nullptr) + return; + + for(unsigned int i = 0; i < values->val_cnt(); i++) + std::cout << values->val(i)->to_string(); + } catch( const std::exception& e ) { + std::cout << e.what() << std::endl; + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/SysrepoCallback.h b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/SysrepoCallback.h new file mode 100644 index 000000000..7d2cd7221 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/SysrepoCallback.h @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +#ifndef NETOPEER_CHANGE_SAVER_CPP_SYSREPOCALLBACK_H +#define NETOPEER_CHANGE_SAVER_CPP_SYSREPOCALLBACK_H +#include "KafkaWrapper.h" +#include "sysrepo/Session.hpp" +#include <memory> + +class SysrepoCallback: public sysrepo::Callback { +private: + std::shared_ptr<KafkaWrapper> kafkaWrapper; + +public: + explicit SysrepoCallback(std::shared_ptr<KafkaWrapper> wrapper); + void print_current_config(sysrepo::S_Session session, const char *module_name); + +private: + std::string create_message(sysrepo::S_Change change); + int module_change(sysrepo::S_Session sess, const char *module_name, sr_notif_event_t event, void *private_ctx); + +}; + + +#endif //NETOPEER_CHANGE_SAVER_CPP_SYSREPOCALLBACK_H diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/libsysrepo-cpp.so b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/libsysrepo-cpp.so Binary files differnew file mode 100755 index 000000000..efdcc135d --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/libsysrepo-cpp.so diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/main.cpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/main.cpp new file mode 100644 index 000000000..0329f0552 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/main.cpp @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +#include <iostream> +#include <csignal> +#include "Application.h" + +volatile int exit_application = 0; + +void sigint_handler(int signum) { + std::cout << "Interrupt signal (" << signum << ") received." << std::endl; + exit_application = 1; +} + +int main(int argc, char *argv[]) { + if (argc != 4) { + std::cerr<<"Usage: "<<argv[0]<<" <module_name> <broker> <topic> "<<std::endl; + return 1; + } + + signal(SIGINT, sigint_handler); + + const char *module_name = argv[1]; + const char *brokers = argv[2]; + const char *topic_name = argv[3]; + + Application application(module_name, brokers, topic_name); + application.run(); + + return 0; +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo.h b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo.h new file mode 100644 index 000000000..9d541d1c0 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo.h @@ -0,0 +1,2015 @@ +/** + * @file sysrepo.h + * @author Rastislav Szabo <raszabo@cisco.com>, Lukas Macko <lmacko@cisco.com> + * @brief Sysrepo Client Library public API. + * + * @copyright + * Copyright 2015 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSREPO_H_ +#define SYSREPO_H_ + +/** + * @defgroup cl Client Library + * @{ + * + * @brief Provides the public API towards applications using sysrepo to store + * their configuration data, or towards management agents. + * + * Communicates with Sysrepo Engine (@ref cm), which is running either inside + * of dedicated sysrepo daemon, or within this library if daemon is not alive. + * + * Access to the sysrepo datastore is connection- and session- oriented. Before + * calling any data access/manipulation API, one needs to connect to the datastore + * via ::sr_connect and open a session via ::sr_session_start. One connection + * can serve multiple sessions. + * + * Each data access/manipulation request call is blocking - blocks the connection + * until the response from Sysrepo Engine comes, or until an error occurs. It is + * safe to call multiple requests on the same session (or different session that + * belongs to the same connection) from multiple threads at the same time, + * however it is not effective, since each call is blocked until previous one + * finishes. If you need fast multi-threaded access to sysrepo, use a dedicated + * connection for each thread. + * + * @see + * See @ref main_page "Sysrepo Introduction" for details about sysrepo architecture. + * @see + * @ref xp_page "XPath Addressing" is used for node identification in data-related calls. + */ + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <time.h> +#ifdef __APPLE__ + #include <sys/types.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Common typedefs and API +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Sysrepo connection context used to identify a connection to sysrepo datastore. + */ +typedef struct sr_conn_ctx_s sr_conn_ctx_t; + +/** + * @brief Sysrepo session context used to identify a configuration session. + */ +typedef struct sr_session_ctx_s sr_session_ctx_t; + +/** + * @brief Memory context used for efficient memory management for values, trees and GPB messages. + */ +typedef struct sr_mem_ctx_s sr_mem_ctx_t; + +/** + * @brief Possible types of an data element stored in the sysrepo datastore. + */ +typedef enum sr_type_e { + /* special types that does not contain any data */ + SR_UNKNOWN_T, /**< Element unknown to sysrepo (unsupported element). */ + SR_TREE_ITERATOR_T, /**< Special type of tree node used to store all data needed for iterative tree loading. */ + + SR_LIST_T, /**< List instance. ([RFC 6020 sec 7.8](http://tools.ietf.org/html/rfc6020#section-7.8)) */ + SR_CONTAINER_T, /**< Non-presence container. ([RFC 6020 sec 7.5](http://tools.ietf.org/html/rfc6020#section-7.5)) */ + SR_CONTAINER_PRESENCE_T, /**< Presence container. ([RFC 6020 sec 7.5.1](http://tools.ietf.org/html/rfc6020#section-7.5.1)) */ + SR_LEAF_EMPTY_T, /**< A leaf that does not hold any value ([RFC 6020 sec 9.11](http://tools.ietf.org/html/rfc6020#section-9.11)) */ + SR_NOTIFICATION_T, /**< Notification instance ([RFC 7095 sec 7.16](https://tools.ietf.org/html/rfc7950#section-7.16)) */ + + /* types containing some data */ + SR_BINARY_T, /**< Base64-encoded binary data ([RFC 6020 sec 9.8](http://tools.ietf.org/html/rfc6020#section-9.8)) */ + SR_BITS_T, /**< A set of bits or flags ([RFC 6020 sec 9.7](http://tools.ietf.org/html/rfc6020#section-9.7)) */ + SR_BOOL_T, /**< A boolean value ([RFC 6020 sec 9.5](http://tools.ietf.org/html/rfc6020#section-9.5)) */ + SR_DECIMAL64_T, /**< 64-bit signed decimal number ([RFC 6020 sec 9.3](http://tools.ietf.org/html/rfc6020#section-9.3)) */ + SR_ENUM_T, /**< A string from enumerated strings list ([RFC 6020 sec 9.6](http://tools.ietf.org/html/rfc6020#section-9.6)) */ + SR_IDENTITYREF_T, /**< A reference to an abstract identity ([RFC 6020 sec 9.10](http://tools.ietf.org/html/rfc6020#section-9.10)) */ + SR_INSTANCEID_T, /**< References a data tree node ([RFC 6020 sec 9.13](http://tools.ietf.org/html/rfc6020#section-9.13)) */ + SR_INT8_T, /**< 8-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + SR_INT16_T, /**< 16-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + SR_INT32_T, /**< 32-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + SR_INT64_T, /**< 64-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + SR_STRING_T, /**< Human-readable string ([RFC 6020 sec 9.4](http://tools.ietf.org/html/rfc6020#section-9.4)) */ + SR_UINT8_T, /**< 8-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + SR_UINT16_T, /**< 16-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + SR_UINT32_T, /**< 32-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + SR_UINT64_T, /**< 64-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + SR_ANYXML_T, /**< Unknown chunk of XML ([RFC 6020 sec 7.10](https://tools.ietf.org/html/rfc6020#section-7.10)) */ + SR_ANYDATA_T, /**< Unknown set of nodes, encoded in XML ([RFC 7950 sec 7.10](https://tools.ietf.org/html/rfc7950#section-7.10)) */ +} sr_type_t; + +/** + * @brief Data of an element (if applicable), properly set according to the type. + */ +typedef union sr_data_u { + char *binary_val; /**< Base64-encoded binary data ([RFC 6020 sec 9.8](http://tools.ietf.org/html/rfc6020#section-9.8)) */ + char *bits_val; /**< A set of bits or flags ([RFC 6020 sec 9.7](http://tools.ietf.org/html/rfc6020#section-9.7)) */ + bool bool_val; /**< A boolean value ([RFC 6020 sec 9.5](http://tools.ietf.org/html/rfc6020#section-9.5)) */ + double decimal64_val; /**< 64-bit signed decimal number ([RFC 6020 sec 9.3](http://tools.ietf.org/html/rfc6020#section-9.3)) */ + char *enum_val; /**< A string from enumerated strings list ([RFC 6020 sec 9.6](http://tools.ietf.org/html/rfc6020#section-9.6)) */ + char *identityref_val; /**< A reference to an abstract identity ([RFC 6020 sec 9.10](http://tools.ietf.org/html/rfc6020#section-9.10)) */ + char *instanceid_val; /**< References a data tree node ([RFC 6020 sec 9.13](http://tools.ietf.org/html/rfc6020#section-9.13)) */ + int8_t int8_val; /**< 8-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + int16_t int16_val; /**< 16-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + int32_t int32_val; /**< 32-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + int64_t int64_val; /**< 64-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + char *string_val; /**< Human-readable string ([RFC 6020 sec 9.4](http://tools.ietf.org/html/rfc6020#section-9.4)) */ + uint8_t uint8_val; /**< 8-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + uint16_t uint16_val; /**< 16-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + uint32_t uint32_val; /**< 32-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + uint64_t uint64_val; /**< 64-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */ + char *anyxml_val; /**< Unknown chunk of XML ([RFC 6020 sec 7.10](https://tools.ietf.org/html/rfc6020#section-7.10)) */ + char *anydata_val; /**< Unknown set of nodes, encoded in XML ([RFC 7950 sec 7.10](https://tools.ietf.org/html/rfc7950#section-7.10)) */ +} sr_data_t; + +/** + * @brief Structure that contains value of an data element stored in the sysrepo datastore. + */ +typedef struct sr_val_s { + /** + * Memory context used internally by Sysrepo for efficient storage + * and conversion of this structure. + */ + sr_mem_ctx_t *_sr_mem; + + /** + * XPath identifier of the data element, as defined in + * @ref xp_page "Path Addressing" documentation + */ + char *xpath; + + /** Type of an element. */ + sr_type_t type; + + /** + * Flag for node with default value (applicable only for leaves). + * It is set to TRUE only if the value was *implicitly* set by the datastore as per + * module schema. Explicitly set/modified data element (through the sysrepo API) always + * has this flag unset regardless of the entered value. + */ + bool dflt; + + /** Data of an element (if applicable), properly set according to the type. */ + sr_data_t data; + +} sr_val_t; + +/** + * @brief A data element stored in the sysrepo datastore represented as a tree node. + * + * @note Can be safely casted to ::sr_val_t, only *xpath* member will point to node name rather + * than to an actual xpath. + */ +typedef struct sr_node_s { + /** + * Memory context used internally by Sysrepo for efficient storage + * and conversion of this structure. + */ + sr_mem_ctx_t *_sr_mem; + + /** Name of the node. */ + char *name; + + /** Type of an element. */ + sr_type_t type; + + /** Flag for default node (applicable only for leaves). */ + bool dflt; + + /** Data of an element (if applicable), properly set according to the type. */ + sr_data_t data; + + /** + * Name of the module that defines scheme of this node. + * NULL if it is the same as that of the predecessor. + */ + char *module_name; + + /** Pointer to the parent node (NULL in case of root node). */ + struct sr_node_s *parent; + + /** Pointer to the next sibling node (NULL if there is no one). */ + struct sr_node_s *next; + + /** Pointer to the previous sibling node (NULL if there is no one). */ + struct sr_node_s *prev; + + /** Pointer to the first child node (NULL if this is a leaf). */ + struct sr_node_s *first_child; + + /** Pointer to the last child node (NULL if this is a leaf). */ + struct sr_node_s *last_child; +} sr_node_t; + +/** + * @brief Sysrepo error codes. + */ +typedef enum sr_error_e { + SR_ERR_OK = 0, /**< No error. */ + SR_ERR_INVAL_ARG, /**< Invalid argument. */ + SR_ERR_NOMEM, /**< Not enough memory. */ + SR_ERR_NOT_FOUND, /**< Item not found. */ + SR_ERR_INTERNAL, /**< Other internal error. */ + SR_ERR_INIT_FAILED, /**< Sysrepo infra initialization failed. */ + SR_ERR_IO, /**< Input/Output error. */ + SR_ERR_DISCONNECT, /**< The peer disconnected. */ + SR_ERR_MALFORMED_MSG, /**< Malformed message. */ + SR_ERR_UNSUPPORTED, /**< Unsupported operation requested. */ + SR_ERR_UNKNOWN_MODEL, /**< Request includes unknown schema */ + SR_ERR_BAD_ELEMENT, /**< Unknown element in existing schema */ + SR_ERR_VALIDATION_FAILED, /**< Validation of the changes failed. */ + SR_ERR_OPERATION_FAILED, /**< An operation failed. */ + SR_ERR_DATA_EXISTS, /**< Item already exists. */ + SR_ERR_DATA_MISSING, /**< Item does not exists. */ + SR_ERR_UNAUTHORIZED, /**< Operation not authorized. */ + SR_ERR_INVAL_USER, /**< Invalid username. */ + SR_ERR_LOCKED, /**< Requested resource is already locked. */ + SR_ERR_TIME_OUT, /**< Time out has expired. */ + SR_ERR_RESTART_NEEDED, /**< Sysrepo Engine restart is needed. */ + SR_ERR_VERSION_MISMATCH, /**< Incompatible client library used to communicate with sysrepo. */ +} sr_error_t; + +/** + * @brief Detailed sysrepo error information. + */ +typedef struct sr_error_info_s { + const char *message; /**< Error message. */ + const char *xpath; /**< XPath to the node where the error has been discovered. */ +} sr_error_info_t; + +/** + * @brief Returns the error message corresponding to the error code. + * + * @param[in] err_code Error code. + * + * @return Error message (statically allocated, do not free). + */ +const char *sr_strerror(int err_code); + +/** + * @brief Log levels used to determine if message of certain severity should be printed. + */ +typedef enum { + SR_LL_NONE, /**< Do not print any messages. */ + SR_LL_ERR, /**< Print only error messages. */ + SR_LL_WRN, /**< Print error and warning messages. */ + SR_LL_INF, /**< Besides errors and warnings, print some other informational messages. */ + SR_LL_DBG, /**< Print all messages including some development debug messages. */ +} sr_log_level_t; + +/** + * @brief Enables / disables / changes log level (verbosity) of logging to + * standard error output. + * + * By default, logging to stderr is disabled. Setting log level to any value + * other than SR_LL_NONE enables the logging to stderr. Setting log level + * back to SR_LL_NONE disables the logging to stderr. + * + * @param[in] log_level requested log level (verbosity). + */ +void sr_log_stderr(sr_log_level_t log_level); + +/** + * @brief Enables / disables / changes log level (verbosity) of logging to system log. + * + * By default, logging into syslog is disabled. Setting log level to any value + * other than SR_LL_NONE enables the logging into syslog. Setting log level + * back to SR_LL_NONE disables the logging into syslog. + * + * @note Please note that enabling logging into syslog will overwrite your syslog + * connection settings (calls openlog), if you are connected to syslog already. + * + * @param[in] log_level requested log level (verbosity). + */ +void sr_log_syslog(sr_log_level_t log_level); + +/** + * @brief Sets callback that will be called when a log entry would be populated. + * + * @param[in] level Verbosity level of the log entry. + * @param[in] message Message of the log entry. + */ +typedef void (*sr_log_cb)(sr_log_level_t level, const char *message); + +/** + * @brief Sets callback that will be called when a log entry would be populated. + * Callback will be called for each message with any log level. + * + * @param[in] log_callback Callback to be called when a log entry would populated. + */ +void sr_log_set_cb(sr_log_cb log_callback); + + +//////////////////////////////////////////////////////////////////////////////// +// Connection / Session Management +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Flags used to override default connection handling by ::sr_connect call. + */ +typedef enum sr_conn_flag_e { + SR_CONN_DEFAULT = 0, /**< Default behavior - instantiate library-local Sysrepo Engine if + the connection to sysrepo daemon is not possible. */ + SR_CONN_DAEMON_REQUIRED = 1, /**< Require daemon connection - do not instantiate library-local Sysrepo Engine + if the library cannot connect to the sysrepo daemon (and return an error instead). */ + SR_CONN_DAEMON_START = 2, /**< If sysrepo daemon is not running, and SR_CONN_DAEMON_REQUIRED was specified, + start it (only if the process calling ::sr_connect is running under root privileges). */ +} sr_conn_flag_t; + +/** + * @brief Options overriding default connection handling by ::sr_connect call, + * it is supposed to be bitwise OR-ed value of any ::sr_conn_flag_t flags. + */ +typedef uint32_t sr_conn_options_t; + +/** + * @brief Flags used to override default session handling (used by ::sr_session_start + * and ::sr_session_start_user calls). + */ +typedef enum sr_session_flag_e { + SR_SESS_DEFAULT = 0, /**< Default (normal) session behavior. */ + SR_SESS_CONFIG_ONLY = 1, /**< Session will process only configuration data (e.g. sysrepo won't + return any state data by ::sr_get_items / ::sr_get_items_iter calls). */ + SR_SESS_ENABLE_NACM = 2, /**< Enable NETCONF access control for this session (disabled by default). */ + + SR_SESS_MUTABLE_OPTS = 3 /**< Bit-mask of options that can be set by the user + (immutable flags are defined in sysrepo.proto file). */ +} sr_session_flag_t; + +/** + * @brief Options overriding default connection session handling, + * it is supposed to be bitwise OR-ed value of any ::sr_session_flag_t flags. + */ +typedef uint32_t sr_sess_options_t; + +/** + * @brief Data stores that sysrepo supports. Both are editable via implicit candidate. + * To make changes permanent in edited datastore ::sr_commit must be issued. + * @see @ref ds_page "Datastores & Sessions" information page. + */ +typedef enum sr_datastore_e { + SR_DS_STARTUP = 0, /**< Contains configuration data that should be loaded by the controlled application when it starts. */ + SR_DS_RUNNING = 1, /**< Contains currently applied configuration and state data of a running application. + @note This datastore is supported only by applications that subscribe for notifications + about the changes made in the datastore (e.g. ::sr_module_change_subscribe). */ + SR_DS_CANDIDATE = 2, /**< Contains configuration that can be manipulated without impacting the current configuration. + Its content is set to the content of running datastore by default. Changes made within + the candidate can be later committed to the running datastore or copied to any datastore. + + @note The main difference between working with running and candidate datastore is in commit + operation - commit of candidate session causes the content of running configuration to be set + the value of the candidate configuration (running datastore is overwritten), whereas commit of + runnnig session merges the changes made within the session with the actual state of running. */ +} sr_datastore_t; + +/** + * @brief Connects to the sysrepo datastore (Sysrepo Engine). + * + * @note If the client library loses connection to the Sysrepo Engine during + * the lifetime of the application, all Sysrepo API calls will start returning + * ::SR_ERR_DISCONNECT error on active sessions. In this case, the application is supposed to reconnect + * with another ::sr_connect call and restart all lost sessions. + * + * @param[in] app_name Name of the application connecting to the datastore + * (can be a static string). Used only for accounting purposes. + * @param[in] opts Options overriding default connection handling by this call. + * @param[out] conn_ctx Connection context that can be used for subsequent API calls + * (automatically allocated, it is supposed to be released by the caller using ::sr_disconnect). + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_connect(const char *app_name, const sr_conn_options_t opts, sr_conn_ctx_t **conn_ctx); + +/** + * @brief Disconnects from the sysrepo datastore (Sysrepo Engine). + * + * Cleans up and frees connection context allocated by ::sr_connect. All sessions + * started within the connection will be automatically stopped and cleaned up too. + * + * @param[in] conn_ctx Connection context acquired with ::sr_connect call. + */ +void sr_disconnect(sr_conn_ctx_t *conn_ctx); + +/** + * @brief Starts a new configuration session. + * + * @see @ref ds_page "Datastores & Sessions" for more information about datastores and sessions. + * + * @param[in] conn_ctx Connection context acquired with ::sr_connect call. + * @param[in] datastore Datastore on which all sysrepo functions within this + * session will operate. Later on, datastore can be later changed using + * ::sr_session_switch_ds call. Functionality of some sysrepo calls does not depend on + * datastore. If your session will contain just calls like these, you can pass + * any valid value (e.g. SR_RUNNING). + * @param[in] opts Options overriding default session handling. + * @param[out] session Session context that can be used for subsequent API + * calls (automatically allocated, can be released by calling ::sr_session_stop). + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_session_start(sr_conn_ctx_t *conn_ctx, const sr_datastore_t datastore, + const sr_sess_options_t opts, sr_session_ctx_t **session); + +/** + * @brief Starts a new configuration session on behalf of a different user. + * + * This call is intended for northbound access to sysrepo from management + * applications, that need sysrepo to authorize the operations not only + * against the user under which the management application is running, but + * also against another user (e.g. user that connected to the management application). + * + * @note Be aware that authorization of specified user may fail with unexpected + * errors in case that the client library uses its own Sysrepo Engine at the + * moment and your process in not running under root privileges. To prevent + * this situation, consider specifying SR_CONN_DAEMON_REQUIRED flag by + * ::sr_connect call or using ::sr_session_start instead of this function. + * + * @see @ref ds_page "Datastores & Sessions" for more information about datastores and sessions. + * + * @param[in] conn_ctx Connection context acquired with ::sr_connect call. + * @param[in] user_name Effective user name used to authorize the access to + * datastore (in addition to automatically-detected real user name). + * @param[in] datastore Datastore on which all sysrepo functions within this + * session will operate. Functionality of some sysrepo calls does not depend on + * datastore. If your session will contain just calls like these, you can pass + * any valid value (e.g. SR_RUNNING). + * @param[in] opts Options overriding default session handling. + * @param[out] session Session context that can be used for subsequent API calls + * (automatically allocated, it is supposed to be released by caller using ::sr_session_stop). + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_session_start_user(sr_conn_ctx_t *conn_ctx, const char *user_name, const sr_datastore_t datastore, + const sr_sess_options_t opts, sr_session_ctx_t **session); + +/** + * @brief Stops current session and releases resources tied to the session. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_session_stop(sr_session_ctx_t *session); + +/** + * @brief Refreshes configuration data cached within the session and starts + * operating on fresh data loaded from the datastore. + * + * Call this function in case that you leave session open for longer time period + * and you expect that the data in the datastore may have been changed since + * last data (re)load (which occurs by ::sr_session_start, ::sr_commit and + * ::sr_discard_changes). + * + * @see @ref ds_page "Datastores & Sessions" for information about session data caching. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_session_refresh(sr_session_ctx_t *session); + +/** + * @brief Checks aliveness and validity of the session & connection tied to it. + * + * If the connection to the Sysrepo Engine has been lost in the meantime, returns SR_ERR_DICONNECT. + * In this case, the application is supposed to stop the session (::sr_session_stop), disconnect (::sr_disconnect) + * and then reconnect (::sr_connect) and start a new session (::sr_session_start). + * + * @note If the client library loses connection to the Sysrepo Engine during the lifetime of the application, + * all Sysrepo API calls will start returning SR_ERR_DISCONNECT error on active sessions. This is the primary + * mechanism that can be used to detect connection issues, ::sr_session_check is just an addition to it. Since + * ::sr_session_check sends a message to the Sysrepo Engine and waits for the response, it costs some extra overhead + * in contrast to catching SR_ERR_DISCONNECT error. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * + * @return Error code (SR_ERR_OK in case that the session is healthy, + * SR_ERR_DICONNECT in case that connection to the Sysrepo Engine has been lost). + */ +int sr_session_check(sr_session_ctx_t *session); + +/** + * @brief Changes datastore to which the session is tied to. All subsequent + * calls will be issued on the chosen datastore. + * + * @param [in] session + * @param [in] ds + * @return Error code (SR_ERR_OK on success) + */ +int sr_session_switch_ds(sr_session_ctx_t *session, sr_datastore_t ds); + +/** + * @brief Alter the session options. E.g.: set/unset SR_SESS_CONFIG_ONLY flag. + * + * @param [in] session + * @param [in] opts - new value for session options + * @return Error code (SR_ERR_OK on success) + */ +int sr_session_set_options(sr_session_ctx_t *session, const sr_sess_options_t opts); + +/** + * @brief Retrieves detailed information about the error that has occurred + * during the last operation executed within provided session. + * + * If multiple errors has occurred within the last operation, only the first + * one is returned. This call is sufficient for all data retrieval and data + * manipulation functions that operate on single-item basis. For operations + * such as ::sr_validate or ::sr_commit where multiple errors can occur, + * use ::sr_get_last_errors instead. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[out] error_info Detailed error information. Be aware that + * returned pointer may change by the next API call executed within the provided + * session, so it's not safe to use this function by concurrent access to the + * same session within multiple threads. Do not free or modify returned values. + * + * @return Error code of the last operation executed within provided session. + */ +int sr_get_last_error(sr_session_ctx_t *session, const sr_error_info_t **error_info); + +/** + * @brief Retrieves detailed information about all errors that have occurred + * during the last operation executed within provided session. + * + * Use this call instead of ::sr_get_last_error by operations where multiple + * errors can occur, such as ::sr_validate or ::sr_commit. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[out] error_info Array of detailed error information. Be aware that + * returned pointer may change by the next API call executed within the provided + * session, so it's not safe to use this function by concurrent access to the + * same session within multiple threads. Do not free or modify returned values. + * @param[out] error_cnt Number of errors returned in the error_info array. + * + * @return Error code of the last operation executed within provided session. + */ +int sr_get_last_errors(sr_session_ctx_t *session, const sr_error_info_t **error_info, size_t *error_cnt); + +/** + * @brief Sets detailed error information into provided session. Used to notify + * the client library about errors that occurred in application code. + * + * @note Intended for commit verifiers (notification session) - the call has no + * impact on any other sessions. + * + * @param[in] session Session context passed into notification callback. + * @param[in] message Human-readable error message. + * @param[in] xpath XPath to the node where the error has occurred. NULL value + * is also accepted. + * + * @return Error code (SR_ERR_OK on success) + */ +int sr_set_error(sr_session_ctx_t *session, const char *message, const char *xpath); + +/** + * @brief Returns the assigned id of the session. Can be used to pair the session with + * netconf-config-change notification initiator. + * @param [in] session + * @return session id or 0 in case of error + */ +uint32_t sr_session_get_id(sr_session_ctx_t *session); + +//////////////////////////////////////////////////////////////////////////////// +// Data Retrieval API (get / get-config functionality) +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Structure that contains information about one particular schema file installed in sysrepo. + */ +typedef struct sr_sch_revision_s { + const char *revision; /**< Revision of the module/submodule. */ + const char *file_path_yang; /**< Absolute path to file where the module/submodule is stored (YANG format). */ + const char *file_path_yin; /**< Absolute path to file where the module/submodule is stored (.yin format). */ +} sr_sch_revision_t; + +/** + * @brief Structure that contains information about submodules of a module installed in sysrepo. + */ +typedef struct sr_sch_submodule_s { + const char *submodule_name; /**< Submodule name. */ + sr_sch_revision_t revision; /**< Revision of the submodule. */ +} sr_sch_submodule_t; + +/** + * @brief Structure that contains information about a module installed in sysrepo. + */ +typedef struct sr_schema_s { + /** + * Memory context used internally by Sysrepo for efficient storage + * and conversion of this structure. + */ + sr_mem_ctx_t *_sr_mem; + + const char *module_name; /**< Name of the module. */ + const char *ns; /**< Namespace of the module used in @ref xp_page "XPath". */ + const char *prefix; /**< Prefix of the module. */ + bool installed; /**< TRUE if the module was explicitly installed. */ + bool implemented; /**< TRUE if the module is implemented (does not have to be installed), + not just imported. */ + + sr_sch_revision_t revision; /**< Revision the module. */ + + sr_sch_submodule_t *submodules; /**< Array of all installed submodules of the module. */ + size_t submodule_count; /**< Number of module's submodules. */ + + char **enabled_features; /**< Array of enabled features */ + size_t enabled_feature_cnt; /**< Number of enabled feature */ +} sr_schema_t; + +/** + * @brief Format types of ::sr_get_schema result + */ +typedef enum sr_schema_format_e { + SR_SCHEMA_YANG, /**< YANG format */ + SR_SCHEMA_YIN /**< YIN format */ +} sr_schema_format_t; + +/** + * @brief Iterator used for accessing data nodes via ::sr_get_items_iter call. + */ +typedef struct sr_val_iter_s sr_val_iter_t; + +/** + * @brief Retrieves list of schemas installed in the sysrepo datastore. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[out] schemas Array of installed schemas information (allocated by + * the function, it is supposed to be freed by caller using ::sr_free_schemas call). + * @param[out] schema_cnt Number of schemas returned in the array. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_list_schemas(sr_session_ctx_t *session, sr_schema_t **schemas, size_t *schema_cnt); + +/** + * @brief Retrieves the content of specified schema file. If the module + * can not be found SR_ERR_NOT_FOUND is returned. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] module_name Name of the requested module. + * @param[in] revision Requested revision of the module. If NULL + * is passed, the latest revision will be returned. + * @param[in] submodule_name Name of the requested submodule. Pass NULL if you are + * requesting the content of the main module. + * @param[in] format of the returned schema + * @param[out] schema_content Content of the specified schema file. Automatically + * allocated by the function, should be freed by the caller. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_get_schema(sr_session_ctx_t *session, const char *module_name, const char *revision, + const char *submodule_name, sr_schema_format_t format, char **schema_content); + +/** + * @brief Retrieves the content of the specified submodule schema file. If the submodule + * cannot be found, SR_ERR_NOT_FOUND is returned. + * + * @param[in] session Session context acquired from ::sr_session_start call. + * @param[in] submodule_name Name of the requested submodule. + * @param[in] submodule_revision Requested revision of the submodule. If NULL + * is passed, the latest revision will be returned. + * @param[in] format of the returned schema. + * @param[out] schema_content Content of the specified schema file. Automatically + * allocated by the function, should be freed by the caller. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_get_submodule_schema(sr_session_ctx_t *session, const char *submodule_name, const char *submodule_revision, + sr_schema_format_t format, char **schema_content); + +/** + * @brief Retrieves a single data element stored under provided XPath. If multiple + * nodes matches the xpath SR_ERR_INVAL_ARG is returned. + * + * If the xpath identifies an empty leaf, a list or a container, the value + * has no data filled in and its type is set properly (SR_LEAF_EMPTY_T / SR_LIST_T / SR_CONTAINER_T / SR_CONTAINER_PRESENCE_T). + * + * @see @ref xp_page "Path Addressing" documentation, or + * https://tools.ietf.org/html/draft-ietf-netmod-yang-json#section-6.11 + * for XPath syntax used for identification of yang nodes in sysrepo calls. + * + * @see Use ::sr_get_items or ::sr_get_items_iter for retrieving larger chunks + * of data from the datastore. Since they retrieve the data from datastore in + * larger chunks, they can work much more efficiently than multiple ::sr_get_item calls. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier of the data element to be retrieved. + * @param[out] value Structure containing information about requested element + * (allocated by the function, it is supposed to be freed by the caller using ::sr_free_val). + * + * @return Error code (SR_ERR_OK on success) + */ +int sr_get_item(sr_session_ctx_t *session, const char *xpath, sr_val_t **value); + +/** + * @brief Retrieves an array of data elements matching provided XPath + * + * All data elements are transferred within one message from the datastore, + * which is much more efficient that calling multiple ::sr_get_item calls. + * + * If the user does not have read permission to access certain nodes, these + * won't be part of the result. SR_ERR_NOT_FOUND will be returned if there are + * no nodes matching xpath in the data tree, or the user does not have read permission to access them. + * + * If the response contains too many elements time out may be exceeded, SR_ERR_TIME_OUT + * will be returned, use ::sr_get_items_iter. + * + * @see @ref xp_page "Path Addressing" documentation + * for Path syntax used for identification of yang nodes in sysrepo calls. + * + * @see ::sr_get_items_iter can be used for the same purpose as ::sr_get_items + * call if you expect that ::sr_get_items could return too large data sets. + * Since ::sr_get_items_iter also retrieves the data from datastore in larger chunks, + * in can still work very efficiently for large datasets. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier of the data element to be retrieved. + * @param[out] values Array of structures containing information about requested data elements + * (allocated by the function, it is supposed to be freed by the caller using ::sr_free_values). + * @param[out] value_cnt Number of returned elements in the values array. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_get_items(sr_session_ctx_t *session, const char *xpath, sr_val_t **values, size_t *value_cnt); + +/** + * @brief Creates an iterator for retrieving of the data elements stored under provided xpath. + * + * Requested data elements are transferred from the datastore in larger chunks + * of pre-defined size, which is much more efficient that calling multiple + * ::sr_get_item calls, and may be less memory demanding than calling ::sr_get_items + * on very large datasets. + * + * @see @ref xp_page "Path Addressing" documentation, or + * https://tools.ietf.org/html/draft-ietf-netmod-yang-json#section-6.11 + * for XPath syntax used for identification of yang nodes in sysrepo calls. + * + * @see ::sr_get_item_next for iterating over returned data elements. + * @note Iterator allows to iterate through the values once. To start iteration + * from the beginning new iterator must be created. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier of the data element / subtree to be retrieved. + * @param[out] iter Iterator context that can be used to retrieve individual data + * elements via ::sr_get_item_next calls. Allocated by the function, should be + * freed with ::sr_free_val_iter. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_get_items_iter(sr_session_ctx_t *session, const char *xpath, sr_val_iter_t **iter); + +/** + * @brief Returns the next item from the dataset of provided iterator created + * by ::sr_get_items_iter call. If there is no item left SR_ERR_NOT_FOUND is returned. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in,out] iter Iterator acquired with ::sr_get_items_iter call. + * @param[out] value Structure containing information about requested element + * (allocated by the function, it is supposed to be freed by the caller using ::sr_free_val). + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_get_item_next(sr_session_ctx_t *session, sr_val_iter_t *iter, sr_val_t **value); + +/** + * @brief Flags used to customize the behaviour of ::sr_get_subtree and ::sr_get_subtrees calls. + */ +typedef enum sr_get_subtree_flag_e { + /** + * Default get-subtree(s) behaviour. + * All matched subtrees are sent with all their content in one message. + */ + SR_GET_SUBTREE_DEFAULT = 0, + + /** + * The iterative get-subtree(s) behaviour. + * The matched subtrees are sent in chunks and only as needed while they are iterated + * through using functions ::sr_node_get_child, ::sr_node_get_next_sibling and + * ::sr_node_get_parent from "sysrepo/trees.h". This behaviour gives much better + * performance than the default one if only a small portion of matched subtree(s) is + * actually iterated through. + * @note It is considered a programming error to access \p next, \p prev, \p parent, + * \p first_child and \p last_child data members of ::sr_node_t on a partially loaded tree. + */ + SR_GET_SUBTREE_ITERATIVE = 1 +} sr_get_subtree_flag_t; + +/** + * @brief Options for get-subtree and get-subtrees operations. + * It is supposed to be bitwise OR-ed value of any ::sr_get_subtree_flag_t flags. + */ +typedef uint32_t sr_get_subtree_options_t; + +/** + * @brief Retrieves a single subtree whose root node is stored under the provided XPath. + * If multiple nodes matches the xpath SR_ERR_INVAL_ARG is returned. + * + * The functions returns values and all associated information stored under the root node and + * all its descendants. While the same data can be obtained using ::sr_get_items in combination + * with the expressive power of XPath addressing, the recursive nature of the output data type + * also preserves the hierarchical relationships between data elements. + * + * Values of internal nodes of the subtree have no data filled in and their type is set properly + * (SR_LIST_T / SR_CONTAINER_T / SR_CONTAINER_PRESENCE_T), whereas leaf nodes are carrying actual + * data (apart from SR_LEAF_EMPTY_T). + * + * @see @ref xp_page "Path Addressing" documentation + * for XPath syntax used for identification of yang nodes in sysrepo calls. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier referencing the root node of the subtree to be retrieved. + * @param[in] opts Options overriding default behavior of this operation. + * @param[out] subtree Nested structure storing all data of the requested subtree + * (allocated by the function, it is supposed to be freed by the caller using ::sr_free_tree). + * + * @return Error code (SR_ERR_OK on success) + */ +int sr_get_subtree(sr_session_ctx_t *session, const char *xpath, sr_get_subtree_options_t opts, + sr_node_t **subtree); + +/** + * @brief Retrieves an array of subtrees whose root nodes match the provided XPath. + * + * If the user does not have read permission to access certain nodes, these together with + * their descendants won't be part of the result. SR_ERR_NOT_FOUND will be returned if there are + * no nodes matching xpath in the data tree, or the user does not have read permission to access them. + * + * Subtrees that match the provided XPath are not merged even if they overlap. This significantly + * simplifies the implementation and decreases the cost of this operation. The downside is that + * the user must choose the XPath carefully. If the subtree selection process results in too many + * node overlaps, the cost of the operation may easily outshine the benefits. As an example, + * a common XPath expression "//." is normally used to select all nodes in a data tree, but for this + * operation it would result in an excessive duplication of transfered data elements. + * Since you get all the descendants of each matched node implicitly, you probably should not need + * to use XPath wildcards deeper than on the top-level. + * (i.e. "/." is preferred alternative to "//." for get-subtrees operation). + * + * If the response contains too many elements time out may be exceeded, SR_ERR_TIME_OUT + * will be returned. + * + * @see @ref xp_page "Path Addressing" documentation, or + * https://tools.ietf.org/html/draft-ietf-netmod-yang-json#section-6.11 + * for XPath syntax used for identification of yang nodes in sysrepo calls. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier referencing root nodes of subtrees to be retrieved. + * @param[in] opts Options overriding default behavior of this operation. + * @param[out] subtrees Array of nested structures storing all data of the requested subtrees + * (allocated by the function, it is supposed to be freed by the caller using ::sr_free_trees). + * @param[out] subtree_cnt Number of returned trees in the subtrees array. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_get_subtrees(sr_session_ctx_t *session, const char *xpath, sr_get_subtree_options_t opts, + sr_node_t **subtrees, size_t *subtree_cnt); + + +//////////////////////////////////////////////////////////////////////////////// +// Data Manipulation API (edit-config functionality) +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Flags used to override default behavior of data manipulation calls. + */ +typedef enum sr_edit_flag_e { + SR_EDIT_DEFAULT = 0, /**< Default behavior - recursive and non-strict. */ + SR_EDIT_NON_RECURSIVE = 1, /**< Non-recursive behavior: + by ::sr_set_item, all preceding nodes (parents) of the identified element must exist, + by ::sr_delete_item xpath must not identify an non-empty list or non-empty container. */ + SR_EDIT_STRICT = 2 /**< Strict behavior: + by ::sr_set_item the identified element must not exist (similar to netconf create operation), + by ::sr_delete_item the identified element must exist (similar to netconf delete operation). */ +} sr_edit_flag_t; + +/** + * @brief Options overriding default behavior of data manipulation calls, + * it is supposed to be bitwise OR-ed value of any ::sr_edit_flag_t flags. + */ +typedef uint32_t sr_edit_options_t; + +/** + * @brief Options for specifying move direction of ::sr_move_item call. + */ +typedef enum sr_move_position_e { + SR_MOVE_BEFORE = 0, /**< Move the specified item before the selected sibling. */ + SR_MOVE_AFTER = 1, /**< Move the specified item after the selected. */ + SR_MOVE_FIRST = 2, /**< Move the specified item to the position of the first child. */ + SR_MOVE_LAST = 3, /**< Move the specified item to the position of the last child. */ +} sr_move_position_t; + +/** + * @brief Sets the value of the leaf, leaf-list, list or presence container. + * + * With default options it recursively creates all missing nodes (containers and + * lists including their key leaves) in the xpath to the specified node (can be + * turned off with SR_EDIT_NON_RECURSIVE option). If SR_EDIT_STRICT flag is set, + * the node must not exist (otherwise an error is returned). + * + * To create a list use xpath with key values included and pass NULL as value argument. + * + * Setting of a leaf-list value appends the value at the end of the leaf-list. + * A value of leaf-list can be specified either by predicate in xpath or by value argument. + * If both are present, value argument is ignored and xpath predicate is used. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier of the data element to be set. + * @param[in] value Value to be set on specified xpath. xpath member of the + * ::sr_val_t structure can be NULL. Value will be copied - can be allocated on stack. + * @param[in] opts Options overriding default behavior of this call. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_set_item(sr_session_ctx_t *session, const char *xpath, const sr_val_t *value, const sr_edit_options_t opts); + + +/** + * @brief Functions is similar to ::sr_set_item with the difference that the value to be set + * is provided as string. + * @param [in] session Session context acquired with ::sr_session_start call. + * @param [in] xpath @ref xp_page "Data Path" identifier of the data element to be set. + * @param [in] value string representation of the value to be set + * @param [in] opts same as for ::sr_set_item + * @return Error code (SR_ERR_OK on success). + */ +int sr_set_item_str(sr_session_ctx_t *session, const char *xpath, const char *value, const sr_edit_options_t opts); +/** + * @brief Deletes the nodes under the specified xpath. + * + * To delete non-empty lists or containers SR_EDIT_NON_RECURSIVE flag must not be set. + * If SR_EDIT_STRICT flag is set the specified node must must exist in the datastore. + * If the xpath includes the list keys, the specified list instance is deleted. + * If the xpath to list does not include keys, all instances of the list are deleted. + * SR_ERR_UNAUTHORIZED will be returned if the user does not have write permission to any affected node. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier of the data element to be deleted. + * @param[in] opts Options overriding default behavior of this call. + * + * @return Error code (SR_ERR_OK on success). + **/ +int sr_delete_item(sr_session_ctx_t *session, const char *xpath, const sr_edit_options_t opts); + +/** + * @brief Move the instance of an user-ordered list or leaf-list to the specified position. + * + * Item can be move to the first or last position or positioned relatively to its sibling. + * @note To determine current order, you can issue a ::sr_get_items call + * (without specifying keys of the list in question). + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier of the data element to be moved. + * @param[in] position Requested move direction. + * @param[in] relative_item xpath Identifier of the data element that is used + * to determine relative position, used only if position argument is SR_MOVE_BEFORE or SR_MOVE_AFTER. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_move_item(sr_session_ctx_t *session, const char *xpath, const sr_move_position_t position, const char *relative_item); + +/** + * @brief Perform the validation of changes made in current session, but do not + * commit nor discard them. + * + * Provides only YANG validation, commit verify subscribers won't be notified in this case. + * + * @see Use ::sr_get_last_errors to retrieve error information if the validation + * returned with an error. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_validate(sr_session_ctx_t *session); + +/** + * @brief Apply changes made in current session. + * + * @note Note that in case that you are committing to the running datstore, you also + * need to copy the config to startup to make changes permanent after restart. + * + * @see Use ::sr_get_last_errors to retrieve error information if the commit + * operation returned with an error. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_commit(sr_session_ctx_t *session); + +/** + * @brief Discard non-committed changes made in current session. + * + * @note Since the function effectively clears all the cached data within the session, + * the next operation will operate on fresh data loaded from the datastore + * (i.e. no need to call ::sr_session_refresh afterwards). + * + * @param[in] session Session context acquired with ::sr_session_start call. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_discard_changes(sr_session_ctx_t *session); + +/** + * @brief Replaces an entire configuration datastore with the contents of + * another complete configuration datastore. If the module is specified, limits + * the copy operation only to one specified module. If it's not specified, + * the operation is performed on all modules that are currently active in the + * source datastore. + * + * If the target datastore exists, it is overwritten. Otherwise, a new one is created. + * + * @note ::sr_session_refresh is needed to see the result of a copy-config operation + * in a session apart from the case when SR_DS_CANDIDATE is the destination datastore. + * Since the candidate is not shared among sessions, data trees are copied only to the + * canidate in the session issuing the copy-config operation. + * + * @note Operation may fail, if it tries to copy a not enabled configuration to the + * running datastore. + * + * @note \p session \p dst_datastore uncommitted changes will get discarded. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] module_name If specified, only limits the copy operation only to + * one specified module. + * @param[in] src_datastore Source datastore. + * @param[in] dst_datastore Destination datastore. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_copy_config(sr_session_ctx_t *session, const char *module_name, + sr_datastore_t src_datastore, sr_datastore_t dst_datastore); + + +//////////////////////////////////////////////////////////////////////////////// +// Locking API +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Locks the datastore which the session is tied to. If there is + * a module locked by the other session SR_ERR_LOCKED is returned. + * Operation fails if there is a modified data tree in session. + * + * All data models within the datastore will be locked for writing until + * ::sr_unlock_datastore is called or until the session is stopped or terminated + * for any reason. + * + * The lock operation will not be allowed if the user does not have sufficient + * permissions for writing into each of the data models in the datastore. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_lock_datastore(sr_session_ctx_t *session); + +/** + * @brief Unlocks the datastore which the session is tied to. + * + * All data models within the datastore will be unlocked if they were locked + * by this session. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_unlock_datastore(sr_session_ctx_t *session); + +/** + * @brief Locks specified data module within the datastore which the session + * is tied to. Operation fails if the data tree has been modified. + * + * Specified data module will be locked for writing in the datastore until + * ::sr_unlock_module is called or until the session is stopped or terminated + * for any reason. + * + * The lock operation will not be allowed if the user does not have sufficient + * permissions for writing into the specified data module. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] module_name Name of the module to be locked. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_lock_module(sr_session_ctx_t *session, const char *module_name); + +/** + * @brief Unlocks specified data module within the datastore which the session + * is tied to. + * + * Specified data module will be unlocked if was locked in the datastore + * by this session. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] module_name Name of the module to be unlocked. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_unlock_module(sr_session_ctx_t *session, const char *module_name); + + +//////////////////////////////////////////////////////////////////////////////// +// Change Notifications API +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Flags used to override default handling of subscriptions. + */ +typedef enum sr_subscr_flag_e { + /** + * @brief Default behavior of the subscription. In case of ::sr_module_change_subscribe and + * ::sr_subtree_change_subscribe calls it means that: + * + * - the subscriber is the "owner" of the subscribed data tree and and the data tree will be enabled in the running + * datastore while this subscription is alive (if not already, can be changed using ::SR_SUBSCR_PASSIVE flag), + * - configuration data of the subscribed module or subtree is copied from startup to running datastore + * (only if the module was not enabled before), + * - the callback will be called twice, once with ::SR_EV_VERIFY event and once with ::SR_EV_APPLY / ::SR_EV_ABORT + * event passed in (can be changed with ::SR_SUBSCR_APPLY_ONLY flag). + */ + SR_SUBSCR_DEFAULT = 0, + + /** + * @brief This option enables the application to re-use an already existing subscription context previously returned + * from any sr_*_subscribe call instead of requesting the creation of a new one. In that case a single + * ::sr_unsubscribe call unsubscribes from all subscriptions filed within the context. + */ + SR_SUBSCR_CTX_REUSE = 1, + + /** + * @brief The subscriber is not the "owner" of the subscribed data tree, just a passive watcher for changes. + * When this option is passed in to ::sr_module_change_subscribe or ::sr_subtree_change_subscribe, + * the subscription will have no effect on the presence of the subtree in the running datastore. + */ + SR_SUBSCR_PASSIVE = 2, + + /** + * @brief The subscriber does not support verification of the changes and wants to be notified only after + * the changes has been applied in the datastore, without the possibility to deny them + * (it will receive only ::SR_EV_APPLY events). + */ + SR_SUBSCR_APPLY_ONLY = 4, + + /** + * @brief The subscriber wants ::SR_EV_ENABLED notifications to be sent to them. + */ + SR_SUBSCR_EV_ENABLED = 8, + + /** + * @brief The subscriber will not receive ::SR_EV_ABORT if he returns an error in verify phase + * (if the commit is refused by other verifier ::SR_EV_ABORT will be delivered). + */ + SR_SUBSCR_NO_ABORT_FOR_REFUSED_CFG = 16, + + /** + * @brief No real-time notifications will be delivered until ::sr_event_notif_replay is called + * and replay has finished (::SR_EV_NOTIF_T_REPLAY_COMPLETE is delivered). + */ + SR_SUBSCR_NOTIF_REPLAY_FIRST = 32, +} sr_subscr_flag_t; + +/** + * @brief Type of the notification event that has occurred (passed to notification callbacks). + * + * @note Each change is normally notified twice: first as ::SR_EV_VERIFY event and then as ::SR_EV_APPLY or ::SR_EV_ABORT + * event. If the subscriber does not support verification, it can subscribe only to ::SR_EV_APPLY event by providing + * ::SR_SUBSCR_APPLY_ONLY subscription flag. + */ +typedef enum sr_notif_event_e { + SR_EV_VERIFY, /**< Occurs just before the changes are committed to the datastore, + the subscriber is supposed to verify that the changes are valid and can be applied + and prepare all resources required for the changes. The subscriber can still deny the changes + in this phase by returning an error from the callback. */ + SR_EV_APPLY, /**< Occurs just after the changes have been successfully committed to the datastore, + the subscriber is supposed to apply the changes now, but it cannot deny the changes in this + phase anymore (any returned errors are just logged and ignored). */ + SR_EV_ABORT, /**< Occurs in case that the commit transaction has failed (possibly because one of the verifiers + has denied the change / returned an error). The subscriber is supposed to return the managed + application to the state before the commit. Any returned errors are just logged and ignored. */ + SR_EV_ENABLED, /**< Occurs just after the subscription. Subscriber gets notified about configuration that was copied + from startup to running. This allows to reuse the callback for applying changes made in running to + reflect the changes when the configuration is copied from startup to running during subscription process */ +} sr_notif_event_t; + +/** + * @brief Type of the operation made on an item, used by changeset retrieval in ::sr_get_change_next. + */ +typedef enum sr_change_oper_e { + SR_OP_CREATED, /**< The item has been created by the change. */ + SR_OP_MODIFIED, /**< The value of the item has been modified by the change. */ + SR_OP_DELETED, /**< The item has been deleted by the change. */ + SR_OP_MOVED, /**< The item has been moved in the subtree by the change (applicable for leaf-lists and user-ordered lists). */ +} sr_change_oper_t; + +/** + * @brief State of a module as returned by the ::sr_module_install_cb callback. + */ +typedef enum sr_module_state_e { + SR_MS_UNINSTALLED, /**< The module is not installed in the sysrepo repository. */ + SR_MS_IMPORTED, /**< The module has been implicitly installed into the sysrepo repository + as it is imported by another implemented/imported module. */ + SR_MS_IMPLEMENTED /**< The module has been explicitly installed into the sysrepo repository by the user. */ +} sr_module_state_t; + +/** + * @brief Sysrepo subscription context returned from sr_*_subscribe calls, + * it is supposed to be released by the caller using ::sr_unsubscribe call. + */ +typedef struct sr_subscription_ctx_s sr_subscription_ctx_t; + +/** + * @brief Iterator used for retrieval of a changeset using ::sr_get_changes_iter call. + */ +typedef struct sr_change_iter_s sr_change_iter_t; + +/** + * @brief Options overriding default behavior of subscriptions, + * it is supposed to be a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + */ +typedef uint32_t sr_subscr_options_t; + +/** + * @brief Callback to be called by the event of changing any running datastore + * content within the specified module. Subscribe to it by ::sr_module_change_subscribe call. + * + * @param[in] session Automatically-created session that can be used for obtaining changed data + * (e.g. by ::sr_get_changes_iter call ot ::sr_get_item -like calls). Do not stop this session. + * @param[in] module_name Name of the module where the change has occurred. + * @param[in] event Type of the notification event that has occurred. + * @param[in] private_ctx Private context opaque to sysrepo, as passed to + * ::sr_module_change_subscribe call. + */ +typedef int (*sr_module_change_cb)(sr_session_ctx_t *session, const char *module_name, + sr_notif_event_t event, void *private_ctx); + +/** + * @brief Callback to be called by the event of changing any running datastore + * content within the specified subtree. Subscribe to it by ::sr_subtree_change_subscribe call. + * + * @param[in] session Automatically-created session that can be used for obtaining changed data + * (e.g. by ::sr_get_changes_iter call or ::sr_get_item -like calls). Do not stop this session. + * @param[in] xpath @ref xp_page "Data Path" of the subtree where the change has occurred. + * @param[in] event Type of the notification event that has occurred. + * @param[in] private_ctx Private context opaque to sysrepo, as passed to + * ::sr_subtree_change_subscribe call. + */ +typedef int (*sr_subtree_change_cb)(sr_session_ctx_t *session, const char *xpath, + sr_notif_event_t event, void *private_ctx); + +/** + * @brief Callback to be called by the event of installation / uninstallation + * of a new module into sysrepo. Subscribe to it by ::sr_module_install_subscribe call. + * + * @param[in] module_name Name of the newly installed / uinstalled module. + * @param[in] revision Revision of the newly installed module (if specified + * within the YANG model). + * @param[in] state The new state of the module (uninstalled vs. imported vs. implemented). + * @param[in] private_ctx Private context opaque to sysrepo, as passed to + * ::sr_module_install_subscribe call. + */ +typedef void (*sr_module_install_cb)(const char *module_name, const char *revision, sr_module_state_t state, + void *private_ctx); + +/** + * @brief Callback to be called by the event of enabling / disabling of + * a YANG feature within a module. Subscribe to it by ::sr_feature_enable_subscribe call. + * + * @param[in] module_name Name of the module where the feature has been enabled / disabled. + * @param[in] feature_name Name of the feature that has been enabled / disabled. + * @param[in] enabled TRUE if the feature has been enabled, FALSE if disabled. + * @param[in] private_ctx Private context opaque to sysrepo, as passed to + * ::sr_feature_enable_subscribe call. + */ +typedef void (*sr_feature_enable_cb)(const char *module_name, const char *feature_name, bool enabled, void *private_ctx); + +/** + * @brief Subscribes for notifications about the changes made within specified + * module in running datastore. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] module_name Name of the module of interest for change notifications. + * @param[in] callback Callback to be called when the change in the datastore occurs. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] priority Specifies the order in which the callbacks will be called (callbacks with higher + * priority will be called sooner, callbacks with the priority of 0 will be called at the end). + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_module_change_subscribe(sr_session_ctx_t *session, const char *module_name, sr_module_change_cb callback, + void *private_ctx, uint32_t priority, sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + +/** + * @brief Subscribes for notifications about the changes made within specified + * subtree in running datastore. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifier of the subtree of the interest for change notifications. + * @param[in] callback Callback to be called when the change in the datastore occurs. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] priority Specifies the order in which the callbacks will be called (callbacks with higher + * priority will be called sooner, callbacks with the priority of 0 will be called at the end). + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_subtree_change_subscribe(sr_session_ctx_t *session, const char *xpath, sr_subtree_change_cb callback, + void *private_ctx, uint32_t priority, sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + +/** + * @brief Subscribes for notifications about installation / uninstallation + * of a new module into sysrepo. + * + * Mainly intended for northbound management applications that need to be + * always aware of all active modules installed in sysrepo. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] callback Callback to be called when the event occurs. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_module_install_subscribe(sr_session_ctx_t *session, sr_module_install_cb callback, void *private_ctx, + sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + +/** + * @brief Subscribes for notifications about enabling / disabling of + * a YANG feature within a module. + * + * Mainly intended for northbound management applications that need to be + * always aware of all active features within the modules installed in sysrepo. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] callback Callback to be called when the event occurs. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_feature_enable_subscribe(sr_session_ctx_t *session, sr_feature_enable_cb callback, void *private_ctx, + sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + +/** + * @brief Unsubscribes from a subscription acquired by any of sr_*_subscribe + * calls and releases all subscription-related data. + * + * @note In case that the same subscription context was used to subscribe for + * multiple subscriptions, unsubscribes from all of them. + * + * @param[in] session Session context acquired with ::sr_session_start call. Does not + * need to be the same as used for subscribing. NULL can be passed too, in that case + * a temporary session used for unsubscribe will be automatically created by sysrepo. + * @param[in] subscription Subscription context acquired by any of sr_*_subscribe calls. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_unsubscribe(sr_session_ctx_t *session, sr_subscription_ctx_t *subscription); + +/** + * @brief Creates an iterator for retrieving of the changeset (list of newly + * added / removed / modified nodes) in notification callbacks. + * + * @see ::sr_get_change_next for iterating over the changeset using this iterator. + * + * @param[in] session Session context as passed to notication the callbacks (e.g. + * ::sr_module_change_cb or ::sr_subtree_change_cb). Will not work with any other sessions. + * @param[in] xpath @ref xp_page "Data Path" identifier of the subtree from which the changeset + * should be obtained. Only XPaths that would be accepted by ::sr_subtree_change_subscribe are allowed. + * @param[out] iter Iterator context that can be used to retrieve individual changes using + * ::sr_get_change_next calls. Allocated by the function, should be freed with ::sr_free_change_iter. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_get_changes_iter(sr_session_ctx_t *session, const char *xpath, sr_change_iter_t **iter); + +/** + * @brief Returns the next change from the changeset of provided iterator created + * by ::sr_get_changes_iter call. If there is no item left, SR_ERR_NOT_FOUND is returned. + * + * @note If the operation is ::SR_OP_MOVED the meaning of new_value and old value argument is + * as follows - the value pointed by new_value was moved after the old_value. If the + * old value is NULL it was moved to the first position. + * + * @param[in] session Session context as passed to notication the callbacks (e.g. + * ::sr_module_change_cb or ::sr_subtree_change_cb). Will not work with any other sessions. + * @param[in,out] iter Iterator acquired with ::sr_get_changes_iter call. + * @param[out] operation Type of the operation made on the returned item. + * @param[out] old_value Old value of the item (the value before the change). + * NULL in case that the item has been just created (operation == SR_OP_CREATED). + * @param[out] new_value New (modified) value of the the item. NULL in case that + * the item has been just deleted (operation == SR_OP_DELETED). + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_get_change_next(sr_session_ctx_t *session, sr_change_iter_t *iter, sr_change_oper_t *operation, + sr_val_t **old_value, sr_val_t **new_value); + + +//////////////////////////////////////////////////////////////////////////////// +// RPC (Remote Procedure Calls) API +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Check if the owner of this session is authorized by NACM to invoke the protocol + * operation defined in a (installed) YANG module under the given xpath (as RPC or Action). + * + * This call is intended for northbound management applications that need to implement + * the NETCONF Access Control Model (RFC 6536) to restrict the protocol operations that + * each user is authorized to execute. + * + * NETCONF access control is already included in the processing of ::sr_rpc_send, + * ::sr_rpc_send_tree, ::sr_action_send and ::sr_action_send_tree and thus it should be + * sufficient to call this function only prior to executing any of the NETCONF standard + * protocol operations as they cannot be always directly translated to a single sysrepo + * API call. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifying the protocol operation. + * @param[out] permitted TRUE if the user is permitted to execute the given operation, FALSE otherwise. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_check_exec_permission(sr_session_ctx_t *session, const char *xpath, bool *permitted); + +/** + * @brief Callback to be called by the delivery of RPC specified by xpath. + * Subscribe to it by ::sr_rpc_subscribe call. + * + * @param[in] xpath @ref xp_page "Data Path" identifying the RPC. + * @param[in] input Array of input parameters. + * @param[in] input_cnt Number of input parameters. + * @param[out] output Array of output parameters. Should be allocated on heap, + * will be freed by sysrepo after sending of the RPC response. + * @param[out] output_cnt Number of output parameters. + * @param[in] private_ctx Private context opaque to sysrepo, as passed to ::sr_rpc_subscribe call. + * + * @return Error code (SR_ERR_OK on success). + */ +typedef int (*sr_rpc_cb)(const char *xpath, const sr_val_t *input, const size_t input_cnt, + sr_val_t **output, size_t *output_cnt, void *private_ctx); + +/** + * @brief Callback to be called by the delivery of RPC specified by xpath. + * This RPC callback variant operates with sysrepo trees rather than with sysrepo values, + * use it with ::sr_rpc_subscribe_tree and ::sr_rpc_send_tree. + * + * @param[in] xpath @ref xp_page "Data Path" identifying the RPC. + * @param[in] input Array of input parameters (represented as trees). + * @param[in] input_cnt Number of input parameters. + * @param[out] output Array of output parameters (represented as trees). Should be allocated on heap, + * will be freed by sysrepo after sending of the RPC response. + * @param[out] output_cnt Number of output parameters. + * @param[in] private_ctx Private context opaque to sysrepo, as passed to ::sr_rpc_subscribe_tree call. + * + * @return Error code (SR_ERR_OK on success). + */ +typedef int (*sr_rpc_tree_cb)(const char *xpath, const sr_node_t *input, const size_t input_cnt, + sr_node_t **output, size_t *output_cnt, void *private_ctx); + +/** + * @brief Subscribes for delivery of RPC specified by xpath. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Schema Path" identifying the RPC. + * @param[in] callback Callback to be called when the RPC is called. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_rpc_subscribe(sr_session_ctx_t *session, const char *xpath, sr_rpc_cb callback, void *private_ctx, + sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + +/** + * @brief Subscribes for delivery of RPC specified by xpath. Unlike ::sr_rpc_subscribe, this + * function expects callback of type ::sr_rpc_tree_cb, therefore use this version if you prefer + * to manipulate with RPC input and output data organized in a list of trees rather than as a flat + * enumeration of all values. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Schema Path" identifying the RPC. + * @param[in] callback Callback to be called when the RPC is called. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_rpc_subscribe_tree(sr_session_ctx_t *session, const char *xpath, sr_rpc_tree_cb callback, + void *private_ctx, sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + +/** + * @brief Sends a RPC specified by xpath and waits for the result. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifying the RPC. + * @param[in] input Array of input parameters (array of all nodes that hold some + * data in RPC input subtree - same as ::sr_get_items would return). + * @param[in] input_cnt Number of input parameters. + * @param[out] output Array of output parameters (all nodes that hold some data + * in RPC output subtree). Will be allocated by sysrepo and should be freed by + * caller using ::sr_free_values. + * @param[out] output_cnt Number of output parameters. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_rpc_send(sr_session_ctx_t *session, const char *xpath, + const sr_val_t *input, const size_t input_cnt, sr_val_t **output, size_t *output_cnt); + +/** + * @brief Sends a RPC specified by xpath and waits for the result. Input and output data + * are represented as arrays of subtrees reflecting the scheme of RPC arguments. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifying the RPC. + * @param[in] input Array of input parameters (organized in trees). + * @param[in] input_cnt Number of input parameters. + * @param[out] output Array of output parameters (organized in trees). + * Will be allocated by sysrepo and should be freed by caller using ::sr_free_trees. + * @param[out] output_cnt Number of output parameters. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_rpc_send_tree(sr_session_ctx_t *session, const char *xpath, + const sr_node_t *input, const size_t input_cnt, sr_node_t **output, size_t *output_cnt); + + +//////////////////////////////////////////////////////////////////////////////// +// Action API +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Callback to be called by the delivery of Action (operation connected to a specific data node) + * specified by xpath. Subscribe to it by ::sr_action_subscribe call. + * @see This type is an alias for @ref sr_rpc_cb "the RPC callback type" + */ +typedef sr_rpc_cb sr_action_cb; + +/** + * @brief Callback to be called by the delivery of Action (operation connected to a specific data node) + * specified by xpath. + * This callback variant operates with sysrepo trees rather than with sysrepo values, + * use it with ::sr_action_subscribe_tree and ::sr_action_send_tree. + * @see This type is an alias for tree variant of @ref sr_rpc_tree_cb "the RPC callback " + */ +typedef sr_rpc_tree_cb sr_action_tree_cb; + +/** + * @brief Subscribes for delivery of Action specified by xpath. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Schema Path" identifying the Action. + * @param[in] callback Callback to be called when the Action is called. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_action_subscribe(sr_session_ctx_t *session, const char *xpath, sr_action_cb callback, void *private_ctx, + sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + +/** + * @brief Subscribes for delivery of Action specified by xpath. Unlike ::sr_action_subscribe, this + * function expects callback of type ::sr_action_tree_cb, therefore use this version if you prefer + * to manipulate with Action input and output data organized in a list of trees rather than as a flat + * enumeration of all values. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Schema Path" identifying the Action. + * @param[in] callback Callback to be called when the Action is called. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_action_subscribe_tree(sr_session_ctx_t *session, const char *xpath, sr_action_tree_cb callback, + void *private_ctx, sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + +/** + * @brief Executes an action specified by xpath and waits for the result. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifying the Action. + * @param[in] input Array of input parameters (array of all nodes that hold some + * data in Action input subtree - same as ::sr_get_items would return). + * @param[in] input_cnt Number of input parameters. + * @param[out] output Array of output parameters (all nodes that hold some data + * in Action output subtree). Will be allocated by sysrepo and should be freed by + * caller using ::sr_free_values. + * @param[out] output_cnt Number of output parameters. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_action_send(sr_session_ctx_t *session, const char *xpath, + const sr_val_t *input, const size_t input_cnt, sr_val_t **output, size_t *output_cnt); + +/** + * @brief Executes an action specified by xpath and waits for the result. Input and output data + * are represented as arrays of subtrees reflecting the scheme of Action arguments. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifying the Action. + * @param[in] input Array of input parameters (organized in trees). + * @param[in] input_cnt Number of input parameters. + * @param[out] output Array of output parameters (organized in trees). + * Will be allocated by sysrepo and should be freed by caller using ::sr_free_trees. + * @param[out] output_cnt Number of output parameters. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_action_send_tree(sr_session_ctx_t *session, const char *xpath, + const sr_node_t *input, const size_t input_cnt, sr_node_t **output, size_t *output_cnt); + + +//////////////////////////////////////////////////////////////////////////////// +// Event Notifications API +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Type of the notification passed to the ::sr_event_notif_cb and ::sr_event_notif_tree_cb callbacks. + */ +typedef enum sr_ev_notif_type_e { + SR_EV_NOTIF_T_REALTIME, /**< Real-time notification. The only possible type if you don't use ::sr_event_notif_replay. */ + SR_EV_NOTIF_T_REPLAY, /**< Replayed notification. */ + SR_EV_NOTIF_T_REPLAY_COMPLETE, /**< Not a real notification, just a signal that the notification replay has completed + (all the stored notifications from the given time interval have been delivered). */ + SR_EV_NOTIF_T_REPLAY_STOP, /**< Not a real notification, just a signal that replay stop time has been reached + (delivered only if stop_time was specified to ::sr_event_notif_replay). */ +} sr_ev_notif_type_t; + +/** + * @brief Flags used to override default notification handling i the datastore. + */ +typedef enum sr_ev_notif_flag_e { + SR_EV_NOTIF_DEFAULT = 0, /**< Notification will be handled normally. */ + SR_EV_NOTIF_EPHEMERAL = 1, /**< Notification will not be stored in the notification store + (and therefore will be also delivered faster). */ +} sr_ev_notif_flag_t; + +/** + * @brief Callback to be called by the delivery of event notification specified by xpath. + * Subscribe to it by ::sr_event_notif_subscribe call. + * + * @param[in] notif_type Type of the notification. + * @param[in] xpath @ref xp_page "Data Path" identifying the event notification. + * @param[in] values Array of all nodes that hold some data in event notification subtree. + * @param[in] values_cnt Number of items inside the values array. + * @param[in] timestamp Time when the notification was generated + * @param[in] private_ctx Private context opaque to sysrepo, + * as passed to ::sr_event_notif_subscribe call. + * + * @return Error code (SR_ERR_OK on success). + */ +typedef void (*sr_event_notif_cb)(const sr_ev_notif_type_t notif_type, const char *xpath, + const sr_val_t *values, const size_t values_cnt, time_t timestamp, void *private_ctx); + +/** + * @brief Callback to be called by the delivery of event notification specified by xpath. + * This callback variant operates with sysrepo trees rather than with sysrepo values, + * use it with ::sr_event_notif_subscribe_tree and ::sr_event_notif_send_tree. + * + * @param[in] notif_type Type of the notification. + * @param[in] xpath @ref xp_page "Data Path" identifying the event notification. + * @param[in] trees Array of subtrees carrying event notification data. + * @param[in] tree_cnt Number of subtrees with data. + * @param[in] timestamp Time when the notification was generated + * @param[in] private_ctx Private context opaque to sysrepo, as passed to ::sr_event_notif_subscribe_tree call. + * + * @return Error code (SR_ERR_OK on success). + */ +typedef void (*sr_event_notif_tree_cb)(const sr_ev_notif_type_t notif_type, const char *xpath, + const sr_node_t *trees, const size_t tree_cnt, time_t timestamp, void *private_ctx); + +/** + * @brief Subscribes for delivery of an event notification specified by xpath. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Schema Path" identifying one event notification or special + * path in the form of a module name in which the whole module is subscribed to. + * @param[in] callback Callback to be called when the event notification is send. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_event_notif_subscribe(sr_session_ctx_t *session, const char *xpath, + sr_event_notif_cb callback, void *private_ctx, sr_subscr_options_t opts, + sr_subscription_ctx_t **subscription); + +/** + * @brief Subscribes for delivery of event notification specified by xpath. + * Unlike ::sr_event_notif_subscribe, this function expects callback of type ::sr_event_notif_tree_cb, + * therefore use this version if you prefer to manipulate with event notification data organized + * in a list of trees rather than as a flat enumeration of all values. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Schema Path" identifying one event notification or special + * path in the form of a module name in which the whole module is subscribed to. + * @param[in] callback Callback to be called when the event notification is called. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * @note An existing context may be passed in case that SR_SUBSCR_CTX_REUSE option is specified. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_event_notif_subscribe_tree(sr_session_ctx_t *session, const char *xpath, + sr_event_notif_tree_cb callback, void *private_ctx, sr_subscr_options_t opts, + sr_subscription_ctx_t **subscription); + +/** + * @brief Sends an event notification specified by xpath and waits for the result. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifying the event notification. + * @param[in] values Array of all nodes that hold some data in event notification subtree + * (same as ::sr_get_items would return). + * @param[in] values_cnt Number of items inside the values array. + * @param[in] opts Options overriding default handling of the notification, it is supposed to be + * a bitwise OR-ed value of any ::sr_ev_notif_flag_t flags. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_event_notif_send(sr_session_ctx_t *session, const char *xpath, const sr_val_t *values, + const size_t values_cnt, sr_ev_notif_flag_t opts); + +/** + * @brief Sends an event notification specified by xpath and waits for the result. + * The notification data are represented as arrays of subtrees reflecting the scheme + * of the event notification. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifying the RPC. + * @param[in] trees Array of subtrees carrying event notification data. + * @param[in] tree_cnt Number of subtrees with data. + * @param[in] opts Options overriding default handling of the notification, it is supposed to be + * a bitwise OR-ed value of any ::sr_ev_notif_flag_t flags. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_event_notif_send_tree(sr_session_ctx_t *session, const char *xpath, const sr_node_t *trees, + const size_t tree_cnt, sr_ev_notif_flag_t opts); + +/** + * @brief Replays already generated notifications stored in the notification store related to + * the provided notification subscription (or subscriptions, in case that ::SR_SUBSCR_CTX_REUSE + * was used). Notification callbacks of the given susbscriptions will be called with the type set to + * ::SR_EV_NOTIF_T_REPLAY, ::SR_EV_NOTIF_T_REPLAY_COMPLETE or ::SR_EV_NOTIF_T_REPLAY_STOP. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] subscription Session context acquired with ::sr_session_start call. + * @param[in] start_time Starting time of the desired time window for notification replay. + * @param[in] stop_time End time of the desired time window for notification replay. If set to 0, + * no stop time will be applied (all notifications up to the current time will be delivered, + * ::SR_EV_NOTIF_T_REPLAY_STOP notification won't be delivered). + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_event_notif_replay(sr_session_ctx_t *session, sr_subscription_ctx_t *subscription, + time_t start_time, time_t stop_time); + + +//////////////////////////////////////////////////////////////////////////////// +// Operational Data API +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Callback to be called when operational data at the selected level is requested. + * Subscribe to it by ::sr_dp_get_items_subscribe call. + * + * Callback handler is supposed to provide data of all nodes at the level selected by the xpath argument: + * + * - If the xpath identifies a container, the provider is supposed to return all leaves and leaf-lists values within it. + * Nested lists and containers should not be provided - sysrepo will ask for them in subsequent calls. + * - If the xpath identifies a list, the provider is supposed to return all leaves (except for keys!) and + * leaf-lists values within all instances of the list. Nested lists and containers should not be provided - sysrepo + * will ask for them in subsequent calls. + * - If the xpath identifies a leaf-list, the provider is supposed to return all leaf-list values. + * - If the xpath identifies a leaf, the provider is supposed to return just the leaf in question. + * + * The xpath argument passed to callback can be only the xpath that was used for the subscription, or xpath of + * any nested lists or containers. + * + * @param[in] xpath @ref xp_page "Data Path" identifying the level under which the nodes are requested. + * @param[out] values Array of values at the selected level (allocated by the provider). + * @param[out] values_cnt Number of values returned. + * @param[in] request_id An ID identifying the originating request. + * @param[in] private_ctx Private context opaque to sysrepo, as passed to ::sr_dp_get_items_subscribe call. + * + * @return Error code (SR_ERR_OK on success). + */ +typedef int (*sr_dp_get_items_cb)(const char *xpath, sr_val_t **values, size_t *values_cnt, uint64_t request_id, void *private_ctx); + +/** + * @brief Registers for providing of operational data under given xpath. + * + * @note The XPath must be generic - must not include any list key values. + * @note This API works only for operational data (subtrees marked in YANG as "config false"). + * Subscribing as a data provider for configuration data does not have any effect. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] xpath @ref xp_page "Data Path" identifying the subtree under which the provider is able to provide + * operational data. + * @param[in] callback Callback to be called when the operational data nder given xpat is needed. + * @param[in] private_ctx Private context passed to the callback function, opaque to sysrepo. + * @param[in] opts Options overriding default behavior of the subscription, it is supposed to be + * a bitwise OR-ed value of any ::sr_subscr_flag_t flags. + * @param[in,out] subscription Subscription context that is supposed to be released by ::sr_unsubscribe. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_dp_get_items_subscribe(sr_session_ctx_t *session, const char *xpath, sr_dp_get_items_cb callback, void *private_ctx, + sr_subscr_options_t opts, sr_subscription_ctx_t **subscription); + + +//////////////////////////////////////////////////////////////////////////////// +// Application-local File Descriptor Watcher API +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Event that has occurred on a monitored file descriptor. + */ +typedef enum sr_fd_event_e { + SR_FD_INPUT_READY = 1, /**< File descriptor is now readable without blocking. */ + SR_FD_OUTPUT_READY = 2, /**< File descriptor is now writable without blocking. */ +} sr_fd_event_t; + +/** + * @brief Action that needs to be taken on a file descriptor. + */ +typedef enum sr_fd_action_s { + SR_FD_START_WATCHING, /**< Start watching for the specified event on the file descriptor. */ + SR_FD_STOP_WATCHING, /**< Stop watching for the specified event on the file descriptor. */ +} sr_fd_action_t; + +/** + * @brief Structure representing a change in the set of file descriptors monitored by the application. + */ +typedef struct sr_fd_change_s { + int fd; /**< File descriptor whose monitored state should be changed. */ + int events; /**< Monitoring events tied to the change (or-ed value of ::sr_fd_event_t). */ + sr_fd_action_t action; /**< Action that is supposed to be performed by application-local file descriptor watcher. */ +} sr_fd_change_t; + +/** + * @brief Callback when the subscription manager is terminated + */ +typedef void (*sr_fd_sm_terminated_cb)(); + +/** + * @brief Initializes application-local file descriptor watcher. + * + * This can be used in those applications that subscribe for changes or providing data in sysrepo, which have their + * own event loop that is capable of monitoring of the events on provided file descriptors. In case that the + * application-local file descriptor watcher is initialized, sysrepo client library won't use a separate thread + * for the delivery of the notifications and for calling the callbacks - they will be called from the main thread of the + * application's event loop (inside of ::sr_fd_event_process calls). + * + * @note Calling this function has global consequences on the behavior of the sysrepo client library within the process + * that called it. It is supposed to be called as the first sysrepo API call within the application. + * + * @param[out] fd Initial file descriptor that is supposed to be monitored for readable events by the application. + * Once there is an event detected on this file descriptor, the application is supposed to call ::sr_fd_event_process. + * + * @param[in] sm_terminate_cb Function to be called when the subscription manager is terminated. If this callback is provided, + * it shall block until all pending events on any file descriptor associated with sysrepo have been handled. I.e., ensure that + * the event loop has called sr_fd_event_process() for all pending events before returning from this callback. If this callback + * doesn't block, errors will be shown in the log. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_fd_watcher_init(int *fd, sr_fd_sm_terminated_cb sm_terminate_cb); + +/** + * @brief Cleans-up the application-local file descriptor watcher previously initiated by ::sr_fd_watcher_init. + * It is supposed to be called as the last sysrepo API within the application. + */ +void sr_fd_watcher_cleanup(); + +/** + * @brief Processes an event that has occurred on one of the file descriptors that the application is monitoring for + * sysrepo client library purposes. As a result of this event, another file descriptors may need to be started or + * stopped monitoring by the application. These are returned as \p fd_change_set array. + * + * @param[in] fd File descriptor where an event occurred. + * @param[in] event Type of the event that occurred on the given file descriptor. + * @param[out] fd_change_set Array of file descriptors that need to be started or stopped monitoring for specified event + * by the application. The application is supposed to free this array after it processes it. + * @param[out] fd_change_set_cnt Count of the items in the \p fd_change_set array. + * + * @return Error code (SR_ERR_OK on success). + */ +int sr_fd_event_process(int fd, sr_fd_event_t event, sr_fd_change_t **fd_change_set, size_t *fd_change_set_cnt); + + +//////////////////////////////////////////////////////////////////////////////// +// Cleanup Routines +//////////////////////////////////////////////////////////////////////////////// + +/** + * @brief Frees ::sr_val_t structure and all memory allocated within it. + * + * @param[in] value Value to be freed. + */ +void sr_free_val(sr_val_t *value); + +/** + * @brief Frees array of ::sr_val_t structures (and all memory allocated + * within of each array element). + * + * @param[in] values Array of values to be freed. + * @param[in] count Number of elements stored in the array. + */ +void sr_free_values(sr_val_t *values, size_t count); + +/** + * @brief Frees ::sr_val_iter_t iterator and all memory allocated within it. + * + * @param[in] iter Iterator to be freed. + */ +void sr_free_val_iter(sr_val_iter_t *iter); + +/** + * @brief Frees ::sr_change_iter_t iterator and all memory allocated within it. + * + * @param[in] iter Iterator to be freed. + */ +void sr_free_change_iter(sr_change_iter_t *iter); + +/** + * @brief Frees array of ::sr_schema_t structures (and all memory allocated + * within of each array element). + * + * @param [in] schemas Array of schemas to be freed. + * @param [in] count Number of elements stored in the array. + */ +void sr_free_schemas(sr_schema_t *schemas, size_t count); + +/** + * @brief Frees sysrepo tree data. + * + * @param[in] tree Tree data to be freed. + */ +void sr_free_tree(sr_node_t *tree); + +/** + * @brief Frees array of sysrepo trees. For each tree, the ::sr_free_tree is called too. + * + * @param[in] trees + * @param[in] count length of array + */ +void sr_free_trees(sr_node_t *trees, size_t count); + +/**@} cl */ + +#ifdef __cplusplus +} +#endif + +#endif /* SYSREPO_H_ */ diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Connection.hpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Connection.hpp new file mode 100644 index 000000000..eb944f72c --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Connection.hpp @@ -0,0 +1,63 @@ +/** + * @file Connection.h + * @author Mislav Novakovic <mislav.novakovic@sartura.hr> + * @brief Sysrepo Connection class header. + * + * @copyright + * Copyright 2016 Deutsche Telekom AG. + * Modifications Copyright (C) 2019 Nokia. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CONNECTION_H +#define CONNECTION_H + +#include <iostream> + +#include "Sysrepo.hpp" +#include "Internal.hpp" + +extern "C" { +#include "../sysrepo.h" +} + +namespace sysrepo { + +/** + * @defgroup classes C++/Python + * @{ + */ + +/** + * @brief Class for wrapping sr_conn_ctx_t. + * @class Connection + */ +class Connection +{ +public: + /** Wrapper for [sr_connect](@ref sr_connect) */ + Connection(const char *app_name, const sr_conn_options_t opts = CONN_DEFAULT); + ~Connection(); + + sr_conn_ctx_t *_conn; + friend class Session; + +private: + sr_conn_options_t _opts; +}; + +/**@} */ +} + +#endif diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Internal.hpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Internal.hpp new file mode 100644 index 000000000..aec62f9f1 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Internal.hpp @@ -0,0 +1,80 @@ +/** + * @file Internal.h + * @author Mislav Novakovic <mislav.novakovic@sartura.hr> + * @brief Sysrepo class header for internal C++ classes. + * + * @copyright + * Copyright 2016 Deutsche Telekom AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERNAL_H +#define INTERNAL_H + +#include <iostream> +#include <memory> + +extern "C" { +#include "../sysrepo.h" +#include "../sysrepo/trees.h" +} + +namespace sysrepo { + +enum class Free_Type { + VAL, + VALS, + VALS_POINTER, + TREE, + TREES, + TREES_POINTER, + SCHEMAS, + SESSION, +}; + +typedef union value_e { + sr_val_t *_val; + sr_val_t **p_vals; + sr_node_t *_tree; + sr_node_t **p_trees; + sr_schema_t *_sch; + sr_session_ctx_t *_sess; +} value_t; + +typedef union count_e { + size_t _cnt; + size_t *p_cnt; +} count_t; + +class Deleter +{ +public: + Deleter(sr_val_t *val); + Deleter(sr_val_t *vals, size_t cnt); + Deleter(sr_val_t **vals, size_t *cnt); + Deleter(sr_node_t *tree); + Deleter(sr_node_t *trees, size_t cnt); + Deleter(sr_node_t **trees, size_t *cnt); + Deleter(sr_schema_t *sch, size_t cnt); + Deleter(sr_session_ctx_t *sess); + ~Deleter(); + +private: + count_t c; + value_t v; + Free_Type _t; +}; + +} +#endif diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Session.hpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Session.hpp new file mode 100644 index 000000000..02d03ed38 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Session.hpp @@ -0,0 +1,245 @@ +/** + * @file Session.h + * @author Mislav Novakovic <mislav.novakovic@sartura.hr> + * @brief Sysrepo Session class header. + * + * @copyright + * Copyright 2016 Deutsche Telekom AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SESSION_H +#define SESSION_H + +#include <iostream> +#include <memory> +#include <map> +#include <vector> + +#include "Sysrepo.hpp" +#include "Internal.hpp" +#include "Struct.hpp" +#include "Tree.hpp" +#include "Connection.hpp" +#include "Session.hpp" + +extern "C" { +#include "../sysrepo.h" +} + +namespace sysrepo { + +/** + * @defgroup classes C++/Python + * @{ + */ + +/** + * @brief Class for wrapping sr_session_ctx_t. + * @class Session + */ +class Session +{ + +public: + /** Wrapper for [sr_session_start](@ref sr_session_start) and [sr_session_start_user](@ref sr_session_start_user) + * if user_name is set.*/ + Session(S_Connection conn, sr_datastore_t datastore = (sr_datastore_t) DS_RUNNING, \ + const sr_sess_options_t opts = SESS_DEFAULT, const char *user_name = nullptr); + /** Wrapper for [sr_session_ctx_t](@ref sr_session_ctx_t), for internal use only.*/ + Session(sr_session_ctx_t *sess, sr_sess_options_t opts = SESS_DEFAULT, S_Deleter deleter = nullptr); + /** Wrapper for [sr_session_stop](@ref sr_session_stop) */ + void session_stop(); + /** Wrapper for [sr_session_switch_ds](@ref sr_session_switch_ds) */ + void session_switch_ds(sr_datastore_t ds); + /** Wrapper for [sr_get_last_error](@ref sr_get_last_error) */ + S_Error get_last_error(); + /** Wrapper for [sr_get_last_errors](@ref sr_get_last_errors) */ + S_Errors get_last_errors(); + /** Wrapper for [sr_list_schemas](@ref sr_list_schemas) */ + S_Yang_Schemas list_schemas(); + /** Wrapper for [sr_get_schema](@ref sr_get_schema) */ + std::string get_schema(const char *module_name, const char *revision, + const char *submodule_name, sr_schema_format_t format); + /** Wrapper for [sr_get_item](@ref sr_get_item) */ + S_Val get_item(const char *xpath); + /** Wrapper for [sr_get_items](@ref sr_get_items) */ + S_Vals get_items(const char *xpath); + /** Wrapper for [sr_get_items_iter](@ref sr_get_items_iter) */ + S_Iter_Value get_items_iter(const char *xpath); + /** Wrapper for [sr_get_item_next](@ref sr_get_item_next) */ + S_Val get_item_next(S_Iter_Value iter); + /** Wrapper for [sr_get_subtree](@ref sr_get_subtree) */ + S_Tree get_subtree(const char *xpath, sr_get_subtree_options_t opts = GET_SUBTREE_DEFAULT); + /** Wrapper for [sr_get_subtrees](@ref sr_get_subtrees) */ + S_Trees get_subtrees(const char *xpath, sr_get_subtree_options_t opts = GET_SUBTREE_DEFAULT); + + /** Wrapper for [sr_node_get_child](@ref sr_node_get_child) */ + S_Tree get_child(S_Tree in_tree); + /** Wrapper for [sr_node_get_next_sibling](@ref sr_node_get_next_sibling) */ + S_Tree get_next_sibling(S_Tree in_tree); + /** Wrapper for [sr_node_get_parent](@ref sr_node_get_parent) */ + S_Tree get_parent(S_Tree in_tree); + + /** Wrapper for [sr_set_item](@ref sr_set_item) */ + void set_item(const char *xpath, S_Val value = nullptr, const sr_edit_options_t opts = EDIT_DEFAULT); + /** Wrapper for [sr_set_item_str](@ref sr_set_item_str) */ + void set_item_str(const char *xpath, const char *value, const sr_edit_options_t opts = EDIT_DEFAULT); + /** Wrapper for [sr_delete_item](@ref sr_delete_item) */ + void delete_item(const char *xpath, const sr_edit_options_t opts = EDIT_DEFAULT); + /** Wrapper for [sr_move_item](@ref sr_move_item) */ + void move_item(const char *xpath, const sr_move_position_t position, const char *relative_item = nullptr); + /** Wrapper for [sr_session_refresh](@ref sr_session_refresh) */ + void refresh(); + /** Wrapper for [sr_validate](@ref sr_validate) */ + void validate(); + /** Wrapper for [sr_commit](@ref sr_commit) */ + void commit(); + /** Wrapper for [sr_lock_datastore](@ref sr_lock_datastore) */ + void lock_datastore(); + /** Wrapper for [sr_unlock_datastore](@ref sr_unlock_datastore) */ + void unlock_datastore(); + /** Wrapper for [sr_lock_module](@ref sr_lock_module) */ + void lock_module(const char *module_name); + /** Wrapper for [sr_unlock_module](@ref sr_unlock_module) */ + void unlock_module(const char *module_name); + /** Wrapper for [sr_discard_changes](@ref sr_discard_changes) */ + void discard_changes(); + /** Wrapper for [sr_copy_config](@ref sr_copy_config) */ + void copy_config(const char *module_name, sr_datastore_t src_datastore, sr_datastore_t dst_datastore); + /** Wrapper for [sr_session_set_options](@ref sr_session_set_options) */ + void set_options(const sr_sess_options_t opts); + /** Wrapper for [sr_get_changes_iter](@ref sr_get_changes_iter) */ + S_Iter_Change get_changes_iter(const char *xpath); + /** Wrapper for [sr_get_change_next](@ref sr_get_change_next) */ + S_Change get_change_next(S_Iter_Change iter); + ~Session(); + + /** Wrapper for [sr_rpc_send](@ref sr_rpc_send) */ + S_Vals rpc_send(const char *xpath, S_Vals input); + /** Wrapper for [sr_rpc_send_tree](@ref sr_rpc_send_tree) */ + S_Trees rpc_send(const char *xpath, S_Trees input); + /** Wrapper for [sr_action_send](@ref sr_action_send) */ + S_Vals action_send(const char *xpath, S_Vals input); + /** Wrapper for [sr_action_send_tree](@ref sr_action_send_tree) */ + S_Trees action_send(const char *xpath, S_Trees input); + /** Wrapper for [sr_event_notif_send](@ref sr_event_notif_send) */ + void event_notif_send(const char *xpath, S_Vals values, const sr_ev_notif_flag_t options = SR_EV_NOTIF_DEFAULT); + /** Wrapper for [sr_event_notif_send_tree](@ref sr_event_notif_send_tree) */ + void event_notif_send(const char *xpath, S_Trees trees, const sr_ev_notif_flag_t options = SR_EV_NOTIF_DEFAULT); + + friend class Subscribe; + +private: + sr_session_ctx_t *_sess; + sr_datastore_t _datastore; + sr_sess_options_t _opts; + S_Connection _conn; + S_Deleter _deleter; +}; + +/** + * @brief Helper class for calling C callbacks, C++ only. + * @class Callback + */ +class Callback +{ +public: + Callback(); + virtual ~Callback(); + + /** Wrapper for [sr_module_change_cb](@ref sr_module_change_cb) callback.*/ + virtual int module_change(S_Session session, const char *module_name, sr_notif_event_t event, void *private_ctx) {return SR_ERR_OK;}; + /** Wrapper for [sr_subtree_change_cb](@ref sr_subtree_change_cb) callback.*/ + virtual int subtree_change(S_Session session, const char *xpath, sr_notif_event_t event, void *private_ctx) {return SR_ERR_OK;}; + /** Wrapper for [sr_module_install_cb](@ref sr_module_install_cb) callback.*/ + virtual void module_install(const char *module_name, const char *revision, sr_module_state_t state, void *private_ctx) {return;}; + /** Wrapper for [sr_feature_enable_cb](@ref sr_feature_enable_cb) callback.*/ + virtual void feature_enable(const char *module_name, const char *feature_name, bool enabled, void *private_ctx) {return;}; + /** Wrapper for [sr_rpc_cb](@ref sr_rpc_cb) callback.*/ + virtual int rpc(const char *xpath, const S_Vals input, S_Vals_Holder output, void *private_ctx) {return SR_ERR_OK;}; + /** Wrapper for [sr_action_cb](@ref sr_action_cb) callback.*/ + virtual int action(const char *xpath, const S_Vals input, S_Vals_Holder output, void *private_ctx) {return SR_ERR_OK;}; + /** Wrapper for [sr_rpc_tree_cb](@ref sr_rpc_tree_cb) callback.*/ + virtual int rpc_tree(const char *xpath, const S_Trees input, S_Trees_Holder output, void *private_ctx) {return SR_ERR_OK;}; + /** Wrapper for [sr_action_tree_cb](@ref sr_action_tree_cb) callback.*/ + virtual int action_tree(const char *xpath, const S_Trees input, S_Trees_Holder output, void *private_ctx) {return SR_ERR_OK;}; + /** Wrapper for [sr_dp_get_items_cb](@ref sr_dp_get_items_cb) callback.*/ + virtual int dp_get_items(const char *xpath, S_Vals_Holder vals, uint64_t request_id, void *private_ctx) {return SR_ERR_OK;}; + /** Wrapper for [sr_event_notif_cb](@ref sr_event_notif_cb) callback.*/ + virtual void event_notif(const sr_ev_notif_type_t notif_type, const char *xpath, S_Vals vals, time_t timestamp, void *private_ctx) {return;}; + /** Wrapper for [sr_event_notif_tree_cb](@ref sr_event_notif_tree_cb) callback.*/ + virtual void event_notif_tree(const sr_ev_notif_type_t notif_type, const char *xpath, S_Trees trees, time_t timestamp, void *private_ctx) {return;}; + Callback *get() {return this;}; + + std::map<const char *, void*> private_ctx; +}; + +/** + * @brief Class for wrapping sr_subscription_ctx_t. + * @class Subscribe + */ +class Subscribe +{ + +public: + /** Wrapper for [sr_subscription_ctx_t](@ref sr_subscription_ctx_t), for internal use only.*/ + Subscribe(S_Session sess); + + /** Wrapper for [sr_module_change_subscribe](@ref sr_module_change_subscribe) */ + void module_change_subscribe(const char *module_name, S_Callback callback, void *private_ctx = nullptr, uint32_t priority = 0, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_subtree_change_subscribe](@ref sr_subtree_change_subscribe) */ + void subtree_change_subscribe(const char *xpath, S_Callback callback, void *private_ctx = nullptr, uint32_t priority = 0, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_module_install_subscribe](@ref sr_module_install_subscribe) */ + void module_install_subscribe(S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_feature_enable_subscribe](@ref sr_feature_enable_subscribe) */ + void feature_enable_subscribe(S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_rpc_subscribe](@ref sr_rpc_subscribe) */ + void rpc_subscribe(const char *xpath, S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_action_subscribe](@ref sr_action_subscribe) */ + void action_subscribe(const char *xpath, S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_event_notif_subscribe_tree](@ref sr_event_notif_subscribe_tree) */ + void event_notif_subscribe_tree(const char *xpath, S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_event_notif_subscribe](@ref sr_event_notif_subscribe) */ + void event_notif_subscribe(const char *xpath, S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_rpc_subscribe_tree](@ref sr_rpc_subscribe_tree) */ + void rpc_subscribe_tree(const char *xpath, S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_action_subscribe_tree](@ref sr_action_subscribe_tree) */ + void action_subscribe_tree(const char *xpath, S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + /** Wrapper for [sr_dp_get_items_subscribe](@ref sr_dp_get_items_subscribe) */ + void dp_get_items_subscribe(const char *xpath, S_Callback callback, void *private_ctx = nullptr, sr_subscr_options_t opts = SUBSCR_DEFAULT); + std::vector<S_Callback > cb_list; + + /** Wrapper for [sr_unsubscribe](@ref sr_unsubscribe) */ + void unsubscribe(); + ~Subscribe(); + + /** SWIG specific, internal use only.*/ + sr_subscription_ctx_t **swig_sub() { return &_sub;}; + /** SWIG specific, internal use only.*/ + sr_session_ctx_t *swig_sess() {return _sess->_sess;}; + /** SWIG specific, internal use only.*/ + std::vector<void*> wrap_cb_l; + /** SWIG specific, internal use only.*/ + void additional_cleanup(void *private_ctx) {return;}; + +private: + sr_subscription_ctx_t *_sub; + S_Session _sess; + S_Deleter sess_deleter; +}; + +/**@} */ +} +#endif diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Struct.hpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Struct.hpp new file mode 100644 index 000000000..7f48d562d --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Struct.hpp @@ -0,0 +1,514 @@ +/** + * @file Struct.h + * @author Mislav Novakovic <mislav.novakovic@sartura.hr> + * @brief Sysrepo class header for C struts. + * + * @copyright + * Copyright 2016 Deutsche Telekom AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef STRUCT_H +#define STRUCT_H + +#include <iostream> +#include <memory> + +#include "Sysrepo.hpp" +#include "Internal.hpp" + +extern "C" { +#include "../sysrepo.h" +} + +namespace sysrepo { + +/** + * @defgroup classes C++/Python + * @{ + */ + +/** + * @brief Class for wrapping sr_data_t. + * @class Data + */ +class Data +{ +public: + /** Wrapper for [sr_data_t](@ref sr_data_t), for internal use only.*/ + Data(sr_data_t data, sr_type_t type, S_Deleter deleter); + ~Data(); + /** Getter for binary data.*/ + char *get_binary() const; + /** Getter for bits.*/ + char *get_bits() const; + /** Getter for bool.*/ + bool get_bool() const; + /** Getter for decimal64.*/ + double get_decimal64() const; + /** Getter for enum.*/ + char *get_enum() const; + /** Getter for identityref.*/ + char *get_identityref() const; + /** Getter for instanceid.*/ + char *get_instanceid() const; + /** Getter for int8.*/ + int8_t get_int8() const; + /** Getter for int16.*/ + int16_t get_int16() const; + /** Getter for int32.*/ + int32_t get_int32() const; + /** Getter for int64.*/ + int64_t get_int64() const; + /** Getter for string.*/ + char *get_string() const; + /** Getter for uint8.*/ + uint8_t get_uint8() const; + /** Getter for uint16.*/ + uint16_t get_uint16() const; + /** Getter for uint32.*/ + uint32_t get_uint32() const; + /** Getter for uint64.*/ + uint64_t get_uint64() const; + +private: + sr_data_t _d; + sr_type_t _t; + S_Deleter _deleter; +}; + +/** + * @brief Class for wrapping sr_val_t. + * @class Val + */ +class Val +{ +public: + /** Constructor for an empty value.*/ + Val(); + /** Wrapper for [sr_val_t](@ref sr_val_t).*/ + Val(sr_val_t *val, S_Deleter deleter); + /** Constructor for string value, type can be SR_STRING_T, SR_BINARY_T, SR_BITS_T, SR_ENUM_T, + * SR_IDENTITYREF_T and SR_INSTANCEID_T.*/ + Val(const char *val, sr_type_t type = SR_STRING_T); + /** Constructor for bool value.*/ + Val(bool bool_val, sr_type_t type = SR_BOOL_T); + /** Constructor for decimal64 value.*/ + Val(double decimal64_val); + /** Constructor for int8 value, C++ only.*/ + Val(int8_t int8_val, sr_type_t type); + /** Constructor for int16 value, C++ only.*/ + Val(int16_t int16_val, sr_type_t type); + /** Constructor for int32 value, C++ only.*/ + Val(int32_t int32_val, sr_type_t type); + /** Constructor for int64 value, type can be SR_INT8_T, SR_INT16_T, SR_INT32_T, + * SR_INT64_T, SR_UINT8_T, SR_UINT16_T and SR_UINT32_T,*/ + Val(int64_t int64_val, sr_type_t type); + /** Constructor for uint8 value, C++ only.*/ + Val(uint8_t uint8_val, sr_type_t type); + /** Constructor for uint16 value, C++ only.*/ + Val(uint16_t uint16_val, sr_type_t type); + /** Constructor for uint32 value, C++ only.*/ + Val(uint32_t uint32_val, sr_type_t type); + /** Constructor for uint64 value, C++ only.*/ + Val(uint64_t uint64_val, sr_type_t type); + ~Val(); + /** Setter for string value, type can be SR_STRING_T, SR_BINARY_T, SR_BITS_T, SR_ENUM_T, + * SR_IDENTITYREF_T and SR_INSTANCEID_T.*/ + void set(const char *xpath, const char *val, sr_type_t type = SR_STRING_T); + /** Setter for bool value.*/ + void set(const char *xpath, bool bool_val, sr_type_t type = SR_BOOL_T); + /** Setter for decimal64 value.*/ + void set(const char *xpath, double decimal64_val); + /** Setter for int8 value, C++ only.*/ + void set(const char *xpath, int8_t int8_val, sr_type_t type); + /** Setter for int16 value, C++ only.*/ + void set(const char *xpath, int16_t int16_val, sr_type_t type); + /** Setter for int32 value, C++ only.*/ + void set(const char *xpath, int32_t int32_val, sr_type_t type); + /** Setter for int64 value, type can be SR_INT8_T, SR_INT16_T, SR_INT32_T, + * SR_INT64_T, SR_UINT8_T, SR_UINT16_T and SR_UINT32_T,*/ + void set(const char *xpath, int64_t int64_val, sr_type_t type); + /** Setter for uint8 value, C++ only.*/ + void set(const char *xpath, uint8_t uint8_val, sr_type_t type); + /** Setter for uint16 value, C++ only.*/ + void set(const char *xpath, uint16_t uint16_val, sr_type_t type); + /** Setter for uint32 value, C++ only.*/ + void set(const char *xpath, uint32_t uint32_val, sr_type_t type); + /** Setter for uint64 value, C++ only.*/ + void set(const char *xpath, uint64_t uint64_val, sr_type_t type); + /** Getter for xpath.*/ + char *xpath() {return _val->xpath;}; + /** Setter for xpath.*/ + void xpath_set(char *xpath); + /** Getter for type.*/ + sr_type_t type() {return _val->type;}; + /** Getter for dflt.*/ + bool dflt() {return _val->dflt;}; + /** Setter for dflt.*/ + void dflt_set(bool data) {_val->dflt = data;}; + /** Getter for data.*/ + S_Data data() {S_Data data(new Data(_val->data, _val->type, _deleter)); return data;}; + /** Wrapper for [sr_print_val_mem](@ref sr_print_val_mem) */ + std::string to_string(); + /** Wrapper for [sr_val_to_string](@ref sr_val_to_string) */ + std::string val_to_string(); + /** Wrapper for [sr_dup_val](@ref sr_dup_val) */ + S_Val dup(); + + friend class Session; + friend class Subscribe; + +private: + sr_val_t *_val; + S_Deleter _deleter; +}; + +/** + * @brief Class for wrapping sr_val_t array. + * @class Vals + */ +class Vals +{ +public: + /** Wrapper for [sr_val_t](@ref sr_val_t) array, internal use only.*/ + Vals(const sr_val_t *vals, const size_t cnt, S_Deleter deleter = nullptr); + /** Wrapper for [sr_val_t](@ref sr_val_t) array, internal use only.*/ + Vals(sr_val_t **vals, size_t *cnt, S_Deleter deleter = nullptr); + /** Wrapper for [sr_val_t](@ref sr_val_t) array, create n-array.*/ + Vals(size_t cnt); + /** Constructor for an empty [sr_val_t](@ref sr_val_t) array.*/ + Vals(); + ~Vals(); + /** Getter for [sr_val_t](@ref sr_val_t), get the n-th element in array.*/ + S_Val val(size_t n); + /** Getter for array size */ + size_t val_cnt() {return _cnt;}; + /** Wrapper for [sr_dup_values](@ref sr_dup_values) */ + S_Vals dup(); + + friend class Session; + friend class Subscribe; + +private: + size_t _cnt; + sr_val_t *_vals; + S_Deleter _deleter; +}; + +/** + * @brief Class for wrapping sr_val_t in callbacks. + * @class Vals_holder + */ +class Vals_Holder +{ +public: + /** Wrapper for [sr_val_t](@ref sr_val_t) array, used only in callbacks.*/ + Vals_Holder(sr_val_t **vals, size_t *cnt); + /** Create [sr_val_t](@ref sr_val_t) array of n size.*/ + S_Vals allocate(size_t n); + ~Vals_Holder(); + +private: + size_t *p_cnt; + sr_val_t **p_vals; + bool _allocate; +}; + +/** + * @brief Class for wrapping sr_val_iter_t. + * @class Val_Iter + */ +class Val_Iter +{ +public: + /** Wrapper for [sr_val_iter_t](@ref sr_val_iter_t).*/ + Val_Iter(sr_val_iter_t *iter = nullptr); + ~Val_Iter(); + /** Getter for [sr_val_iter_t](@ref sr_val_iter_t).*/ + sr_val_iter_t *iter() {return _iter;}; + +private: + sr_val_iter_t *_iter; +}; + +/** + * @brief Class for wrapping sr_change_iter_t. + * @class Change_Iter + */ +class Change_Iter +{ +public: + /** Wrapper for [sr_change_iter_t](@ref sr_change_iter_t).*/ + Change_Iter(sr_change_iter_t *iter = nullptr); + ~Change_Iter(); + /** Getter for [sr_change_iter_t](@ref sr_change_iter_t).*/ + sr_change_iter_t *iter() {return _iter;}; + +private: + sr_change_iter_t *_iter; +}; + +/** + * @brief Class for wrapping sr_error_info_t. + * @class Error + */ +class Error +{ +public: + /** Constructor for an empty [sr_error_info_t](@ref sr_error_info_t).*/ + Error(); + /** Wrapper for [sr_error_info_t](@ref sr_error_info_t).*/ + Error(const sr_error_info_t *info); + ~Error(); + /** Getter for message.*/ + const char *message() const {if (_info) return _info->message; else return nullptr;}; + /** Getter for xpath.*/ + const char *xpath() const {if (_info) return _info->xpath; else return nullptr;}; + + friend class Session; + +private: + const sr_error_info_t *_info; +}; + +/** + * @brief Class for wrapping sr_error_info_t array. + * @class Errors + */ +class Errors +{ +public: + /** Constructor for an empty [sr_error_info_t](@ref sr_error_info_t) array.*/ + Errors(); + ~Errors(); + /** Getter for [sr_error_info_t](@ref sr_error_info_t), get the n-th element in array.*/ + S_Error error(size_t n); + /** Getter for array size.*/ + size_t error_cnt() {return _cnt;}; + + friend class Session; + +private: + size_t _cnt; + const sr_error_info_t *_info; +}; + +/** + * @brief Class for wrapping sr_sch_revision_t array. + * @class Schema_Revision + */ +class Schema_Revision +{ +public: + /** Wrapper for [sr_sch_revision_t](@ref sr_sch_revision_t).*/ + Schema_Revision(sr_sch_revision_t rev); + ~Schema_Revision(); + /** Getter for revision.*/ + const char *revision() const {return _rev.revision;}; + /** Getter for file_path_yang.*/ + const char *file_path_yang() const {return _rev.file_path_yang;}; + /** Getter for file_path_yin.*/ + const char *file_path_yin() const {return _rev.file_path_yin;}; + +private: + sr_sch_revision_t _rev; +}; + +/** + * @brief Class for wrapping sr_sch_submodule_t. + * @class Schema_Submodule + */ +class Schema_Submodule +{ +public: + /** Wrapper for [sr_sch_submodule_t](@ref sr_sch_submodule_t).*/ + Schema_Submodule(sr_sch_submodule_t sub, S_Deleter deleter); + ~Schema_Submodule(); + /** Getter for submodule_name.*/ + const char *submodule_name() const {return _sub.submodule_name;}; + /** Getter for revision.*/ + S_Schema_Revision revision(); + +private: + sr_sch_submodule_t _sub; + S_Deleter _deleter; +}; + +/** + * @brief Class for wrapping sr_schema_t. + * @class Yang_Schema + */ +class Yang_Schema +{ +public: + /** Wrapper for [sr_schema_t](@ref sr_schema_t).*/ + Yang_Schema(sr_schema_t *sch, S_Deleter deleter); + ~Yang_Schema(); + /** Getter for module_name.*/ + const char *module_name() const {return _sch->module_name;}; + /** Getter for ns.*/ + const char *ns() const {return _sch->ns;}; + /** Getter for prefix.*/ + const char *prefix() const {return _sch->prefix;}; + /** Getter for implemented.*/ + bool implemented() const {return _sch->implemented;}; + /** Getter for revision.*/ + S_Schema_Revision revision(); + /** Getter for submodule.*/ + S_Schema_Submodule submodule(size_t n); + /** Getter for submodule_cnt.*/ + size_t submodule_cnt() const {return _sch->submodule_count;}; + /** Getter for enabled_features.*/ + char *enabled_features(size_t n); + /** Getter for enabled_features_cnt.*/ + size_t enabled_feature_cnt() const {return _sch->enabled_feature_cnt;}; + + friend class Session; + +private: + sr_schema_t *_sch; + S_Deleter _deleter; +}; + +/** + * @brief Class for wrapping sr_schema_t array. + * @class Yang_Schemas + */ +class Yang_Schemas +{ +public: + /** Constructor for an empty [sr_schema_t](@ref sr_schema_t) array.*/ + Yang_Schemas(); + ~Yang_Schemas(); + /** Getter for [sr_schema_t](@ref sr_schema_t) array, get the n-th element in array.*/ + S_Yang_Schema schema(size_t n); + /** Getter for array size.*/ + size_t schema_cnt() const {return _cnt;}; + + friend class Session; + +private: + size_t _cnt; + sr_schema_t *_sch; + S_Deleter _deleter; +}; + +/** + * @brief Class for wrapping sr_fd_change_t. + * @class Fd_Change + */ +class Fd_Change +{ +public: + /** Wrapper for [sr_fd_change_t](@ref sr_fd_change_t).*/ + Fd_Change(sr_fd_change_t *ch); + ~Fd_Change(); + /** Getter for fd.*/ + int fd() const {return _ch->fd;}; + /** Getter for events.*/ + int events() const {return _ch->events;}; + /** Getter for action.*/ + sr_fd_action_t action() const {return _ch->action;}; + +private: + sr_fd_change_t *_ch; +}; + +/** + * @brief Class for wrapping sr_fd_change_t array. + * @class Fd_Changes + */ +class Fd_Changes +{ +public: + /** Wrapper for [sr_fd_change_t](@ref sr_fd_change_t) array.*/ + Fd_Changes(sr_fd_change_t *ch, size_t cnt); + ~Fd_Changes(); + /** Getter for [sr_fd_change_t](@ref sr_fd_change_t) array, get the n-th element in array.*/ + S_Fd_Change fd_change(size_t n); + +private: + sr_fd_change_t *_ch; + size_t _cnt; +}; + +/** + * @brief Class for wrapping sr_val_iter_t. + * @class Fd_Changes + */ +class Iter_Value +{ + +public: + /** Wrapper for [sr_val_iter_t](@ref sr_val_iter_t).*/ + Iter_Value(sr_val_iter_t *iter = nullptr); + ~Iter_Value(); + /** Setter for [sr_val_iter_t](@ref sr_val_iter_t).*/ + void Set(sr_val_iter_t *iter); + + friend class Session; + +private: + sr_val_iter_t *_iter; +}; + +/** + * @brief Class for wrapping sr_change_iter_t. + * @class Iter_Change + */ +class Iter_Change +{ + +public: + /** Wrapper for [sr_change_iter_t](@ref sr_change_iter_t).*/ + Iter_Change(sr_change_iter_t *iter = nullptr); + ~Iter_Change(); + + friend class Session; + +private: + sr_change_iter_t *_iter; +}; + +/** + * @brief Class for wrapping sr_change_oper_t. + * @class Change + */ +class Change +{ +public: + /** Constructor for an empty [sr_change_oper_t](@ref sr_change_oper_t).*/ + Change(); + ~Change(); + /** Getter for sr_change_oper_t.*/ + sr_change_oper_t oper() {return _oper;}; + /** Getter for new sr_val_t.*/ + S_Val new_val(); + /** Getter for old sr_val_t.*/ + S_Val old_val(); + + friend class Session; + +private: + sr_change_oper_t _oper; + sr_val_t *_new; + sr_val_t *_old; + S_Deleter _deleter_new; + S_Deleter _deleter_old; +}; + +/**@} */ +} +#endif diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Sysrepo.hpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Sysrepo.hpp new file mode 100644 index 000000000..d3b76483f --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Sysrepo.hpp @@ -0,0 +1,177 @@ +/** + * @file Sysrepo.h + * @author Mislav Novakovic <mislav.novakovic@sartura.hr> + * @brief Sysrepo Sysrepo class header. + * + * @copyright + * Copyright 2016 Deutsche Telekom AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSREPO_H +#define SYSREPO_H + +#include <iostream> +#include <memory> +#include <stdexcept> + +#include "Internal.hpp" + +extern "C" { +#include "../sysrepo.h" +} + +namespace sysrepo { + +/** + * @defgroup classes C++/Python + * @{ + */ + +class Iter_Value; +class Iter_Change; +class Session; +class Subscribe; +class Connection; +class Operation; +class Schema_Content; +class Error; +class Errors; +class Data; +class Schema_Revision; +class Schema_Submodule; +class Yang_Schema; +class Yang_Schemas; +class Fd_Change; +class Fd_Changes; +class Val; +class Vals_Holder; +class Vals; +class Tree; +class Trees; +class Trees_Holder; +class Xpath_Ctx; +class Logs; +class Change; +class Counter; +class Callback; +class Deleter; + +#ifdef SWIGLUA +using S_Iter_Value = Iter_Value*; +using S_Iter_Change = Iter_Change*; +using S_Session = Session*; +using S_Subscribe = Subscribe*; +using S_Connection = Connection*; +using S_Operation = Operation*; +using S_Schema_Content = Schema_Content*; +using S_Error = Error*; +using S_Errors = Errors*; +using S_Data = Data*; +using S_Schema_Revision = Schema_Revision*; +using S_Schema_Submodule = Schema_Submodule*; +using S_Yang_Schema = Yang_Schema*; +using S_Yang_Schemas = Yang_Schemas*; +using S_Fd_Change = Fd_Change*; +using S_Fd_Changes = Fd_Changes*; +using S_Val = Val*; +using S_Vals_Holder = Vals_Holder*; +using S_Vals = Vals*; +using S_Tree = Tree*; +using S_Trees = Trees*; +using S_Trees_Holder = Trees_Holder*; +using S_Xpath_Ctx = Xpath_Ctx*; +using S_Logs = Logs*; +using S_Change = Change*; +using S_Counter = Counter*; +using S_Callback = Callback*; +#else +using S_Iter_Value = std::shared_ptr<Iter_Value>; +using S_Iter_Change = std::shared_ptr<Iter_Change>; +using S_Session = std::shared_ptr<Session>; +using S_Subscribe = std::shared_ptr<Subscribe>; +using S_Connection = std::shared_ptr<Connection>; +using S_Operation = std::shared_ptr<Operation>; +using S_Schema_Content = std::shared_ptr<Schema_Content>; +using S_Error = std::shared_ptr<Error>; +using S_Errors = std::shared_ptr<Errors>; +using S_Data = std::shared_ptr<Data>; +using S_Schema_Revision = std::shared_ptr<Schema_Revision>; +using S_Schema_Submodule = std::shared_ptr<Schema_Submodule>; +using S_Yang_Schema = std::shared_ptr<Yang_Schema>; +using S_Yang_Schemas = std::shared_ptr<Yang_Schemas>; +using S_Fd_Change = std::shared_ptr<Fd_Change>; +using S_Fd_Changes = std::shared_ptr<Fd_Changes>; +using S_Val = std::shared_ptr<Val>; +using S_Vals_Holder = std::shared_ptr<Vals_Holder>; +using S_Vals = std::shared_ptr<Vals>; +using S_Tree = std::shared_ptr<Tree>; +using S_Trees = std::shared_ptr<Trees>; +using S_Trees_Holder = std::shared_ptr<Trees_Holder>; +using S_Xpath_Ctx = std::shared_ptr<Xpath_Ctx>; +using S_Logs = std::shared_ptr<Logs>; +using S_Change = std::shared_ptr<Change>; +using S_Counter = std::shared_ptr<Counter>; +using S_Callback = std::shared_ptr<Callback>; +using S_Deleter = std::shared_ptr<Deleter>; +#endif + +/* this is a workaround for python not recognizing + * enum's in function default values */ +static const int SESS_DEFAULT = SR_SESS_DEFAULT; +static const int DS_RUNNING = SR_DS_RUNNING; +static const int EDIT_DEFAULT = SR_EDIT_DEFAULT; +static const int CONN_DEFAULT = SR_CONN_DEFAULT; +static const int GET_SUBTREE_DEFAULT = SR_GET_SUBTREE_DEFAULT; +static const int SUBSCR_DEFAULT = SR_SUBSCR_DEFAULT; + +#ifdef SWIG +// https://github.com/swig/swig/issues/1158 +void throw_exception (int error); +#else +void throw_exception [[noreturn]] (int error); +#endif + +/** + * @brief Class for wrapping sr_error_t. + * @class sysrepo_exception + */ +class sysrepo_exception : public std::runtime_error +{ +public: + explicit sysrepo_exception(const sr_error_t error_code); + virtual ~sysrepo_exception() override; + sr_error_t error_code() const; +private: + sr_error_t m_error_code; +}; + +/** + * @brief Class for wrapping ref sr_log_level_t. + * @class Logs + */ +class Logs +{ +public: + Logs(); + ~Logs(); + /** Wrapper for [sr_log_stderr](@ref sr_log_stderr) */ + void set_stderr(sr_log_level_t log_level); + /** Wrapper for [sr_log_syslog](@ref sr_log_syslog) */ + void set_syslog(sr_log_level_t log_level); +}; + +/**@} */ +} +#endif diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Tree.hpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Tree.hpp new file mode 100644 index 000000000..31f3abd47 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Tree.hpp @@ -0,0 +1,176 @@ +/** + * @file Trees.h + * @author Mislav Novakovic <mislav.novakovic@sartura.hr> + * @brief Sysrepo class header for C header trees.h. + * + * @copyright + * Copyright 2016 Deutsche Telekom AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TREE_H +#define TREE_H + +#include "Sysrepo.hpp" +#include "Struct.hpp" + +extern "C" { +#include "../sysrepo.h" +#include "../sysrepo/trees.h" +} + +namespace sysrepo { + +/** + * @defgroup classes C++/Python + * @{ + */ + +/** + * @brief Class for wrapping sr_node_t. + * @class Tree + */ +class Tree +{ +public: + /** Constructor for an empty [sr_node_t](@ref sr_node_t).*/ + Tree(); + /** Wrapper for [sr_new_tree](@ref sr_new_tree).*/ + Tree(const char *root_name, const char *root_module_name); + /** Wrapper for [sr_node_t](@ref sr_node_t).*/ + Tree(sr_node_t *tree, S_Deleter deleter); + /** Wrapper for [sr_dup_tree](@ref sr_dup_tree).*/ + S_Tree dup(); + /** Get the node value.*/ + S_Tree node(); + /** Getter for name.*/ + char *name() {return _node->name;}; + /** Getter for type.*/ + sr_type_t type() {return _node->type;}; + /** Getter for dflt.*/ + bool dflt() {return _node->dflt;}; + /** Getter for data.*/ + S_Data data() {S_Data data(new Data(_node->data, _node->type, _deleter)); return data;}; + /** Getter for module_name.*/ + char *module_name() {return _node->module_name;}; + /** Getter for parent.*/ + S_Tree parent(); + /** Getter for next.*/ + S_Tree next(); + /** Getter for prev.*/ + S_Tree prev(); + /** Getter for first_child.*/ + S_Tree first_child(); + /** Getter for last_child.*/ + S_Tree last_child(); + /** Wrapper for [sr_print_tree_mem](@ref sr_print_tree_mem).*/ + std::string to_string(int depth_limit); + /** Wrapper for [sr_print_val_mem](@ref sr_print_val_mem).*/ + std::string value_to_string(); + /** Wrapper for [sr_node_set_name](@ref sr_node_set_name).*/ + void set_name(const char *name); + /** Wrapper for [sr_node_set_module](@ref sr_node_set_module).*/ + void set_module(const char *module_name); + /** Wrapper for [sr_node_set_str_data](@ref sr_node_set_str_data).*/ + void set_str_data(sr_type_t type, const char *string_val); + /** Wrapper for [sr_node_add_child](@ref sr_node_add_child).*/ + void add_child(const char *child_name, const char *child_module_name, S_Tree child); + /** Setter for string value, type can be SR_STRING_T, SR_BINARY_T, SR_BITS_T, SR_ENUM_T, + * SR_IDENTITYREF_T and SR_INSTANCEID_T.*/ + void set(const char *val, sr_type_t type = SR_STRING_T); + /** Setter for bool value.*/ + void set(bool bool_val, sr_type_t type = SR_BOOL_T); + /** Setter for decimal64 value.*/ + void set(double decimal64_val); + /** Setter for int8 value, C++ only.*/ + void set(int8_t int8_val, sr_type_t type); + /** Setter for int16 value, C++ only.*/ + void set(int16_t int16_val, sr_type_t type); + /** Setter for int32 value, C++ only.*/ + void set(int32_t int32_val, sr_type_t type); + /** Setter for int64 value, type can be SR_INT8_T, SR_INT16_T, SR_INT32_T, + * SR_INT64_T, SR_UINT8_T, SR_UINT16_T and SR_UINT32_T,*/ + void set(int64_t int64_val, sr_type_t type); + /** Setter for uint8 value, C++ only.*/ + void set(uint8_t uint8_val, sr_type_t type); + /** Setter for uint16 value, C++ only.*/ + void set(uint16_t uint16_val, sr_type_t type); + /** Setter for uint32 value, C++ only.*/ + void set(uint32_t uint32_val, sr_type_t type); + /** Setter for uint64 value, C++ only.*/ + void set(uint64_t uint64_val, sr_type_t type); + ~Tree(); + + friend class Session; + friend class Subscribe; + +private: + sr_node_t *_node; + S_Deleter _deleter; +}; + +/** + * @brief Class for wrapping sr_node_t array. + * @class Trees + */ +class Trees +{ +public: + /** Constructor for an empty [sr_node_t](@ref sr_node_t) array.*/ + Trees(); + /** Wrapper for [sr_node_t](@ref sr_node_t) array, create n-array.*/ + Trees(size_t n); + /** Wrapper for [sr_node_t](@ref sr_node_t) array, internal use only.*/ + Trees(sr_node_t **trees, size_t *cnt, S_Deleter deleter = nullptr); + /** Wrapper for [sr_node_t](@ref sr_node_t) array, internal use only.*/ + Trees(const sr_node_t *trees, const size_t n, S_Deleter deleter = nullptr); + /** Getter for [sr_node_t](@ref sr_node_t), get the n-th element in array.*/ + S_Tree tree(size_t n); + /** Wrapper for [sr_dup_trees](@ref sr_dup_trees) */ + S_Trees dup(); + /** Getter for array size */ + size_t tree_cnt() {return _cnt;}; + ~Trees(); + + friend class Session; + friend class Subscribe; + +private: + size_t _cnt; + sr_node_t *_trees; + S_Deleter _deleter; +}; + +/** + * @brief Class for wrapping sr_node_t in callbacks. + * @class Trees_Holder + */ +class Trees_Holder +{ +public: + /** Wrapper for [sr_node_t](@ref sr_node_t) array, used only in callbacks.*/ + Trees_Holder(sr_node_t **trees, size_t *cnt); + /** Create [sr_node_t](@ref sr_node_t) array of n size.*/ + S_Trees allocate(size_t n); + ~Trees_Holder(); + +private: + size_t *p_cnt; + sr_node_t **p_trees; + bool _allocate; +}; + +/**@} */ +} +#endif diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Xpath.hpp b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Xpath.hpp new file mode 100644 index 000000000..4406134da --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/Xpath.hpp @@ -0,0 +1,97 @@ +/** + * @file Xpath.h + * @author Mislav Novakovic <mislav.novakovic@sartura.hr> + * @brief Sysrepo class header for C header xpath_utils.h. + * + * @copyright + * Copyright 2016 Deutsche Telekom AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef XPATH_H +#define XPATH_H + +#include <iostream> + +extern "C" { +#include "../sysrepo/xpath.h" +} + +namespace sysrepo { + +/** + * @defgroup classes C++/Python + * @{ + */ + +/** + * @brief Class for wrapping sr_xpath_ctx_t. + * @class Xpath_Ctx + */ +class Xpath_Ctx +{ +public: + /** Constructor for an empty [sr_xpath_ctx_t](@ref sr_xpath_ctx_t).*/ + Xpath_Ctx(); + /** Getter for begining.*/ + char *begining() {if (_state != nullptr) return _state->begining; return nullptr;}; + /** Getter for current_node.*/ + char *current_node() {if (_state != nullptr) return _state->current_node; return nullptr;}; + /** Getter for replaced_position.*/ + char *replaced_position() {if (_state != nullptr) return _state->replaced_position; return nullptr;}; + /** Getter for replaced_char.*/ + char replaced_char() {if (_state != nullptr) return _state->replaced_char; return (char) 0;}; + ~Xpath_Ctx(); + /** Wrapper for [sr_xpath_next_node](@ref sr_xpath_next_node).*/ + char *next_node(char *xpath) {return sr_xpath_next_node(xpath, _state);}; + /** Wrapper for [sr_xpath_next_node_with_ns](@ref sr_xpath_next_node_with_ns).*/ + char *next_node_with_ns(char *xpath) {return sr_xpath_next_node_with_ns(xpath, _state);}; + /** Wrapper for [sr_xpath_next_key_name](@ref sr_xpath_next_key_name).*/ + char *next_key_name(char *xpath) {return sr_xpath_next_key_name(xpath, _state);}; + /** Wrapper for [sr_xpath_next_key_value](@ref sr_xpath_next_key_value).*/ + char *next_key_value(char *xpath) {return sr_xpath_next_key_value(xpath, _state);}; + /** Wrapper for [sr_xpath_node](@ref sr_xpath_node).*/ + char *node(char *xpath, const char *node_name) {return sr_xpath_node(xpath, node_name, _state);}; + /** Wrapper for [sr_xpath_node_rel](@ref sr_xpath_node_rel).*/ + char *node_rel(char *xpath, const char *node_name) {return sr_xpath_node_rel(xpath, node_name, _state);}; + /** Wrapper for [sr_xpath_node_idx](@ref sr_xpath_node_idx).*/ + char *node_idx(char *xpath, size_t index) {return sr_xpath_node_idx(xpath, index, _state);}; + /** Wrapper for [sr_xpath_node_idx_rel](@ref sr_xpath_node_idx_rel).*/ + char *node_idx_rel(char *xpath, size_t index) {return sr_xpath_node_idx_rel(xpath, index, _state);}; + /** Wrapper for [sr_xpath_node_key_value](@ref sr_xpath_node_key_value).*/ + char *node_key_value(char *xpath, const char *key) {return sr_xpath_node_key_value(xpath, key, _state);}; + /** Wrapper for [sr_xpath_node_key_value_idx](@ref sr_xpath_node_key_value_idx).*/ + char *node_key_value_idx(char *xpath, size_t index) {return sr_xpath_node_key_value_idx(xpath, index, _state);}; + /** Wrapper for [sr_xpath_key_value](@ref sr_xpath_key_value).*/ + char *key_value(char *xpath, const char *node_name, const char *key_name) { + return sr_xpath_key_value(xpath, node_name, key_name, _state);}; + /** Wrapper for [sr_xpath_key_value_idx](@ref sr_xpath_key_value_idx).*/ + char *key_value_idx(char *xpath, size_t node_index, size_t key_index) { + return sr_xpath_key_value_idx(xpath, node_index, key_index, _state);}; + /** Wrapper for [sr_xpath_last_node](@ref sr_xpath_last_node).*/ + char *last_node(char *xpath) {return sr_xpath_last_node(xpath, _state);}; + /** Wrapper for [sr_xpath_node_name](@ref sr_xpath_node_name).*/ + char *node_name(const char *xpath) {return sr_xpath_node_name(xpath);}; + /** Wrapper for [sr_xpath_node_name_eq](@ref sr_xpath_node_name_eq).*/ + bool node_name_eq(const char *xpath, const char *node_str) {return sr_xpath_node_name_eq(xpath, node_str);}; + /** Wrapper for [sr_xpath_recover](@ref sr_xpath_recover).*/ + void recover() {return sr_xpath_recover(_state);}; + +private: + sr_xpath_ctx_t *_state; +}; + +/**@} */ +} +#endif diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/plugins.h b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/plugins.h new file mode 100644 index 000000000..3c4efc9a9 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/plugins.h @@ -0,0 +1,139 @@ +/** + * @file plugins.h + * @author Rastislav Szabo <raszabo@cisco.com>, Lukas Macko <lmacko@cisco.com> + * @brief Sysrepo helpers for plugin integrations. + * + * @copyright + * Copyright 2016 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSREPO_PLUGINS_H_ +#define SYSREPO_PLUGINS_H_ + +#include <stdio.h> +#include <stdint.h> +#include <errno.h> +#include <string.h> +#include <syslog.h> + +#include <sysrepo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup plugin_utils Plugin Utilities + * @{ + * + * @brief Utilities that expand sysrepo API aimed for sysrepo plugins. + * + * The provided features are: logging macros. + */ + +/** Prints an error message (with format specifiers). */ +#define SRP_LOG_ERR(MSG, ...) SRP_LOG__INTERNAL(SR_LL_ERR, MSG, __VA_ARGS__) +/** Prints an error message. */ +#define SRP_LOG_ERR_MSG(MSG) SRP_LOG__INTERNAL(SR_LL_ERR, MSG "%s", "") + +/** Prints a warning message (with format specifiers). */ +#define SRP_LOG_WRN(MSG, ...) SRP_LOG__INTERNAL(SR_LL_WRN, MSG, __VA_ARGS__) +/** Prints a warning message. */ +#define SRP_LOG_WRN_MSG(MSG) SRP_LOG__INTERNAL(SR_LL_WRN, MSG "%s", "") + +/** Prints an informational message (with format specifiers). */ +#define SRP_LOG_INF(MSG, ...) SRP_LOG__INTERNAL(SR_LL_INF, MSG, __VA_ARGS__) +/** Prints an informational message. */ +#define SRP_LOG_INF_MSG(MSG) SRP_LOG__INTERNAL(SR_LL_INF, MSG "%s", "") + +/** Prints a development debug message (with format specifiers). */ +#define SRP_LOG_DBG(MSG, ...) SRP_LOG__INTERNAL(SR_LL_DBG, MSG, __VA_ARGS__) +/** Prints a development debug message. */ +#define SRP_LOG_DBG_MSG(MSG) SRP_LOG__INTERNAL(SR_LL_DBG, MSG "%s", "") + +/**@} plugin_utils */ + + +//////////////////////////////////////////////////////////////////////////////// +// Internal macros (not intended to be used directly) +//////////////////////////////////////////////////////////////////////////////// + +#ifdef NDEBUG + #define SRP_LOG_PRINT_FUNCTION_NAMES (0) /**< Do not print function names in messages */ +#else + #define SRP_LOG_PRINT_FUNCTION_NAMES (1) /**< Every message will include the function that generated the output */ +#endif + +extern volatile uint8_t sr_ll_stderr; /**< Holds current level of stderr debugs. */ +extern volatile uint8_t sr_ll_syslog; /**< Holds current level of syslog debugs. */ + +/** + * @brief Matching log level to message beginning + */ +#define SRP_LOG__LL_STR(LL) \ + ((SR_LL_DBG == LL) ? "DBG" : \ + (SR_LL_INF == LL) ? "INF" : \ + (SR_LL_WRN == LL) ? "WRN" : \ + "ERR") + +/** + * @brief Matching log level to message macros + */ +#define SRP_LOG__LL_FACILITY(LL) \ + ((SR_LL_DBG == LL) ? LOG_DEBUG : \ + (SR_LL_INF == LL) ? LOG_INFO : \ + (SR_LL_WRN == LL) ? LOG_WARNING : \ + LOG_ERR) + +#if SRP_LOG_PRINT_FUNCTION_NAMES +/** + * @brief Syslog output macro with function names. + */ +#define SRP_LOG__SYSLOG(LL, MSG, ...) \ + syslog(SRP_LOG__LL_FACILITY(LL), "[%s] (%s:%d) " MSG, SRP_LOG__LL_STR(LL), __func__, __LINE__, __VA_ARGS__); +/** + * @brief Stderr output macro with function names. + */ +#define SRP_LOG__STDERR(LL, MSG, ...) \ + fprintf(stderr, "[%s] (%s:%d) " MSG "\n", SRP_LOG__LL_STR(LL), __func__, __LINE__, __VA_ARGS__); +#else +/** + * @brief Syslog output macro without function names. + */ +#define SRP_LOG__SYSLOG(LL, MSG, ...) \ + syslog(SRP_LOG__LL_FACILITY(LL), "[%s] " MSG, SRP_LOG__LL_STR(LL), __VA_ARGS__); +/** + * @brief Stderr output macro without function names. + */ +#define SRP_LOG__STDERR(LL, MSG, ...) \ + fprintf(stderr, "[%s] " MSG "\n", SRP_LOG__LL_STR(LL), __VA_ARGS__); +#endif + +/** + * @brief Internal outptu macro. + */ +#define SRP_LOG__INTERNAL(LL, MSG, ...) \ + do { \ + if (sr_ll_stderr >= LL) \ + SRP_LOG__STDERR(LL, MSG, __VA_ARGS__) \ + if (sr_ll_syslog >= LL) \ + SRP_LOG__SYSLOG(LL, MSG, __VA_ARGS__) \ + } while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* SYSREPO_PLUGINS_H_ */ diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/trees.h b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/trees.h new file mode 100644 index 000000000..8db1602e6 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/trees.h @@ -0,0 +1,226 @@ +/** + * @file trees.h + * @author Rastislav Szabo <raszabo@cisco.com>, Lukas Macko <lmacko@cisco.com>, + * Milan Lenco <milan.lenco@pantheon.tech> + * @brief Functions for simplified manipulation with Sysrepo trees. + * + * @copyright + * Copyright 2016 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSREPO_TREES_H_ +#define SYSREPO_TREES_H_ + +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup trees Tree Manipulation Utilities + * @{ + * + * @brief Set of functions facilitating simplified manipulation and traversal + * of Sysrepo trees. As there are many connections between the tree nodes + * and also some internal attributes associated with each node, it is actually + * recommended to use these function rather than to allocate and initialize trees + * manually, which is very likely to lead to time-wasting and hard-to-debug programming + * errors. + * Iterative tree loading (@see SR_GET_SUBTREE_ITERATIVE) even requires to use + * designated functions for tree traversal -- ::sr_node_get_child and ::sr_node_get_next_sibling. + * + * Another added benefit of using these function is that the trees created using + * ::sr_new_tree and ::sr_new_trees will be allocated using the Sysrepo's own memory management + * (if enabled) which was proven to be more efficient for larger data sets + * (far less copying, quicker conversion to/from google protocol buffer messages, + * stable memory footprint, etc.). + */ + +/** + * @brief Allocate an instance of Sysrepo tree. The newly allocated tree has only + * one node -- the tree root -- and can be expanded to its full desired size + * through a repeated use of the function ::sr_node_add_child. + * + * @param [in] root_name Name for the newly allocated tree root. Can be NULL. + * @param [in] root_module_name Name of the module that defines scheme of the tree root. + * Can be NULL. + * @param [out] tree Returned newly allocated Sysrepo tree. + */ +int sr_new_tree(const char *root_name, const char *root_module_name, sr_node_t **tree); + +/** + * @brief Allocate an array of sysrepo trees (uninitialized tree roots). + * + * @param [in] tree_cnt Length of the array to allocate. + * @param [out] trees Returned newly allocated array of trees. + */ +int sr_new_trees(size_t tree_cnt, sr_node_t **trees); + +/** + * @brief Reallocate an array of sysrepo trees (uninitialized tree roots). + * + * @param [in] old_tree_cnt Current length of the tree array. + * @param [in] new_tree_cnt Desired length of the tree array. + * @param [in,out] trees Returned newly allocated/enlarged array of trees. + */ +int sr_realloc_trees(size_t old_tree_cnt, size_t new_tree_cnt, sr_node_t **trees); + +/** + * @brief Set/change name of a Sysrepo node. + * + * @param [in] node Sysrepo node to change the name of. + * @param [in] name Name to set. + */ +int sr_node_set_name(sr_node_t *node, const char *name); + +/** + * @brief Set/change module of a Sysrepo node. + * + * @param [in] node Sysrepo node to change the module of. + * @param [in] module_name Module name to set. + */ +int sr_node_set_module(sr_node_t *node, const char *module_name); + +/** + * @brief Store data of string type into the Sysrepo node data. + * + * @param [in] node Sysrepo node to edit. + * @param [in] type Exact type of the data. + * @param [in] string_val String value to set. + */ +int sr_node_set_str_data(sr_node_t *node, sr_type_t type, const char *string_val); + +/** + * @brief Store data of string type into the Sysrepo node data. The actual data + * will be built from the a format string and a variable arguments list. + * + * @param [in] node Sysrepo node to edit. + * @param [in] type Exact type of the data. + * @param [in] format Format string used to build the data. + */ +int sr_node_build_str_data(sr_node_t *node, sr_type_t type, const char *format, ...); + +/** + * @brief Create a new child for a given Sysrepo node. + * + * @param [in] parent Sysrepo node that should be parent of the newly created node. + * @param [in] child_name Name of the newly created child node. Can be NULL. + * @param [in] child_module_name Name of the module that defines scheme of the newly created + * child node. Can be NULL. + * @param [out] child Returned newly allocated child node. + */ +int sr_node_add_child(sr_node_t *parent, const char *child_name, const char *child_module_name, + sr_node_t **child); + +/** + * @brief Duplicate node and all its descendants (with or without Sysrepo memory context) + * into a new instance of Sysrepo tree with memory context. + * + * @param [in] tree Sysrepo tree to duplicate. + * @param [out] tree_dup Returned duplicate of the input tree. + */ +int sr_dup_tree(const sr_node_t *tree, sr_node_t **tree_dup); + +/** + * @brief Duplicate an array of trees (with or without Sysrepo memory context) into a new + * array of trees with memory context. + * + * @param [in] trees Array of sysrepo trees to duplicate. + * @param [in] count Size of the array to duplicate. + * @param [out] trees_dup Returned duplicate of the input array. + */ +int sr_dup_trees(const sr_node_t *trees, size_t count, sr_node_t **trees_dup); + +/** + * @brief Print sysrepo tree to STDOUT. + * + * @param [in] tree Sysrepo tree to print. + * @param [in] depth_limit Maximum number of tree levels to print. + */ +int sr_print_tree(const sr_node_t *tree, int depth_limit); + +/** + * @brief Print sysrepo tree to the specified file descriptor. + * + * @param [in] fd File descriptor to print the tree into. + * @param [in] tree Sysrepo tree to print. + * @param [in] depth_limit Maximum number of tree levels to print. + */ +int sr_print_tree_fd(int fd, const sr_node_t *tree, int depth_limit); + +/** + * @brief Print sysrepo tree to the specified output file stream. + * + * @param [in] stream Output file stream to print the tree into. + * @param [in] tree Sysrepo tree to print. + * @param [in] depth_limit Maximum number of tree levels to print. + */ +int sr_print_tree_stream(FILE *stream, const sr_node_t *tree, int depth_limit); + +/** + * @brief Print sysrepo tree into a newly allocated memory buffer. + * The caller is expected to eventually free the returned string. + * + * @param [in] mem_p Pointer to store the resulting dump. + * @param [in] tree Sysrepo tree to print. + * @param [in] depth_limit Maximum number of tree levels to print. + */ +int sr_print_tree_mem(char **mem_p, const sr_node_t *tree, int depth_limit); + +/** + * @brief Returns pointer to the first child (based on the schema) of a given node. + * For a fully loaded tree it is equivalent to "node->first_child". For a partially + * loaded tree (@see SR_GET_SUBTREE_ITERATIVE) it may internally issue a sysrepo + * get-subtree-chunk request in order to obtain the data of the child + * (and the data of some surrounding nodes with it for efficiency). + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] node Node to get the child of. + * @return Pointer to a child node. NULL if there is none or an error occured. + */ +sr_node_t *sr_node_get_child(sr_session_ctx_t *session, sr_node_t *node); + +/** + * @brief Returns pointer to the next sibling (based on the schema) of a given node. + * For a fully loaded tree it is equivalent to "node->next". For a partially + * loaded tree (@see SR_GET_SUBTREE_ITERATIVE) it may internally issue a sysrepo + * get-subtree-chunk request in order to obtain the data of the next sibling + * (and the data of some surrounding nodes with it for efficiency). + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] node Node to get the next sibling of. + * @return Pointer to the next sibling. NULL if this is the last sibling or an error occured. + */ +sr_node_t *sr_node_get_next_sibling(sr_session_ctx_t *session, sr_node_t *node); + +/** + * @brief Get the parent of a given node. It is equivalent to "node->parent", but for + * a partially loaded tree it is preferred to use this function rather than to access + * the pointer directly just for the sake of code cleanliness. + * + * @param[in] session Session context acquired with ::sr_session_start call. + * @param[in] node Node to get the parent of. + * @return Pointer to the node's parent or NULL if the node is a root of a (sub)tree. + */ +sr_node_t *sr_node_get_parent(sr_session_ctx_t *session, sr_node_t *node); + +/**@} trees */ + +#ifdef __cplusplus +} +#endif + +#endif /* SYSREPO_TREES_H_ */ diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/values.h b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/values.h new file mode 100644 index 000000000..049c82f19 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/values.h @@ -0,0 +1,196 @@ +/** + * @file values.h + * @author Rastislav Szabo <raszabo@cisco.com>, Lukas Macko <lmacko@cisco.com>, + * Milan Lenco <milan.lenco@pantheon.tech> + * @brief Functions for simplified manipulation with Sysrepo values. + * + * @copyright + * Copyright 2016 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSREPO_VALUES_H_ +#define SYSREPO_VALUES_H_ + +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup values Value Manipulation Utilities + * @{ + * + * @brief Set of functions facilitating simplified manipulation with sysrepo + * values. It is not necessary to use these functions in any scenario, values + * can be allocated and initialized manually (just remember to set all uninitialized + * members to zero!). + * + * Using these utilities, however, has several benefits. Firstly, all the memory + * allocations associated with creating values and setting their attributes get + * hidden behind these functions. The "old-way" was (and still is) to set xpath + * and string values using strdup, which may repeat in applications communicating + * with sysrepo very often and becomes very annoying to write. + * Secondly, the programmer may actually forget to copy or give-up on the ownership + * of a string passed to sysrepo value which will then get unexpectedly deallocated + * in ::sr_free_val or ::sr_free_values. + * The third benefit is that the values created using ::sr_new_val + * and ::sr_new_values will be allocated using the Sysrepo's own memory management + * (if enabled) which was proven to be more efficient for larger data sets + * (far less copying, quicker conversion to/from google protocol buffer messages, + * stable memory footprint, etc.). + */ + +/** + * @brief Allocate an instance of Sysrepo value. + * + * @param [in] xpath Xpath to set for the newly allocated value. Can be NULL. + * @param [out] value Returned newly allocated value. + */ +int sr_new_val(const char *xpath, sr_val_t **value); + +/** + * @brief Allocate an array of sysrepo values. + * + * @param [in] value_cnt Length of the array to allocate. + * @param [out] values Returned newly allocated array of values. + */ +int sr_new_values(size_t value_cnt, sr_val_t **values); + +/** + * @brief Reallocate an array of sysrepo values. + * + * @param [in] old_value_cnt Current length of the value array. + * @param [in] new_value_cnt Desired length of the value array. + * @param [in,out] values Returned newly allocated/enlarged array of values. + */ +int sr_realloc_values(size_t old_value_cnt, size_t new_value_cnt, sr_val_t **values); + +/** + * @brief Set/change xpath of a Sysrepo value. + * + * @param [in] value Sysrepo value to change the xpath of. + * @param [in] xpath XPath to set. + */ +int sr_val_set_xpath(sr_val_t *value, const char *xpath); + +/** + * @brief Set/change xpath of a Sysrepo value to a new one, built from + * a format string and a variable arguments list. + * + * @param [in] value Sysrepo value to change the xpath of. + * @param [in] format Format string used to build XPath. + */ +int sr_val_build_xpath(sr_val_t *value, const char *format, ...); + +/** + * @brief Store data of string type into the Sysrepo value data. + * + * @param [in] value Sysrepo value to edit. + * @param [in] type Exact type of the data. + * @param [in] string_val String value to set. + */ +int sr_val_set_str_data(sr_val_t *value, sr_type_t type, const char *string_val); + +/** + * @brief Store data of string type into the Sysrepo value data. The actual data + * will be built from the a format string and a variable arguments list. + * + * @param [in] value Sysrepo value to edit. + * @param [in] type Exact type of the data. + * @param [in] format Format string used to build the data. + */ +int sr_val_build_str_data(sr_val_t *value, sr_type_t type, const char *format, ...); + +/** + * @brief Duplicate value (with or without Sysrepo memory context) into a new + * instance with memory context. + * + * @param [in] value Sysrepo value to duplicate + * @param [out] value_dup Returned duplicate of the input value. + */ +int sr_dup_val(const sr_val_t *value, sr_val_t **value_dup); + +/** + * @brief Duplicate values (with or without Sysrepo memory context) into a new + * array with memory context. + * + * @param [in] values Array of sysrepo values to duplicate + * @param [in] count Size of the array to duplicate. + * @param [out] values_dup Returned duplicate of the input array. + */ +int sr_dup_values(const sr_val_t *values, size_t count, sr_val_t **values_dup); + +/** + * @brief Print sysrepo value to STDOUT. + * + * @param [in] value Sysrepo value to print. + */ +int sr_print_val(const sr_val_t *value); + +/** + * @brief Print sysrepo value to the specified file descriptor. + * + * @param [in] fd File descriptor to print the value into. + * @param [in] value Sysrepo value to print. + */ +int sr_print_val_fd(int fd, const sr_val_t *value); + +/** + * @brief Print sysrepo value to the specified output file stream. + * + * @param [in] stream Output file stream to print the value into. + * @param [in] value Sysrepo value to print. + */ +int sr_print_val_stream(FILE *stream, const sr_val_t *value); + +/** + * @brief Print sysrepo value into a newly allocated memory buffer. + * The caller is expected to eventually free the returned string. + * + * @param [in] mem_p Pointer to store the resulting dump. + * @param [in] value Sysrepo value to print. + */ +int sr_print_val_mem(char **mem_p, const sr_val_t *value); + +/** + * @brief Converts value to string representation + * @param [in] value + * @return allocated string representation of value (must be freed by caller), NULL in case of error + * @note In case of SR_DECIMAL64_T type, number of fraction digits doesn't have to + * correspond to schema. + */ +char *sr_val_to_str(const sr_val_t *value); + +/** + * @brief Converts value to string and prints it to the provided buffer including + * terminating NULL byte + * @param [in] value + * @param [in] buffer - buffer provided by caller where the data will be printed + * @param [in] size - the size of the buffer + * @return number of characters that was written in case of success, otherwise number of characters which would have been + * written if enough space had been available (excluding terminating NULL byte) + * @note In case of SR_DECIMAL64_T type, number of fraction digits doesn't have to + * correspond to schema. + */ +int sr_val_to_buff(const sr_val_t *value, char buffer[], size_t size); + +/**@} values */ + +#ifdef __cplusplus +} +#endif + +#endif /* SYSREPO_VALUES_H_ */ diff --git a/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/xpath.h b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/xpath.h new file mode 100644 index 000000000..7eca41e57 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/netopeer-change-saver-native/sysrepo/xpath.h @@ -0,0 +1,232 @@ +/** + * @file xpath.h + * @author Rastislav Szabo <raszabo@cisco.com>, Lukas Macko <lmacko@cisco.com> + * @brief Sysrepo helpers for node's address manipulation. + * + * @copyright + * Copyright 2015 Cisco Systems, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSREPO_XPATH_H_ +#define SYSREPO_XPATH_H_ + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup xpath_utils XPath Processing Utilities + * @{ + * + * @brief Set of helpers working on a subset of xpath expressions used of node identification + * Functions modify inputs arguments by placing termination zero at appropriate places to save up + * string duplication. The state of processing is stored in ::sr_xpath_ctx_t opaque for user. + * It allows to continue in processing where the processing stopped or recover processed input. + * + * Similarly to strtok function in all subsequent calls that is supposed to work with the same + * input xpath must be NULL. + */ + +/** + * @brief State of xpath parsing. User must not modify nor rely on the content + * of the structure. + */ +typedef struct sr_xpath_ctx_s { + char *begining; /**< Pointer to the begining of the processed string */ + char *current_node; /**< Pointer to the currently processed node, used as a context for key search */ + char *replaced_position; /**< Pointer to the posistion where the last terminating 0 by was written */ + char replaced_char; /**< Character that was overwritten by the last termination 0 */ +} sr_xpath_ctx_t; + +/** + * @brief The function returns a pointer to the following node. If xpath is + * not NULL returns the first node name, otherwise returns the subsequent node + * according to the state. + * + * The state is modified upon function successful return from function, so the subsequent + * calls can continue in processing or xpath can be recovered by calling ::sr_xpath_recover. + * + * @note It writes terminating zero at the and of the node name. + * + * @note Skips the namespace if it is present to get node name qualified by namespace use ::sr_xpath_next_node_with_ns + * + * @param [in] xpath - xpath to be processed, can be NULL + * @param [in] state + * @return Pointer to the node name, NULL if there are no more node names + */ +char *sr_xpath_next_node(char *xpath, sr_xpath_ctx_t *state); + +/** + * @brief Returns pointer to the last node. + * @param [in] xpath + * @param [in] state + * @return Pointer to the last node + */ +char *sr_xpath_last_node(char *xpath, sr_xpath_ctx_t *state); + +/** + * @brief Same as ::sr_xpath_next_node with the difference that namespace is included in result if present in xpath + * + * @param [in] xpath - xpath to be processed, can be NULL if the user wants to continue in processing of previous input + * @param [in] state + * @return Pointer to the node name including namespace, NULL if there are no more node names + */ +char *sr_xpath_next_node_with_ns(char *xpath, sr_xpath_ctx_t *state); + +/** + * @brief Returns the name of the next key at the current level in processed xpath. + * + * @param [in] xpath + * @param [in] state + * @return Pointer to the key name, NULL if there are no more keys at the current level + */ +char *sr_xpath_next_key_name(char *xpath, sr_xpath_ctx_t *state); + +/** + * @brief Returns the value of the next key at the current level in processed xpath. + * + * @param [in] xpath + * @param [in] state + * @return Pointer to the key value, NULL if there are no more keys at the current level + */ +char *sr_xpath_next_key_value(char *xpath, sr_xpath_ctx_t *state); + +/** + * @brief Returns a pointer to the node specified by name. It searches from the beginning of the xpath, returns first match. + * Can be used to jump at the desired node xpath and subsequent analysis of key values. + * + * @param [in] xpath + * @param [in] node_name + * @param [in] state + * @return Pointer to the node, NULL if the node with the specified name is not found + */ +char *sr_xpath_node(char *xpath, const char *node_name, sr_xpath_ctx_t *state); + +/** + * @brief Similar to ::sr_xpath_node. The difference is that search start at current node + * according to the state. + * + * @param [in] xpath + * @param [in] node_name + * @param [in] state + * @return Pointer to the node, NULL if the node with the specified name is not found + */ +char *sr_xpath_node_rel(char *xpath, const char *node_name, sr_xpath_ctx_t *state); + +/** + * @brief Returns node specified by index starting at the begin of expression. + * First node has index 0. + * + * @param [in] xpath + * @param [in] index + * @param [in] state + * @return Pointer to the specified node, NULL if the index is out of bounds + */ +char *sr_xpath_node_idx(char *xpath, size_t index, sr_xpath_ctx_t *state); + +/** + * @brief Return node specified by index. Following node has index zero. + * + * @param [in] xpath + * @param [in] index + * @param [in] state + * @return Pointer to the specified node, NULL if the index is out of bounds + */ +char *sr_xpath_node_idx_rel(char *xpath, size_t index, sr_xpath_ctx_t *state); + +/** + * @brief Looks up the value for the key at the current level in xpath. + * + * @param [in] xpath + * @param [in] key - key name to be looked up + * @param [in] state + * @return Key value, NULL if the key with the specified name is not found + */ +char *sr_xpath_node_key_value(char *xpath, const char *key, sr_xpath_ctx_t *state); + +/** + * @brief Looks up the value for the key at the current level in xpath specified by index. + * First key has index zero. + * + * @param [in] xpath + * @param [in] index + * @param [in] state + * @return Key value, NULL if the index is out of bound + */ +char *sr_xpath_node_key_value_idx(char *xpath, size_t index, sr_xpath_ctx_t *state); + +/** + * @brief Looks up the value of the key in a node specified by name. + * + * @param [in] xpath + * @param [in] node_name + * @param [in] key_name + * @param [in] state + * @return Pointer to the key value, NULL if not found + */ +char *sr_xpath_key_value(char *xpath, const char *node_name, const char *key_name, sr_xpath_ctx_t *state); + +/** + * @brief Looks up the value of the key in a node specified by index. First node has index zero. + * + * @param [in] xpath + * @param [in] node_index + * @param [in] key_index + * @param [in] state + * @return Pointer to the key value, NULL if not found or index out of bound + */ +char *sr_xpath_key_value_idx(char *xpath, size_t node_index, size_t key_index, sr_xpath_ctx_t *state); + +/** + * @brief Returns pointer to the string after the last slash in xpath (node name). + * + * @note The returned string can also contain namespace and/or key values + * if they were specified for the last node in xpath. + * + * @param [in] xpath + * @return Result, NULL in case of the slash was not found + */ +char *sr_xpath_node_name(const char *xpath); + +/** + * @brief Compares string after the last slash in xpath (node name) with provided string. + * + * @note The returned string can also contain namespace and/or key values + * if they were specified for the last node in xpath. + * + * @param [in] xpath + * @param [in] node_str String to test for equality. + * @return true in case that the Node names are equal, false otherwise + */ +bool sr_xpath_node_name_eq(const char *xpath, const char *node_str); + +/** + * @brief Recovers the xpath string to the original state (puts back the character + * that was replaced by termination zero). + * + * @param [in] state + */ +void sr_xpath_recover(sr_xpath_ctx_t *state); + +/**@} xpath_utils */ + +#ifdef __cplusplus +} +#endif + +#endif /* SYSREPO_XPATH_H_ */ + diff --git a/test/mocks/pnfsimulator/netconfsimulator/pom.xml b/test/mocks/pnfsimulator/netconfsimulator/pom.xml new file mode 100644 index 000000000..7c8d5c78e --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/pom.xml @@ -0,0 +1,278 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.simulator</groupId> + <artifactId>simulator-parent</artifactId> + <version>5.0.0-SNAPSHOT</version> + </parent> + + <artifactId>netconfsimulator</artifactId> + <version>5.0.0-SNAPSHOT</version> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + <maven.build.timestamp.format>yyyyMMdd'T'HHmmss</maven.build.timestamp.format> + <docker.registry>nexus3.onap.org:10003</docker.registry> + <docker.image.tag>latest</docker.image.tag> + <docker.image.name>onap/${project.artifactId}</docker.image.name> + <spring.boot.version>2.1.6.RELEASE</spring.boot.version> + <spring.kafka.version>2.2.7.RELEASE</spring.kafka.version> + <apache.httpclient.version>4.5.6</apache.httpclient.version> + <dependency.directory.name>libs</dependency.directory.name> + <dependency.directory.location>${project.build.directory}/${dependency.directory.name} + </dependency.directory.location> + <netopeer-saver-project-name>netopeer-change-saver</netopeer-saver-project-name> + <netopeer-saver-source-dir>${project.basedir}/netopeer-change-saver-native</netopeer-saver-source-dir> + <netopeer-saver-build-dir>${project.build.directory}/cmake</netopeer-saver-build-dir> + <netopeer-saver-executable-dir>${netopeer-saver-build-dir}/bin</netopeer-saver-executable-dir> + <skipITs>true</skipITs> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter</artifactId> + <version>${spring.boot.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + <version>${spring.boot.version}</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.2</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>jnc</artifactId> + <version>1.0</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-websocket</artifactId> + <version>${spring.boot.version}</version> + </dependency> + <dependency> + <groupId>javax.websocket</groupId> + <artifactId>javax.websocket-api</artifactId> + <version>1.1</version> + </dependency> + + <!-- Kafka --> + + <dependency> + <groupId>org.springframework.kafka</groupId> + <artifactId>spring-kafka</artifactId> + <version>${spring.kafka.version}</version> + </dependency> + + <!-- TEST DEPENDENCIES --> + + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.9.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>2.18.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>5.3.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.vintage</groupId> + <artifactId>junit-vintage-engine</artifactId> + <version>5.3.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <version>${spring.boot.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.kafka</groupId> + <artifactId>spring-kafka-test</artifactId> + <version>${spring.kafka.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.bitbucket.radistao.test</groupId> + <artifactId>before-after-spring-test-runner</artifactId> + <version>0.1.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.palantir.docker.compose</groupId> + <artifactId>docker-compose-rule-junit4</artifactId> + <version>0.29.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.5.6</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpmime</artifactId> + <version>4.5.6</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>${apache.httpclient.version}</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpmime</artifactId> + <version>${apache.httpclient.version}</version> + </dependency> + + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + <version>2.9.2</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>2.9.2</version> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <configuration> + <outputDirectory>${dependency.directory.location}</outputDirectory> + <includeScope>runtime</includeScope> + <silent>true</silent> + </configuration> + <executions> + <execution> + <id>copy-external-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.19</version> + <dependencies> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-surefire-provider</artifactId> + <version>1.1.1</version> + </dependency> + </dependencies> + <configuration> + <detail>true</detail> + <printSummary>true</printSummary> + <useSystemClassLoader>false</useSystemClassLoader> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <version>2.19.1</version> + <configuration> + <skipITs>${skipITs}</skipITs> + </configuration> + <executions> + <execution> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>1.1.1</version> + <configuration> + <imageName>${docker.registry}/${docker.image.name}</imageName> + <dockerDirectory>${project.basedir}/docker</dockerDirectory> + <forceTags>true</forceTags> + <registryUrl>${docker.registry}</registryUrl> + <imageTags> + <tag>latest</tag> + <tag>${project.version}</tag> + <tag>${project.version}-${maven.build.timestamp}</tag> + </imageTags> + <resources> + <resource> + <targetPath>${dependency.directory.name}</targetPath> + <directory>${dependency.directory.location}</directory> + </resource> + <resource> + <targetPath>/</targetPath> + <directory>${project.build.directory}</directory> + <include>${project.build.finalName}.jar</include> + </resource> + </resources> + <forceTags>true</forceTags> + </configuration> + </plugin> + </plugins> + </build> + <repositories> + <repository> + <id>Palantir</id> + <url>https://dl.bintray.com/palantir/releases/</url> + </repository> + </repositories> +</project> diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/Configuration.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/Configuration.java new file mode 100644 index 000000000..92e5b2327 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/Configuration.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator; + +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.springframework.context.annotation.Bean; + +@org.springframework.context.annotation.Configuration +public class Configuration { + + @Bean + public HttpClient httpClient() { + return HttpClientBuilder.create().build(); + } +} diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationCacheTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/Main.java index 56f62ac50..e2a0ed0c0 100644 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationCacheTest.java +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/Main.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,22 +17,15 @@ * limitations under the License. * ============LICENSE_END========================================================= */ +package org.onap.netconfsimulator; -package org.onap.pnfsimulator.netconfmonitor.netconf; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; -import static org.junit.jupiter.api.Assertions.assertEquals; +@SpringBootApplication +public class Main { -import org.junit.jupiter.api.Test; - -public class NetconfConfigurationCacheTest { - - private static final String CONFIGURATION = "sampleConfiguration"; - - @Test - void changeConfigurationAfterUpdate() { - NetconfConfigurationCache configurationCache = new NetconfConfigurationCache(); - configurationCache.update(CONFIGURATION); - - assertEquals(CONFIGURATION, configurationCache.getConfiguration()); + public static void main(String[] args) { + SpringApplication.run(Main.class, args); } -}
\ No newline at end of file +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/SwaggerConfig.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/SwaggerConfig.java new file mode 100644 index 000000000..2e9df997e --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/SwaggerConfig.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@Configuration +class SwaggerConfig { + + @Bean + Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("org.onap.netconfsimulator")) + .paths(PathSelectors.any()) + .build(); + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/Config.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/Config.java new file mode 100644 index 000000000..9ae564103 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/Config.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.onap.netconfsimulator.kafka.listener.KafkaListenerHandler; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; + +@Configuration +@EnableKafka +class Config { + + @Value("${spring.kafka.bootstrap-servers}") + private String bootstrapServer; + + @Value("${spring.kafka.consumer.auto-offset-reset}") + private String offsetReset; + + @Bean + ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory(ConsumerFactory<String, String> consumerFactory) { + ConcurrentKafkaListenerContainerFactory<String, String> containerFactory = new ConcurrentKafkaListenerContainerFactory<>(); + containerFactory.setConsumerFactory(consumerFactory); + return containerFactory; + } + + @Bean + ConsumerFactory<String, String> consumerFactory() { + Map<String, Object> props = new HashMap<>(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServer); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, offsetReset); + return new DefaultKafkaConsumerFactory<>(props); + } + + + @Bean + KafkaListenerHandler kafkaListenerHandler(ConsumerFactory<String, String> consumerFactory) { + return new KafkaListenerHandler(consumerFactory); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/MessageDTO.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/MessageDTO.java new file mode 100644 index 000000000..4311cd61f --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/MessageDTO.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +class MessageDTO { + private long timestamp; + private String configuration; +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreController.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreController.java new file mode 100644 index 000000000..33bbdf7cf --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreController.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +@RequestMapping("/store") +public class StoreController { + + private StoreService service; + + @Autowired + public StoreController(StoreService service) { + this.service = service; + } + + @GetMapping("/ping") + String ping() { + return "pong"; + } + + @GetMapping("cm-history") + List<MessageDTO> getAllConfigurationChanges() { + return service.getAllMessages(); + } + + @GetMapping("/less") + List<MessageDTO> less(@RequestParam(value = "offset", required = false, defaultValue = "${spring.kafka.default-offset}") long offset) { + return service.getLastMessages(offset); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreService.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreService.java new file mode 100644 index 000000000..5fddff5a2 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/StoreService.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka; + +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.Consumer; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.common.TopicPartition; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Slf4j +@Service +public class StoreService { + + private static final String CONFIG_TOPIC = "config"; + private static final long CONSUMING_DURATION_IN_MS = 1000; + + private ConsumerFactory<String, String> consumerFactory; + static final List<String> TOPICS_TO_SUBSCRIBE = Collections.singletonList(CONFIG_TOPIC); + + @Autowired + StoreService(ConsumerFactory<String, String> consumerFactory) { + this.consumerFactory = consumerFactory; + } + + List<MessageDTO> getAllMessages() { + List<MessageDTO> messages = new ArrayList<>(); + String clientID = Long.toString(Instant.now().getEpochSecond()); + try (Consumer<String, String> consumer = consumerFactory.createConsumer(clientID, clientID)) { + consumer.subscribe(TOPICS_TO_SUBSCRIBE); + ConsumerRecords<String, String> consumerRecords = consumer.poll(CONSUMING_DURATION_IN_MS); + consumerRecords.forEach( + consumerRecord -> + messages.add(new MessageDTO(consumerRecord.timestamp(), consumerRecord.value()))); + log.debug(String.format("consumed %d messages", consumerRecords.count())); + } + return messages; + } + + List<MessageDTO> getLastMessages(long offset) { + List<MessageDTO> messages = new ArrayList<>(); + try (Consumer<String, String> consumer = createConsumer(offset)) { + ConsumerRecords<String, String> consumerRecords = consumer.poll(CONSUMING_DURATION_IN_MS); + consumerRecords.forEach(consumerRecord -> + messages.add(new MessageDTO(consumerRecord.timestamp(), consumerRecord.value()))); + } + return messages; + } + + private Consumer<String, String> createConsumer(long offsetFromLastIndex) { + String clientID = Long.toString(Instant.now().getEpochSecond()); + Consumer<String, String> consumer = consumerFactory.createConsumer(clientID, clientID); + consumer.subscribe(TOPICS_TO_SUBSCRIBE); + seekConsumerTo(consumer, offsetFromLastIndex); + return consumer; + } + + private void seekConsumerTo(Consumer<String, String> consumer, long offsetFromLastIndex) { + consumer.seekToEnd(consumer.assignment()); + consumer.poll(CONSUMING_DURATION_IN_MS); + TopicPartition topicPartition = consumer.assignment().iterator().next(); + long topicCurrentSize = consumer.position(topicPartition); + long indexToSeek = offsetFromLastIndex > topicCurrentSize ? 0 : topicCurrentSize - offsetFromLastIndex; + consumer.seek(topicPartition, indexToSeek); + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerEntry.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerEntry.java new file mode 100644 index 000000000..e3c04c9fc --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerEntry.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka.listener; + +import lombok.Getter; +import org.springframework.kafka.listener.AbstractMessageListenerContainer; + +@Getter +public class KafkaListenerEntry { + + private String clientId; + private AbstractMessageListenerContainer listenerContainer; + + public KafkaListenerEntry(String clientId, AbstractMessageListenerContainer listenerContainer) { + this.clientId = clientId; + this.listenerContainer = listenerContainer; + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerHandler.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerHandler.java new file mode 100644 index 000000000..604315d5f --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerHandler.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka.listener; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.ConsumerFactory; + +import org.springframework.kafka.listener.ContainerProperties; +import org.springframework.kafka.listener.KafkaMessageListenerContainer; +import org.springframework.kafka.listener.MessageListener; + + +import org.springframework.kafka.support.TopicPartitionInitialOffset; + +import java.time.Instant; + +public class KafkaListenerHandler { + + private static final int PARTITION = 0; + private static final long NUMBER_OF_HISTORICAL_MESSAGES_TO_SHOW = -10L; + private static final boolean RELATIVE_TO_CURRENT = false; + private ConsumerFactory<String, String> consumerFactory; + + + @Autowired + public KafkaListenerHandler(ConsumerFactory<String, String> consumerFactory) { + this.consumerFactory = consumerFactory; + } + + + public KafkaListenerEntry createKafkaListener(MessageListener messageListener, String topicName) { + String clientId = Long.toString(Instant.now().getEpochSecond()); + ContainerProperties containerProperties = new ContainerProperties(topicName); + containerProperties.setGroupId(clientId); + KafkaMessageListenerContainer<String, String> listenerContainer = createListenerContainer(containerProperties, + topicName); + + listenerContainer.setupMessageListener(messageListener); + return new KafkaListenerEntry(clientId, listenerContainer); + } + + + KafkaMessageListenerContainer<String, String> createListenerContainer(ContainerProperties containerProperties, + String topicName) { + TopicPartitionInitialOffset config = new TopicPartitionInitialOffset(topicName, PARTITION, + NUMBER_OF_HISTORICAL_MESSAGES_TO_SHOW, RELATIVE_TO_CURRENT); + return new KafkaMessageListenerContainer<>(consumerFactory, containerProperties, config); + } +} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationCache.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/model/KafkaMessage.java index 39721841b..90f283acf 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationCache.java +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/kafka/model/KafkaMessage.java @@ -1,8 +1,8 @@ -/* +/*- * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER + * Simulator * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2019 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,17 +18,20 @@ * ============LICENSE_END========================================================= */ -package org.onap.pnfsimulator.netconfmonitor.netconf; +package org.onap.netconfsimulator.kafka.model; -public class NetconfConfigurationCache { +import lombok.Getter; - private String configuration = ""; +@Getter +public class KafkaMessage { + private long timestamp; + private String configuration; - public String getConfiguration() { - return configuration; + public KafkaMessage(long timestamp, String configuration) { + this.timestamp = timestamp; + this.configuration = configuration; } - public void update(String configuration) { - this.configuration = configuration; + KafkaMessage() { } } diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/NetconfController.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/NetconfController.java new file mode 100644 index 000000000..cdb4a8f97 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/NetconfController.java @@ -0,0 +1,111 @@ +/* + * ============LICENSE_START======================================================= + * NETCONF-CONTROLLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore; + +import com.tailf.jnc.JNCException; + +import java.io.IOException; + +import lombok.extern.slf4j.Slf4j; +import org.onap.netconfsimulator.netconfcore.configuration.NetconfConfigurationService; +import org.onap.netconfsimulator.netconfcore.model.LoadModelResponse; +import org.onap.netconfsimulator.netconfcore.model.NetconfModelLoaderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@Slf4j +@RestController +@RequestMapping("netconf") +class NetconfController { + + private final NetconfConfigurationService netconfService; + private final NetconfModelLoaderService netconfModelLoaderService; + + @Autowired + NetconfController(NetconfConfigurationService netconfService, + NetconfModelLoaderService netconfModelLoaderService) { + this.netconfService = netconfService; + this.netconfModelLoaderService = netconfModelLoaderService; + } + + @GetMapping(value = "get", produces = "application/xml") + ResponseEntity<String> getNetconfConfiguration() throws IOException, JNCException { + return ResponseEntity.ok(netconfService.getCurrentConfiguration()); + } + + @GetMapping(value = "get/{model}/{container}", produces = "application/xml") + ResponseEntity<String> getNetconfConfiguration(@PathVariable String model, + @PathVariable String container) + throws IOException { + ResponseEntity<String> entity; + try { + entity = ResponseEntity.ok(netconfService.getCurrentConfiguration(model, container)); + } catch (JNCException exception) { + log.error("Get configuration for model {} and container {} failed.", model, container, + exception); + entity = ResponseEntity.badRequest().body(exception.toString()); + } + return entity; + } + + @PostMapping(value = "edit-config", produces = "application/xml") + @ResponseStatus(HttpStatus.ACCEPTED) + ResponseEntity<String> editConfig(@RequestPart("editConfigXml") MultipartFile editConfig) + throws IOException, JNCException { + log.info("Loading updated configuration"); + if (editConfig == null || editConfig.isEmpty()) { + throw new IllegalArgumentException("No XML file with proper name: editConfigXml found."); + } + return ResponseEntity + .status(HttpStatus.ACCEPTED) + .body(netconfService.editCurrentConfiguration(editConfig)); + } + + @PostMapping("model/{moduleName}") + ResponseEntity<String> loadNewYangModel(@RequestBody MultipartFile yangModel, + @RequestBody MultipartFile initialConfig, @PathVariable String moduleName) + throws IOException { + LoadModelResponse response = netconfModelLoaderService.loadYangModel(yangModel, initialConfig, moduleName); + return ResponseEntity + .status(response.getStatusCode()) + .body(response.getMessage()); + } + + @DeleteMapping("model/{modelName}") + ResponseEntity<String> deleteYangModel(@PathVariable String modelName) + throws IOException { + LoadModelResponse response = netconfModelLoaderService.deleteYangModel(modelName); + return ResponseEntity + .status(response.getStatusCode()) + .body(response.getMessage()); + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfBeanConfiguration.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfBeanConfiguration.java new file mode 100644 index 000000000..d90c60d58 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfBeanConfiguration.java @@ -0,0 +1,60 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.configuration; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class NetconfBeanConfiguration { + + private static final Logger LOGGER = LoggerFactory.getLogger(NetconfBeanConfiguration.class); + + @Value("${netconf.port}") + private Integer netconfPort; + + @Value("${netconf.address}") + private String netconfAddress; + + @Value("${netconf.user}") + private String netconfUser; + + @Value("${netconf.password}") + private String netconfPassword; + + @Bean + NetconfConfigurationReader configurationReader() { + NetconfConnectionParams params = new NetconfConnectionParams(netconfAddress, netconfPort, netconfUser, netconfPassword); + LOGGER.info("Configuration params are : {}", params); + return new NetconfConfigurationReader(params, new NetconfSessionHelper()); + } + + @Bean + NetconfConfigurationEditor configurationEditor() { + NetconfConnectionParams params = + new NetconfConnectionParams(netconfAddress, netconfPort, netconfUser, netconfPassword); + return new NetconfConfigurationEditor(params, new NetconfSessionHelper()); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationEditor.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationEditor.java new file mode 100644 index 000000000..992c88d5a --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationEditor.java @@ -0,0 +1,50 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.configuration; + +import com.tailf.jnc.Element; +import com.tailf.jnc.JNCException; +import com.tailf.jnc.NetconfSession; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; + +@Slf4j +public class NetconfConfigurationEditor { + + private NetconfConnectionParams params; + private NetconfSessionHelper netconfSessionHelper; + + public NetconfConfigurationEditor(NetconfConnectionParams params, NetconfSessionHelper netconfSessionHelper) { + this.params = params; + this.netconfSessionHelper = netconfSessionHelper; + } + + void editConfig(Element configurationXmlElement) throws JNCException, IOException { + log.debug("New configuration passed to simulator: {}", configurationXmlElement.toXMLString()); + NetconfSession session = netconfSessionHelper.createNetconfSession(params); + session.editConfig(configurationXmlElement); + session.closeSession(); + + log.info("Successfully updated configuration"); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationReader.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationReader.java new file mode 100644 index 000000000..10fe40e2f --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationReader.java @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.configuration; + +import com.tailf.jnc.JNCException; +import com.tailf.jnc.NetconfSession; +import com.tailf.jnc.NodeSet; +import java.io.IOException; +import java.util.Objects; + +class NetconfConfigurationReader { + + private NetconfConnectionParams params; + private NetconfSessionHelper netconfSessionHelper; + + NetconfConfigurationReader(NetconfConnectionParams params, NetconfSessionHelper netconfSessionHelper) { + this.params = params; + this.netconfSessionHelper = netconfSessionHelper; + } + + String getRunningConfig() throws IOException, JNCException { + NetconfSession session = netconfSessionHelper.createNetconfSession(params); + String config = session.getConfig().toXMLString(); + session.closeSession(); + return config; + } + + String getRunningConfig(String modelPath) throws IOException, JNCException { + NetconfSession session = netconfSessionHelper.createNetconfSession(params); + NodeSet config = session.getConfig(modelPath); + if (Objects.isNull(config) || Objects.isNull(config.first())) { + throw new JNCException(JNCException.ELEMENT_MISSING, modelPath); + } + session.closeSession(); + return config.first().toXMLString(); + } + + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationService.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationService.java new file mode 100644 index 000000000..248aec46a --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationService.java @@ -0,0 +1,76 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.configuration; + +import com.tailf.jnc.Element; +import com.tailf.jnc.JNCException; +import com.tailf.jnc.XMLParser; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import org.xml.sax.InputSource; + +@Service +public class NetconfConfigurationService { + + private static final Logger LOGGER = LoggerFactory.getLogger(NetconfConfigurationService.class); + private static final String CONFIGURATION_HAS_BEEN_ACTIVATED = "New configuration has been activated"; + + private final NetconfConfigurationReader netconfConfigurationReader; + private NetconfConfigurationEditor configurationEditor; + private XMLParser parser; + + @Autowired + public NetconfConfigurationService(NetconfConfigurationReader netconfConfigurationReader, + NetconfConfigurationEditor netconfConfigurationEditor) throws JNCException { + this.netconfConfigurationReader = netconfConfigurationReader; + this.configurationEditor = netconfConfigurationEditor; + this.parser = new XMLParser(); + } + + public String getCurrentConfiguration() throws IOException, JNCException { + return netconfConfigurationReader.getRunningConfig(); + } + + public String getCurrentConfiguration(String model, String container) throws IOException, JNCException { + String path = String.format("/%s:%s", model, container); + return netconfConfigurationReader.getRunningConfig(path); + } + + public String editCurrentConfiguration(MultipartFile newConfiguration) throws IOException, JNCException { + Element configurationElement = convertMultipartToXmlElement(newConfiguration); + configurationEditor.editConfig(configurationElement); + + LOGGER.debug("Loading new configuration: \n{}", configurationElement.toXMLString()); + return CONFIGURATION_HAS_BEEN_ACTIVATED; + } + + private Element convertMultipartToXmlElement(MultipartFile editConfig) throws IOException, JNCException { + InputSource inputSourceUpdateConfig = new InputSource(new ByteArrayInputStream(editConfig.getBytes())); + return parser.parse(inputSourceUpdateConfig); + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationTO.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationTO.java new file mode 100644 index 000000000..e43ff690e --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationTO.java @@ -0,0 +1,32 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.configuration; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class NetconfConfigurationTO { + + private String configuration; + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConnectionParams.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConnectionParams.java new file mode 100644 index 000000000..ace0ee04c --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConnectionParams.java @@ -0,0 +1,37 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.configuration; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; + +@AllArgsConstructor +@ToString +@Getter +class NetconfConnectionParams { + + private final String address; + private final int port; + private final String user; + private final String password; + +} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationReader.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfSessionHelper.java index 593598e86..69fda7d63 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationReader.java +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfSessionHelper.java @@ -1,15 +1,15 @@ -/* +/*- * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER + * Simulator * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2019 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,23 +18,20 @@ * ============LICENSE_END========================================================= */ -package org.onap.pnfsimulator.netconfmonitor.netconf; +package org.onap.netconfsimulator.netconfcore.configuration; import com.tailf.jnc.JNCException; import com.tailf.jnc.NetconfSession; +import com.tailf.jnc.SSHConnection; +import com.tailf.jnc.SSHSession; import java.io.IOException; -public class NetconfConfigurationReader { +class NetconfSessionHelper { - private final NetconfSession session; - private final String netconfModelPath; - - public NetconfConfigurationReader(NetconfSession session, String netconfModelPath) { - this.session = session; - this.netconfModelPath = netconfModelPath; + NetconfSession createNetconfSession(NetconfConnectionParams params) throws IOException, JNCException { + SSHConnection sshConnection = new SSHConnection(params.getAddress(), params.getPort()); + sshConnection.authenticateWithPassword(params.getUser(), params.getPassword()); + return new NetconfSession(new SSHSession(sshConnection)); } - public String read() throws IOException, JNCException { - return session.getConfig(netconfModelPath).first().toXMLString(); - } } diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/model/LoadModelResponse.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/model/LoadModelResponse.java new file mode 100644 index 000000000..a6e292f62 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/model/LoadModelResponse.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.model; + +public class LoadModelResponse { + + private Integer statusCode; + private String message; + + public LoadModelResponse(Integer statusCode, String message) { + this.statusCode = statusCode; + this.message = message; + } + + public Integer getStatusCode() { + return this.statusCode; + } + + public String getMessage() { + return this.message; + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/model/NetconfModelLoaderService.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/model/NetconfModelLoaderService.java new file mode 100644 index 000000000..7e0739579 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/netconfcore/model/NetconfModelLoaderService.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.model; + +import java.io.IOException; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +@Service +public class NetconfModelLoaderService { + + private static final Logger LOGGER = LoggerFactory.getLogger(NetconfModelLoaderService.class); + + @Value("${netconf.address}") + private String netconfIp; + + @Value("${netconf.model-loader.port}") + private String modelLoaderPort; + + private final HttpClient httpClient; + + @Autowired + public NetconfModelLoaderService(HttpClient httpClient) { + this.httpClient = httpClient; + } + + public LoadModelResponse deleteYangModel(String yangModelName) throws IOException { + String uri = getDeleteAddress(yangModelName); + HttpDelete httpDelete = new HttpDelete(uri); + HttpResponse httpResponse = httpClient.execute(httpDelete); + return parseResponse(httpResponse); + } + + public LoadModelResponse loadYangModel(MultipartFile yangModel, MultipartFile initialConfig, String moduleName) + throws IOException { + HttpPost httpPost = new HttpPost(getBackendAddress()); + HttpEntity httpEntity = MultipartEntityBuilder.create() + .addBinaryBody("yangModel", yangModel.getInputStream(), ContentType.MULTIPART_FORM_DATA, + yangModel.getOriginalFilename()) + .addBinaryBody("initialConfig", initialConfig.getInputStream(), ContentType.MULTIPART_FORM_DATA, + initialConfig.getOriginalFilename()) + .addTextBody("moduleName", moduleName) + .build(); + httpPost.setEntity(httpEntity); + HttpResponse response = httpClient.execute(httpPost); + return parseResponse(response); + } + + String getBackendAddress() { + return String.format("http://%s:%s/model", netconfIp, modelLoaderPort); + } + + String getDeleteAddress(String yangModelName) { + return String.format("%s?yangModelName=%s", getBackendAddress(), yangModelName); + } + + + private LoadModelResponse parseResponse(HttpResponse response) throws IOException { + int statusCode = response.getStatusLine().getStatusCode(); + String responseBody = EntityUtils.toString(response.getEntity()); + + logResponse(statusCode, responseBody); + return new LoadModelResponse(statusCode, responseBody); + } + + private void logResponse(int statusCode, String responseBody) { + if (statusCode >= HttpStatus.BAD_REQUEST.value()) { + LOGGER.error(responseBody); + } else { + LOGGER.info(responseBody); + } + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/EndpointConfig.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/EndpointConfig.java new file mode 100644 index 000000000..4eaa85010 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/EndpointConfig.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.websocket; + +import java.util.Collections; +import org.onap.netconfsimulator.websocket.message.NetconfMessageEncoder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; +import org.springframework.web.socket.server.standard.ServerEndpointRegistration; + +@Configuration +class EndpointConfig { + + @Bean + ServerEndpointRegistration endpointRegistration() { + ServerEndpointRegistration serverEndpointRegistration = new ServerEndpointRegistration("/netconf", + NetconfEndpoint.class); + serverEndpointRegistration.setEncoders(Collections.singletonList(NetconfMessageEncoder.class)); + return serverEndpointRegistration; + } + + @Bean + ServerEndpointExporter endpointExporter() { + return new ServerEndpointExporter(); + } +} + diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/NetconfEndpoint.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/NetconfEndpoint.java new file mode 100644 index 000000000..5870ee1e4 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/NetconfEndpoint.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.websocket; + + +import java.util.Optional; +import javax.websocket.CloseReason; +import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; +import javax.websocket.RemoteEndpoint; +import javax.websocket.Session; + +import org.onap.netconfsimulator.kafka.listener.KafkaListenerEntry; +import org.onap.netconfsimulator.kafka.listener.KafkaListenerHandler; +import org.onap.netconfsimulator.websocket.message.NetconfMessageListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.listener.AbstractMessageListenerContainer; +import org.springframework.kafka.listener.MessageListener; +import org.springframework.stereotype.Component; + +//instance of this class is created every each websocket request +@Component +class NetconfEndpoint extends Endpoint { + + private static final Logger LOGGER = LoggerFactory.getLogger(NetconfEndpoint.class); + private static final String TOPIC_NAME = "config"; + + private KafkaListenerHandler kafkaListenerHandler; + + public Optional<KafkaListenerEntry> getEntry() { + return entry; + } + + public void setEntry(Optional<KafkaListenerEntry> entry) { + this.entry = entry; + } + + private Optional<KafkaListenerEntry> entry = Optional.empty(); + + + @Autowired + NetconfEndpoint(KafkaListenerHandler listenerHandler) { + this.kafkaListenerHandler = listenerHandler; + } + + @Override + public void onOpen(Session session, EndpointConfig endpointConfig) { + RemoteEndpoint.Basic basicRemote = session.getBasicRemote(); + + addKafkaListener(basicRemote); + entry.ifPresent(x -> LOGGER.info("Session with client: {} established", x.getClientId())); + } + + @Override + public void onError(Session session, Throwable throwable) { + LOGGER.error("Unexpected error occurred", throwable); + } + + @Override + public void onClose(Session session, CloseReason closeReason) { + entry.ifPresent(x -> x.getListenerContainer().stop()); + entry.ifPresent(x -> LOGGER.info("Closing connection for client: {}", x.getClientId())); + } + + + private void addKafkaListener(RemoteEndpoint.Basic remoteEndpoint) { + MessageListener messageListener = new NetconfMessageListener(remoteEndpoint); + + KafkaListenerEntry kafkaListener = kafkaListenerHandler.createKafkaListener(messageListener, TOPIC_NAME); + + AbstractMessageListenerContainer listenerContainer = kafkaListener.getListenerContainer(); + listenerContainer.start(); + entry = Optional.of(kafkaListener); + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/message/NetconfMessageEncoder.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/message/NetconfMessageEncoder.java new file mode 100644 index 000000000..349b7e2d9 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/message/NetconfMessageEncoder.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.websocket.message; + +import org.onap.netconfsimulator.kafka.model.KafkaMessage; +import org.springframework.web.socket.adapter.standard.ConvertingEncoderDecoderSupport; + +public class NetconfMessageEncoder extends ConvertingEncoderDecoderSupport.TextEncoder<KafkaMessage> { + + private static final String MESSAGE_FORMAT = "%s: %s"; + + @Override + public String encode(KafkaMessage netconfMessage) { + return String.format(MESSAGE_FORMAT, netconfMessage.getTimestamp(), netconfMessage.getConfiguration()); + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/message/NetconfMessageListener.java b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/message/NetconfMessageListener.java new file mode 100644 index 000000000..61610dea0 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/java/org/onap/netconfsimulator/websocket/message/NetconfMessageListener.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.websocket.message; + +import java.io.IOException; +import javax.websocket.EncodeException; +import javax.websocket.RemoteEndpoint; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.onap.netconfsimulator.kafka.model.KafkaMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.listener.MessageListener; + +public class NetconfMessageListener implements MessageListener<String, String> { + + private static final Logger LOGGER = LoggerFactory.getLogger(NetconfMessageListener.class); + private RemoteEndpoint.Basic remoteEndpoint; + + public NetconfMessageListener(RemoteEndpoint.Basic remoteEndpoint) { + this.remoteEndpoint = remoteEndpoint; + } + + @Override + public void onMessage(ConsumerRecord<String, String> message) { + LOGGER.debug("Attempting to send message to {}", remoteEndpoint); + try { + remoteEndpoint + .sendObject(new KafkaMessage(message.timestamp(), message.value())); + } catch (IOException | EncodeException exception) { + LOGGER.error("Error during sending message to remote", exception); + } + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/main/resources/application.properties b/test/mocks/pnfsimulator/netconfsimulator/src/main/resources/application.properties new file mode 100644 index 000000000..3947cf358 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/main/resources/application.properties @@ -0,0 +1,8 @@ +netconf.port=830 +netconf.address=netopeer +netconf.user=netconf +netconf.password=netconf +netconf.model-loader.port=5002 +spring.kafka.bootstrap-servers=kafka1:9092 +spring.kafka.default-offset=100 +spring.kafka.consumer.auto-offset-reset=earliest diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/integration/NetconfFunctionsIT.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/integration/NetconfFunctionsIT.java new file mode 100644 index 000000000..95ef58696 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/integration/NetconfFunctionsIT.java @@ -0,0 +1,211 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package integration; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.palantir.docker.compose.connection.DockerMachine; +import com.palantir.docker.compose.connection.waiting.HealthChecks; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.bitbucket.radistao.test.annotation.BeforeAllMethods; +import org.bitbucket.radistao.test.runner.BeforeAfterSpringTestRunner; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import com.palantir.docker.compose.DockerComposeRule; +import org.onap.netconfsimulator.kafka.model.KafkaMessage; +import org.springframework.http.HttpStatus; + +import java.io.IOException; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static junit.framework.TestCase.fail; +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(BeforeAfterSpringTestRunner.class) +public class NetconfFunctionsIT { + + private static NetconfSimulatorClient client; + private static ObjectMapper objectMapper; + + private static final DockerMachine dockerMachine = DockerMachine + .localMachine() + .build(); + + private static DockerComposeRule docker = DockerComposeRule.builder() + .file("docker-compose.yml") + .machine(dockerMachine) + .removeConflictingContainersOnStartup(true) + .waitingForService("sftp-server", HealthChecks.toHaveAllPortsOpen()) + .waitingForService("ftpes-server", HealthChecks.toHaveAllPortsOpen()) + .waitingForService("zookeeper", HealthChecks.toHaveAllPortsOpen()) + .waitingForService("netopeer", HealthChecks.toHaveAllPortsOpen()) + .waitingForService("kafka1", HealthChecks.toHaveAllPortsOpen()) + .waitingForService("netconf-simulator", HealthChecks.toHaveAllPortsOpen()) + .build(); + + @ClassRule + public static TestRule exposePortMappings = docker; + + @BeforeClass + public static void setUpClass() { + objectMapper = new ObjectMapper(); + client = new NetconfSimulatorClient(String.format("http://%s:%d", docker.containers().ip(), 9000)); + } + + @BeforeAllMethods + public void setupBeforeAll() throws InterruptedException { + if (client.isServiceAvailable(Instant.now(), Duration.ofSeconds(45))) { + Thread.sleep(60000); + return; + } + fail("Application failed to start within established timeout: 45 seconds. Exiting."); + } + + @Before + public void setUp() { + client.reinitializeClient(); + } + + @After + public void tearDown() throws Exception { + client.releaseClient(); + } + + @Test + public void testShouldLoadModelEditConfigurationAndDeleteModule() throws IOException { + // do load + try (CloseableHttpResponse response = client + .loadModel("newyangmodel", "newYangModel.yang", "initialConfig.xml")) { + assertResponseStatusCode(response, HttpStatus.OK); + String original = client.getResponseContentAsString(response); + assertThat(original).isEqualTo("\"Successfully started\"\n"); + } + // do edit-config + try (CloseableHttpResponse updateResponse = client.updateConfig()) { + String afterUpdateConfigContent = client.getResponseContentAsString(updateResponse); + assertResponseStatusCode(updateResponse, HttpStatus.ACCEPTED); + assertThat(afterUpdateConfigContent).isEqualTo("New configuration has been activated"); + } + // do delete + try (CloseableHttpResponse deleteResponse = client.deleteModel("newyangmodel")) { + assertResponseStatusCode(deleteResponse, HttpStatus.OK); + String original = client.getResponseContentAsString(deleteResponse); + assertThat(original).isEqualTo("\"Successfully deleted\"\n"); + } + } + + @Test + public void testShouldGetCurrentConfigurationAndEditItSuccessfully() throws IOException { + try (CloseableHttpResponse updateResponse = client.updateConfig(); + CloseableHttpResponse newCurrentConfigResponse = client.getCurrentConfig()) { + String afterUpdateConfigContent = client.getResponseContentAsString(updateResponse); + + assertResponseStatusCode(updateResponse, HttpStatus.ACCEPTED); + assertResponseStatusCode(newCurrentConfigResponse, HttpStatus.OK); + + assertThat(afterUpdateConfigContent).isEqualTo("New configuration has been activated"); + } + } + + @Test + public void testShouldPersistConfigChangesAndGetAllWhenRequested() throws IOException { + client.updateConfig(); + + try (CloseableHttpResponse newAllConfigChangesResponse = client.getAllConfigChanges()) { + String newAllConfigChangesString = client.getResponseContentAsString(newAllConfigChangesResponse); + assertResponseStatusCode(newAllConfigChangesResponse, HttpStatus.OK); + + List<KafkaMessage> kafkaMessages = objectMapper + .readValue(newAllConfigChangesString, new TypeReference<List<KafkaMessage>>() { + }); + + assertThat(kafkaMessages.size()).isGreaterThanOrEqualTo(1); + Set<String> configChangeContent = kafkaMessages.stream().map(KafkaMessage::getConfiguration) + .collect(Collectors.toSet()); + assertThat(configChangeContent) + .anyMatch(el -> el.contains("new value: /pnf-simulator:config/itemValue1 = 100")); + assertThat(configChangeContent) + .anyMatch(el -> el.contains("new value: /pnf-simulator:config/itemValue2 = 200")); + } + } + + @Test + public void testShouldGetLastMessage() throws IOException { + client.updateConfig(); + + try (CloseableHttpResponse lastConfigChangesResponse = client.getLastConfigChanges(2)) { + String newAllConfigChangesString = client.getResponseContentAsString(lastConfigChangesResponse); + List<KafkaMessage> kafkaMessages = objectMapper + .readValue(newAllConfigChangesString, new TypeReference<List<KafkaMessage>>() { + }); + + assertThat(kafkaMessages).hasSize(2); + assertThat(kafkaMessages.get(0).getConfiguration()) + .contains("new value: /pnf-simulator:config/itemValue1 = 100"); + assertThat(kafkaMessages.get(1).getConfiguration()) + .contains("new value: /pnf-simulator:config/itemValue2 = 200"); + } + } + + @Test + public void testShouldLoadNewYangModelAndReconfigure() throws IOException { + try (CloseableHttpResponse response = client + .loadModel("newyangmodel", "newYangModel.yang", "initialConfig.xml")) { + assertResponseStatusCode(response, HttpStatus.OK); + + String original = client.getResponseContentAsString(response); + + assertThat(original).isEqualTo("\"Successfully started\"\n"); + } + } + + @Test + public void shouldGetLoadedModelByName() throws IOException { + testShouldLoadNewYangModelAndReconfigure(); + + try (CloseableHttpResponse response = client.getConfigByModelAndContainerNames("newyangmodel", "config2")) { + assertResponseStatusCode(response, HttpStatus.OK); + String config = client.getResponseContentAsString(response); + + assertThat(config).isEqualTo( + "<config2 xmlns=\"http://onap.org/newyangmodel\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" + + " <item1>100</item1>\n" + + "</config2>\n"); + } + + } + + private void assertResponseStatusCode(HttpResponse response, HttpStatus expectedStatus) { + assertThat(response.getStatusLine().getStatusCode()).isEqualTo(expectedStatus.value()); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/integration/NetconfSimulatorClient.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/integration/NetconfSimulatorClient.java new file mode 100644 index 000000000..61f2ef1d8 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/integration/NetconfSimulatorClient.java @@ -0,0 +1,150 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package integration; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.junit.platform.commons.logging.Logger; +import org.junit.platform.commons.logging.LoggerFactory; +import org.springframework.util.ResourceUtils; + +import java.io.IOException; +import java.time.Duration; +import java.time.Instant; + +class NetconfSimulatorClient { + + private CloseableHttpClient netconfClient; + private String simulatorBaseUrl; + private static final Logger LOG = LoggerFactory.getLogger(NetconfSimulatorClient.class); + + NetconfSimulatorClient(String simulatorBaseUrl) { + this.netconfClient = HttpClients.createDefault(); + this.simulatorBaseUrl = simulatorBaseUrl; + } + + CloseableHttpResponse loadModel(String moduleName, String yangModelFileName, String initialiConfigFileName) throws IOException { + String updateConfigUrl = String.format("%s/netconf/model/%s", simulatorBaseUrl, moduleName); + HttpPost httpPost = new HttpPost(updateConfigUrl); + HttpEntity updatedConfig = MultipartEntityBuilder + .create() + .addBinaryBody("yangModel", ResourceUtils.getFile(String.format("classpath:%s", yangModelFileName))) + .addBinaryBody("initialConfig", ResourceUtils.getFile(String.format("classpath:%s",initialiConfigFileName))) + .addTextBody("moduleName", moduleName) + .build(); + httpPost.setEntity(updatedConfig); + return netconfClient.execute(httpPost); + } + + CloseableHttpResponse deleteModel(String moduleName) throws IOException { + String deleteModuleUrl = String.format("%s/netconf/model/%s", simulatorBaseUrl, moduleName); + HttpDelete httpDelete = new HttpDelete(deleteModuleUrl); + return netconfClient.execute(httpDelete); + } + + boolean isServiceAvailable(Instant startTime, Duration maxWaitingDuration) throws InterruptedException { + boolean isServiceReady = false; + while (Duration.between(startTime, Instant.now()).compareTo(maxWaitingDuration) < 1){ + if(checkIfSimResponds()){ + return true; + } + else { + LOG.info(() -> "Simulator not ready yet, retrying in 5s..."); + Thread.sleep(5000); + } + } + return isServiceReady; + } + + private boolean checkIfSimResponds() throws InterruptedException { + try(CloseableHttpResponse pingResponse = getCurrentConfig()){ + String responseString = getResponseContentAsString(pingResponse); + if(pingResponse.getStatusLine().getStatusCode() == 200 && !responseString.trim().isEmpty()){ + return true; + } + } + catch(IOException ex){ + LOG.error(ex, () -> "EXCEPTION"); + Thread.sleep(5000); + } + return false; + } + + CloseableHttpResponse getCurrentConfig() throws IOException { + String netconfAddress = String.format("%s/netconf/get", simulatorBaseUrl); + HttpGet get = new HttpGet(netconfAddress); + return netconfClient.execute(get); + } + + CloseableHttpResponse getConfigByModelAndContainerNames(String model, String container) throws IOException { + String netconfAddress = String + .format("%s/netconf/get/%s/%s", simulatorBaseUrl, model, container); + HttpGet get = new HttpGet(netconfAddress); + return netconfClient.execute(get); + } + + CloseableHttpResponse updateConfig() throws IOException { + String updateConfigUrl = String.format("%s/netconf/edit-config", simulatorBaseUrl); + HttpPost httpPost = new HttpPost(updateConfigUrl); + HttpEntity updatedConfig = MultipartEntityBuilder + .create() + .addBinaryBody("editConfigXml", ResourceUtils.getFile("classpath:updatedConfig.xml")) + .build(); + httpPost.setEntity(updatedConfig); + return netconfClient.execute(httpPost); + } + + CloseableHttpResponse getAllConfigChanges() throws IOException { + String netconfStoreCmHistoryAddress = String.format("%s/store/cm-history", simulatorBaseUrl); + HttpGet configurationChangesResponse = new HttpGet(netconfStoreCmHistoryAddress); + return netconfClient.execute(configurationChangesResponse); + } + + CloseableHttpResponse getLastConfigChanges(int howManyLastChanges) throws IOException { + String netconfStoreCmHistoryAddress = String.format("%s/store/less?offset=%d", simulatorBaseUrl, howManyLastChanges); + HttpGet configurationChangesResponse = new HttpGet(netconfStoreCmHistoryAddress); + return netconfClient.execute(configurationChangesResponse); + } + + void releaseClient() throws IOException { + netconfClient.close(); + } + + void reinitializeClient(){ + netconfClient = HttpClients.createDefault(); + } + + String getResponseContentAsString(HttpResponse response) throws IOException { + HttpEntity entity = response.getEntity(); + String entityStringRepr = EntityUtils.toString(entity); + EntityUtils.consume(entity); + return entityStringRepr; + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/EmbeddedKafkaConfig.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/EmbeddedKafkaConfig.java new file mode 100644 index 000000000..5ddf2b2a6 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/EmbeddedKafkaConfig.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka; + + +import java.util.Map; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.test.utils.KafkaTestUtils; + +import static org.onap.netconfsimulator.kafka.StoreServiceTest.embeddedKafka; + +@Configuration +class EmbeddedKafkaConfig { + + @Bean + KafkaTemplate<String, String> kafkaTemplate(){ + return new KafkaTemplate<>(producerFactory()); + } + + @Bean + @Autowired + ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerContainerFactory(ConsumerFactory<String, String> consumerFactory){ + ConcurrentKafkaListenerContainerFactory<String, String> containerFactory = new ConcurrentKafkaListenerContainerFactory<>(); + containerFactory.setConsumerFactory(consumerFactory); + return containerFactory; + } + + @Bean + ConsumerFactory<String, String> consumerFactory(){ + Map<String, Object> consumerProperties = + KafkaTestUtils.consumerProps("sender", "false", embeddedKafka.getEmbeddedKafka()); + consumerProperties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + return new DefaultKafkaConsumerFactory<>(consumerProperties); + } + + private ProducerFactory<String, String> producerFactory() { + Map<String, Object> senderProperties = + KafkaTestUtils.senderProps(embeddedKafka.getEmbeddedKafka().getBrokersAsString()); + return new DefaultKafkaProducerFactory<>(senderProperties); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/StoreControllerTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/StoreControllerTest.java new file mode 100644 index 000000000..02eec12ac --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/StoreControllerTest.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka; + +import java.time.Instant; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.assertj.core.util.Lists; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.mockito.Mockito.when; + +@RunWith(SpringJUnit4ClassRunner.class) +public class StoreControllerTest { + + private static final String MESSAGE_3 = "message 3"; + private static final String MESSAGE_2 = "message 2"; + private static final String MESSAGE_1 = "message 1"; + + private static final List<MessageDTO> ALL_MESSAGES = Lists.newArrayList(new MessageDTO(Instant.now().getEpochSecond(), MESSAGE_1), + new MessageDTO(Instant.now().getEpochSecond(), MESSAGE_2), + new MessageDTO(Instant.now().getEpochSecond(), MESSAGE_3)); + + @Mock + private StoreService service; + + @InjectMocks + private StoreController storeController; + + + @Test + public void lessShouldTakeAllMessagesTest() { + when(service.getLastMessages(3)).thenReturn(ALL_MESSAGES); + + List<MessageDTO> lessResponse = storeController.less(3); + + assertResponseContainsExpectedMessages(lessResponse, 3, MESSAGE_1, MESSAGE_2, MESSAGE_3); + } + + @Test + public void lessShouldTakeTwoMessagesTest() { + when(service.getLastMessages(2)).thenReturn(Lists.newArrayList(new MessageDTO(Instant.now().getEpochSecond(), MESSAGE_1))); + + List<MessageDTO> lessResult = storeController.less(2); + + assertResponseContainsExpectedMessages(lessResult, 1, MESSAGE_1); + } + + @Test + public void shouldGetAllMessages(){ + when(service.getAllMessages()).thenReturn(ALL_MESSAGES); + + List<MessageDTO> allMsgResult = storeController.getAllConfigurationChanges(); + + assertResponseContainsExpectedMessages(allMsgResult, 3, MESSAGE_1, MESSAGE_2, MESSAGE_3); + } + + private void assertResponseContainsExpectedMessages(List<MessageDTO> actualMessages, int expectedMessageCount, String... expectedMessages){ + Assertions.assertThat(actualMessages.stream().map(MessageDTO::getConfiguration)) + .hasSize(expectedMessageCount) + .containsExactly(expectedMessages); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/StoreServiceTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/StoreServiceTest.java new file mode 100644 index 000000000..fd36116a8 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/StoreServiceTest.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka; + +import org.bitbucket.radistao.test.annotation.BeforeAllMethods; +import org.bitbucket.radistao.test.runner.BeforeAfterSpringTestRunner; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.kafka.test.rule.EmbeddedKafkaRule; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(BeforeAfterSpringTestRunner.class) +@SpringBootTest(classes = {StoreService.class, EmbeddedKafkaConfig.class}) +@EmbeddedKafka +public class StoreServiceTest { + + private static final String MESSAGE_1 = "message1"; + private static final String MESSAGE_2 = "message2"; + private static final String MESSAGE_3 = "message3"; + + @ClassRule + public static EmbeddedKafkaRule embeddedKafka = new EmbeddedKafkaRule(1, true, 1, "config"); + + @Autowired + StoreService service; + + @Autowired + KafkaTemplate<String, String> kafkaTemplate; + + @BeforeAllMethods + public void setupBeforeAll() { + prepareProducer(); + } + + @Test + public void testShouldReturnAllAvailableMessages(){ + + List<MessageDTO> actualMessages = service.getAllMessages(); + + assertResponseContainsExpectedMessages(actualMessages, 3, MESSAGE_1, MESSAGE_2, MESSAGE_3); + } + + @Test + public void testShouldGetLastMessagesRespectingOffset(){ + + List<MessageDTO> wantedLastMsg = service.getLastMessages(1L); + + assertResponseContainsExpectedMessages(wantedLastMsg, 1, MESSAGE_3); + } + + @Test + public void testShouldGetAll3Messages() { + List<MessageDTO> wantedLastMsgs = service.getLastMessages(3L); + + assertResponseContainsExpectedMessages(wantedLastMsgs, 3, MESSAGE_1, MESSAGE_2, MESSAGE_3); + } + + private void prepareProducer(){ + kafkaTemplate.send("config", "message1"); + kafkaTemplate.send("config", "message2"); + kafkaTemplate.send("config", "message3"); + } + + private void assertResponseContainsExpectedMessages(List<MessageDTO> actualMessages, int expectedMessageCount, String... expectedMessages){ + assertThat(actualMessages.stream().map(MessageDTO::getConfiguration)) + .hasSize(expectedMessageCount) + .containsExactly(expectedMessages); + } + +} + + + + + + + diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerHandlerTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerHandlerTest.java new file mode 100644 index 000000000..fcb72666a --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/kafka/listener/KafkaListenerHandlerTest.java @@ -0,0 +1,87 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.kafka.listener; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.MockitoAnnotations.initMocks; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.listener.ContainerProperties; +import org.springframework.kafka.listener.KafkaMessageListenerContainer; +import org.springframework.kafka.listener.MessageListener; + +class KafkaListenerHandlerTest { + + private static final String CLIENT_ID_REGEX = "[0-9]{10,}"; + private static final String SAMPLE_TOPIC = "sampleTopic"; + + @Mock + private ConsumerFactory<String, String> consumerFactory; + + @Mock + private KafkaMessageListenerContainer<String, String> kafkaMessageListenerContainer; + + @Mock + private MessageListener messageListener; + + @BeforeEach + void setUp() { + initMocks(this); + } + + + @Test + void shouldProperlyCreateKafkaListener() { + KafkaListenerHandler kafkaListenerHandler = spy(new KafkaListenerHandler(consumerFactory)); + doReturn(kafkaMessageListenerContainer).when(kafkaListenerHandler) + .createListenerContainer(any(ContainerProperties.class), eq(SAMPLE_TOPIC)); + + KafkaListenerEntry kafkaListenerEntry = kafkaListenerHandler + .createKafkaListener(messageListener, SAMPLE_TOPIC); + + assertThat(kafkaListenerEntry.getListenerContainer()).isEqualTo(kafkaMessageListenerContainer); + assertThat(kafkaListenerEntry.getClientId()).matches(CLIENT_ID_REGEX); + } + + @Test + void shouldProperlyCreateContainer() { + KafkaListenerHandler kafkaListenerHandler = spy(new KafkaListenerHandler(consumerFactory)); + ContainerProperties containerProperties = new ContainerProperties(SAMPLE_TOPIC); + containerProperties.setMessageListener(mock(MessageListener.class)); + + KafkaMessageListenerContainer<String, String> listenerContainer = kafkaListenerHandler + .createListenerContainer(containerProperties, SAMPLE_TOPIC); + + ContainerProperties actualProperties = listenerContainer.getContainerProperties(); + assertThat(actualProperties.getTopics()).isEqualTo(containerProperties.getTopics()); + assertThat(actualProperties.getMessageListener()).isEqualTo(containerProperties.getMessageListener()); + } + + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/NetconfControllerTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/NetconfControllerTest.java new file mode 100644 index 000000000..73fb627ea --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/NetconfControllerTest.java @@ -0,0 +1,172 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.tailf.jnc.JNCException; +import java.io.IOException; +import java.nio.file.Files; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.onap.netconfsimulator.netconfcore.configuration.NetconfConfigurationService; +import org.onap.netconfsimulator.netconfcore.model.LoadModelResponse; +import org.onap.netconfsimulator.netconfcore.model.NetconfModelLoaderService; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.util.ResourceUtils; +import org.springframework.web.multipart.MultipartFile; + +class NetconfControllerTest { + + private MockMvc mockMvc; + + @Mock + private NetconfConfigurationService netconfService; + + @Mock + private NetconfModelLoaderService netconfModelLoaderService; + + @InjectMocks + private NetconfController controller; + + private static final String SAMPLE_CONFIGURATION = "<config xmlns=\"http://onap.org/pnf-simulator\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><itemValue1>11</itemValue1><itemValue2>22</itemValue2></config>"; + + @BeforeEach + void setUp() { + initMocks(this); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + void testShouldDigestMultipartFile() throws Exception { + byte[] bytes = + Files.readAllBytes(ResourceUtils.getFile("classpath:updatedConfig.xml").toPath()); + MockMultipartFile file = new MockMultipartFile("editConfigXml", bytes); + + mockMvc + .perform(MockMvcRequestBuilders.multipart("/netconf/edit-config").file(file)) + .andExpect(status().isAccepted()); + + verify(netconfService).editCurrentConfiguration(any(MultipartFile.class)); + } + + @Test + void testShouldThrowExceptionWhenEditConfigFileWithIncorrectNameProvided() throws Exception { + MockMultipartFile file = new MockMultipartFile("wrongName", new byte[0]); + + mockMvc + .perform(MockMvcRequestBuilders.multipart("/netconf/edit-config").file(file)) + .andExpect(status().isBadRequest()); + + verify(netconfService, never()).editCurrentConfiguration(any(MultipartFile.class)); + } + + @Test + void testShouldReturnCurrentConfiguration() throws Exception { + when(netconfService.getCurrentConfiguration()).thenReturn(SAMPLE_CONFIGURATION); + + String contentAsString = + mockMvc + .perform(get("/netconf/get")) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); + + verify(netconfService).getCurrentConfiguration(); + assertThat(contentAsString).isEqualTo(SAMPLE_CONFIGURATION); + } + + @Test + void testShouldReturnConfigurationForGivenPath() throws Exception { + when(netconfService.getCurrentConfiguration("sampleModel", "sampleContainer")) + .thenReturn(SAMPLE_CONFIGURATION); + + String contentAsString = + mockMvc + .perform(get("/netconf/get/sampleModel/sampleContainer")) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); + + verify(netconfService).getCurrentConfiguration("sampleModel", "sampleContainer"); + assertThat(contentAsString).isEqualTo(SAMPLE_CONFIGURATION); + } + + @Test + void testShouldRaiseBadRequestWhenConfigurationIsNotPresent() throws Exception { + when(netconfService.getCurrentConfiguration("sampleModel", "sampleContainer2")) + .thenThrow(new JNCException(JNCException.ELEMENT_MISSING, "/sampleModel:sampleContainer2")); + + String contentAsString = + mockMvc + .perform(get("/netconf/get/sampleModel/sampleContainer2")) + .andExpect(status().isBadRequest()) + .andReturn() + .getResponse() + .getContentAsString(); + + assertThat(contentAsString).isEqualTo("Element does not exists: /sampleModel:sampleContainer2"); + } + + @Test + void shouldThrowExceptionWhenNoConfigurationPresent() throws IOException, JNCException { + when(netconfService.getCurrentConfiguration()).thenThrow(JNCException.class); + + assertThatThrownBy(() -> mockMvc.perform(get("/netconf/get"))) + .hasRootCauseExactlyInstanceOf(JNCException.class); + } + + @Test + void testShouldDeleteYangModel() throws Exception { + String responseOkString = "Alles klar"; + String yangModelName = "someModel"; + LoadModelResponse loadModelResponse = new LoadModelResponse(200, responseOkString); + String uri = String.format("/netconf/model/%s", yangModelName); + when(netconfModelLoaderService.deleteYangModel(yangModelName)).thenReturn(loadModelResponse); + + String contentAsString = + mockMvc + .perform(delete(uri)) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getContentAsString(); + + verify(netconfModelLoaderService).deleteYangModel(yangModelName); + assertThat(contentAsString).isEqualTo(responseOkString); + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationEditorTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationEditorTest.java new file mode 100644 index 000000000..371bdd84b --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationEditorTest.java @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.configuration; + +import com.tailf.jnc.Element; +import com.tailf.jnc.JNCException; +import com.tailf.jnc.NetconfSession; +import com.tailf.jnc.XMLParser; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.onap.netconfsimulator.netconfcore.configuration.NetconfConfigurationEditor; +import org.springframework.util.ResourceUtils; +import org.xml.sax.InputSource; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.file.Files; + +import static org.mockito.Mockito.verify; +import static org.mockito.MockitoAnnotations.initMocks; + +class NetconfConfigurationEditorTest { + + @Mock + private NetconfSession session; + @Mock + private NetconfSessionHelper netconfSessionHelper; + + private NetconfConfigurationEditor editor; + + @BeforeEach + void setUp() throws IOException, JNCException { + initMocks(this); + NetconfConnectionParams params = null; + Mockito.when(netconfSessionHelper.createNetconfSession(params)).thenReturn(session); + editor = new NetconfConfigurationEditor(params, netconfSessionHelper); + } + + @Test + void testShouldEditConfigSuccessfully() throws IOException, JNCException { + byte[] bytes = + Files.readAllBytes(ResourceUtils.getFile("classpath:updatedConfig.xml").toPath()); + Element editConfigXml = new XMLParser().parse(new InputSource(new ByteArrayInputStream(bytes))); + + editor.editConfig(editConfigXml); + + verify(session).editConfig(editConfigXml); + } +} diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationReaderTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationReaderTest.java index 65b2bc32e..a0a15b993 100644 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationReaderTest.java +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationReaderTest.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,12 @@ * ============LICENSE_END========================================================= */ -package org.onap.pnfsimulator.netconfmonitor.netconf; +package org.onap.netconfsimulator.netconfcore.configuration; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -33,6 +35,7 @@ import java.io.IOException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; class NetconfConfigurationReaderTest { @@ -43,28 +46,49 @@ class NetconfConfigurationReaderTest { @Mock private NetconfSession netconfSession; + + @Mock + private NetconfSessionHelper netconfSessionHelper; + @Mock private NodeSet nodeSet; + @Mock private Element element; @BeforeEach - void setup() { + void setUp() throws IOException, JNCException { MockitoAnnotations.initMocks(this); - reader = new NetconfConfigurationReader(netconfSession, NETCONF_MODEL_PATH); + NetconfConnectionParams params = null; + Mockito.when(netconfSessionHelper.createNetconfSession(params)).thenReturn(netconfSession); + reader = new NetconfConfigurationReader(params, netconfSessionHelper); } @Test void properlyReadXML() throws IOException, JNCException { - when(netconfSession.getConfig(anyString())).thenReturn(nodeSet); + when(netconfSession.getConfig()).thenReturn(nodeSet); + when(nodeSet.toXMLString()).thenReturn(EXPECTED_STRING_XML); + + String result = reader.getRunningConfig(); + + verify(netconfSession).getConfig(); + verify(nodeSet).toXMLString(); + assertThat(result).isEqualTo(EXPECTED_STRING_XML); + } + + @Test + void shouldProperlyReadXmlByName() throws IOException, JNCException { + when(netconfSession.getConfig("/sample:test")).thenReturn(nodeSet); when(nodeSet.first()).thenReturn(element); when(element.toXMLString()).thenReturn(EXPECTED_STRING_XML); - String result = reader.read(); + String result = reader.getRunningConfig("/sample:test"); - verify(netconfSession).getConfig(anyString()); - verify(nodeSet).first(); + verify(netconfSession).getConfig("/sample:test"); + verify(nodeSet, times(2)).first(); verify(element).toXMLString(); - assertEquals(EXPECTED_STRING_XML, result); + + assertThat(result).isEqualTo(EXPECTED_STRING_XML); } -}
\ No newline at end of file + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationServiceTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationServiceTest.java new file mode 100644 index 000000000..6da65728e --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/configuration/NetconfConfigurationServiceTest.java @@ -0,0 +1,102 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.tailf.jnc.Element; +import com.tailf.jnc.JNCException; +import java.io.IOException; +import java.nio.file.Files; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.util.ResourceUtils; + +class NetconfConfigurationServiceTest { + + @Mock + NetconfConfigurationReader reader; + + @Mock + NetconfConfigurationEditor editor; + + @InjectMocks + NetconfConfigurationService service; + + private static String CURRENT_CONFIG_XML_STRING = + "<config xmlns=\"http://onap.org/pnf-simulator\" xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n" + + " <itemValue1>100</itemValue1>\n" + + " <itemValue2>200</itemValue2>\n" + + "</config>\n"; + + @BeforeEach + void setUp() { + initMocks(this); + } + + @Test + void testShouldReturnCorrectCurrentConfiguration() throws IOException, JNCException { + String expectedConfiguration = CURRENT_CONFIG_XML_STRING; + when(reader.getRunningConfig()).thenReturn(CURRENT_CONFIG_XML_STRING); + + String actualCurrentConfiguration = service.getCurrentConfiguration(); + + assertThat(actualCurrentConfiguration).isEqualToIgnoringCase(expectedConfiguration); + } + + @Test + void testShouldThrowExceptionWhenCurrentConfigurationDoesNotExists() throws IOException, JNCException{ + when(reader.getRunningConfig()).thenThrow(JNCException.class); + + assertThatThrownBy(() -> service.getCurrentConfiguration()).isInstanceOf(JNCException.class); + } + + @Test + void testShouldEditConfigurationSuccessfully() throws IOException, JNCException{ + byte[] bytes = + Files.readAllBytes(ResourceUtils.getFile("classpath:updatedConfig.xml").toPath()); + MockMultipartFile editConfigXmlContent = new MockMultipartFile("editConfigXml", bytes); + ArgumentCaptor<Element> elementCaptor = ArgumentCaptor.forClass(Element.class); + doNothing().when(editor).editConfig(elementCaptor.capture()); + + service.editCurrentConfiguration(editConfigXmlContent); + + assertThat(elementCaptor.getValue().toXMLString()).isEqualTo(CURRENT_CONFIG_XML_STRING); + } + + @Test + void testShouldRaiseExceptionWhenMultipartFileIsInvalidXmlFile() throws IOException { + byte[] bytes = + Files.readAllBytes(ResourceUtils.getFile("classpath:invalidXmlFile.xml").toPath()); + MockMultipartFile editConfigXmlContent = new MockMultipartFile("editConfigXml", bytes); + + assertThatThrownBy(() -> service.editCurrentConfiguration(editConfigXmlContent)).isInstanceOf(JNCException.class); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/model/NetconfModelLoaderServiceTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/model/NetconfModelLoaderServiceTest.java new file mode 100644 index 000000000..a10876b98 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/netconfcore/model/NetconfModelLoaderServiceTest.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.netconfcore.model; + + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpRequestBase; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.web.multipart.MultipartFile; + +class NetconfModelLoaderServiceTest { + + @Mock + private HttpClient httpClient; + + private NetconfModelLoaderService modelLoaderService; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + modelLoaderService = new NetconfModelLoaderService(httpClient); + } + + + @Test + void shouldSendMultipartToServer() throws IOException { + //given + String loadModelAddress = modelLoaderService.getBackendAddress(); + makeMockClientReturnStatusOk(httpClient, HttpPost.class); + ArgumentCaptor<HttpPost> postArgumentCaptor = ArgumentCaptor.forClass(HttpPost.class); + MultipartFile yangMmodel = mock(MultipartFile.class); + MultipartFile initialConfig = mock(MultipartFile.class); + String moduleName = "moduleName"; + when(yangMmodel.getInputStream()).thenReturn(getEmptyImputStream()); + when(initialConfig.getInputStream()).thenReturn(getEmptyImputStream()); + + //when + LoadModelResponse response = modelLoaderService.loadYangModel(yangMmodel, initialConfig, moduleName); + + //then + verify(httpClient).execute(postArgumentCaptor.capture()); + HttpPost sentPost = postArgumentCaptor.getValue(); + assertThat(response.getStatusCode()).isEqualTo(200); + assertThat(response.getMessage()).isEqualTo(""); + assertThat(sentPost.getURI().toString()).isEqualTo(loadModelAddress); + assertThat(sentPost.getEntity().getContentType().getElements()[0].getName()).isEqualTo("multipart/form-data"); + } + + @Test + void shouldSendDeleteRequestToServer() throws IOException { + //given + String yangModelName = "sampleModel"; + String deleteModelAddress = modelLoaderService.getDeleteAddress(yangModelName); + makeMockClientReturnStatusOk(httpClient, HttpDelete.class); + ArgumentCaptor<HttpDelete> deleteArgumentCaptor = ArgumentCaptor.forClass(HttpDelete.class); + + //when + LoadModelResponse response = modelLoaderService.deleteYangModel(yangModelName); + + //then + verify(httpClient).execute(deleteArgumentCaptor.capture()); + HttpDelete sendDelete = deleteArgumentCaptor.getValue(); + assertThat(response.getStatusCode()).isEqualTo(200); + assertThat(response.getMessage()).isEqualTo(""); + assertThat(sendDelete.getURI().toString()).isEqualTo(deleteModelAddress); + } + + private void makeMockClientReturnStatusOk(HttpClient client, + Class<? extends HttpRequestBase> httpMethodClass) throws IOException { + HttpResponse httpResponse = mock(HttpResponse.class); + StatusLine mockStatus = mock(StatusLine.class); + HttpEntity mockEntity = mock(HttpEntity.class); + + when(client.execute(any(httpMethodClass))).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(mockStatus); + when(mockStatus.getStatusCode()).thenReturn(200); + when(httpResponse.getEntity()).thenReturn(mockEntity); + when(mockEntity.getContent()).thenReturn(getEmptyImputStream()); + } + + private InputStream getEmptyImputStream() { + return new ByteArrayInputStream("".getBytes()); + } + +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/websocket/NetconfEndpointTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/websocket/NetconfEndpointTest.java new file mode 100644 index 000000000..c1484d4b2 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/websocket/NetconfEndpointTest.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.netconfsimulator.websocket; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.Map; +import java.util.Optional; +import javax.websocket.CloseReason; +import javax.websocket.EndpointConfig; +import javax.websocket.RemoteEndpoint; +import javax.websocket.Session; +import org.apache.kafka.common.Metric; +import org.apache.kafka.common.MetricName; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.onap.netconfsimulator.kafka.listener.KafkaListenerEntry; +import org.onap.netconfsimulator.kafka.listener.KafkaListenerHandler; +import org.onap.netconfsimulator.websocket.message.NetconfMessageListener; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.listener.AbstractMessageListenerContainer; + +import org.springframework.kafka.listener.ContainerProperties; +import org.springframework.kafka.listener.GenericMessageListener; + +class NetconfEndpointTest { + + + @Mock + private KafkaListenerHandler kafkaListenerHandler; + + @Mock + private Session session; + + @Mock + private EndpointConfig endpointConfig; + + @Mock + private RemoteEndpoint.Basic remoteEndpoint; + + + @BeforeEach + void setUp() { + initMocks(this); + } + + + @Test + void shouldCreateKafkaListenerWhenClientInitializeConnection() { + NetconfEndpoint netconfEndpoint = new NetconfEndpoint(kafkaListenerHandler); + AbstractMessageListenerContainer abstractMessageListenerContainer = getListenerContainer(); + when(session.getBasicRemote()).thenReturn(remoteEndpoint); + KafkaListenerEntry kafkaListenerEntry = new KafkaListenerEntry("sampleGroupId", + abstractMessageListenerContainer); + when(kafkaListenerHandler.createKafkaListener(any(NetconfMessageListener.class), eq("config"))) + .thenReturn(kafkaListenerEntry); + + netconfEndpoint.onOpen(session, endpointConfig); + + assertThat(netconfEndpoint.getEntry().get().getClientId()).isEqualTo("sampleGroupId"); + assertThat(netconfEndpoint.getEntry().get().getListenerContainer()).isEqualTo(abstractMessageListenerContainer); + + verify(abstractMessageListenerContainer).start(); + } + + + @Test + void shouldCloseListenerWhenClientDisconnects() { + NetconfEndpoint netconfEndpoint = new NetconfEndpoint(kafkaListenerHandler); + AbstractMessageListenerContainer abstractMessageListenerContainer = getListenerContainer(); + netconfEndpoint.setEntry( Optional.of(new KafkaListenerEntry("sampleGroupId", abstractMessageListenerContainer)) ); + + netconfEndpoint.onClose(session, mock(CloseReason.class)); + + verify(abstractMessageListenerContainer).stop(); + } + + class TestAbstractMessageListenerContainer extends AbstractMessageListenerContainer { + + + TestAbstractMessageListenerContainer(ContainerProperties containerProperties) { + super(mock(ConsumerFactory.class),containerProperties); + } + + @Override + protected void doStart() { + + } + + @Override + protected void doStop(Runnable callback) { + + } + + @Override + public Map<String, Map<MetricName, ? extends Metric>> metrics() { + return null; + } + } + + private AbstractMessageListenerContainer getListenerContainer() { + ContainerProperties containerProperties = new ContainerProperties("config"); + containerProperties.setGroupId("sample"); + containerProperties.setMessageListener(mock(GenericMessageListener.class)); + TestAbstractMessageListenerContainer testAbstractMessageListenerContainer = new TestAbstractMessageListenerContainer( + containerProperties); + return spy(testAbstractMessageListenerContainer); + } +} diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/websocket/message/NetconfMessageListenerTest.java index a4fb9eb04..bb040d1e3 100644 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/java/org/onap/netconfsimulator/websocket/message/NetconfMessageListenerTest.java @@ -1,15 +1,15 @@ -/* +/*- * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER + * Simulator * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2019 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,54 +18,56 @@ * ============LICENSE_END========================================================= */ -package org.onap.pnfsimulator.simulator.client; +package org.onap.netconfsimulator.websocket.message; + import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.MockitoAnnotations.initMocks; import java.io.IOException; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; +import javax.websocket.EncodeException; +import javax.websocket.RemoteEndpoint; +import org.apache.kafka.clients.consumer.ConsumerRecord; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; import org.mockito.Mock; +import org.onap.netconfsimulator.kafka.model.KafkaMessage; -class HttpClientAdapterImplTest { - private HttpClientAdapter adapter; +class NetconfMessageListenerTest { + + private static final ConsumerRecord<String, String> KAFKA_RECORD = new ConsumerRecord<>("sampleTopic", 0, 0, + "sampleKey", "sampleValue"); @Mock - private HttpClient httpClient; - @Mock - private HttpResponse httpResponse; + private RemoteEndpoint.Basic remoteEndpoint; + + @InjectMocks + private NetconfMessageListener netconfMessageListener; + @BeforeEach - void setup() { + void setUp() { initMocks(this); - adapter = new HttpClientAdapterImpl(httpClient); } - @Test - void send_should_successfully_send_request_given_valid_url() throws IOException { - doReturn(httpResponse).when(httpClient).execute(any()); - adapter.send("test-msg", "http://valid-url"); + @Test + void shouldProperlyParseAndSendConsumerRecord() throws IOException, EncodeException { + netconfMessageListener.onMessage(KAFKA_RECORD); - verify(httpClient).execute(any()); - verify(httpResponse).getStatusLine(); + verify(remoteEndpoint).sendObject(any(KafkaMessage.class)); } - @Test - void send_should_not_send_request_given_invalid_url() throws IOException { - doThrow(new IOException("test")).when(httpClient).execute(any()); - adapter.send("test-msg", "http://invalid-url"); - verify(httpClient).execute(any()); - verify(httpResponse, never()).getStatusLine(); + @Test + void shouldNotPropagateEncodeException() throws IOException, EncodeException { + doThrow(new EncodeException("","")).when(remoteEndpoint).sendObject(any(KafkaMessage.class)); + + netconfMessageListener.onMessage(KAFKA_RECORD); } } diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/application-it.properties b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/application-it.properties new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/application-it.properties diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/initialConfig.xml b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/initialConfig.xml new file mode 100644 index 000000000..f28a1a0a8 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/initialConfig.xml @@ -0,0 +1,23 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<config2 xmlns="http://onap.org/newyangmodel"> + <item1>100</item1> +</config2> diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/invalidXmlFile.xml b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/invalidXmlFile.xml new file mode 100644 index 000000000..3debd8c26 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/invalidXmlFile.xml @@ -0,0 +1,23 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<config xmlns="http://onap.org/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>100</itemValue1> +<config> diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/newYangModel.yang b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/newYangModel.yang new file mode 100644 index 000000000..bbe66c3ae --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/newYangModel.yang @@ -0,0 +1,8 @@ +module newyangmodel { + namespace "http://onap.org/newyangmodel"; + prefix config2; + container config2 { + config true; + leaf item1 {type uint32;} + } +} diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/updatedConfig.xml b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/updatedConfig.xml new file mode 100644 index 000000000..628a710fd --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/updatedConfig.xml @@ -0,0 +1,24 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<config xmlns="http://onap.org/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>100</itemValue1> + <itemValue2>200</itemValue2> +</config> diff --git a/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/updatedConfigForCmHistory.xml b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/updatedConfigForCmHistory.xml new file mode 100644 index 000000000..5bc0e4285 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/src/test/resources/updatedConfigForCmHistory.xml @@ -0,0 +1,24 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<config xmlns="http://onap.org/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>500</itemValue1> + <itemValue2>1000</itemValue2> +</config> diff --git a/test/mocks/pnfsimulator/ssh/ssh_host_rsa_key b/test/mocks/pnfsimulator/netconfsimulator/ssh/ssh_host_rsa_key index dbf8d7635..dbf8d7635 100644 --- a/test/mocks/pnfsimulator/ssh/ssh_host_rsa_key +++ b/test/mocks/pnfsimulator/netconfsimulator/ssh/ssh_host_rsa_key diff --git a/test/mocks/pnfsimulator/ssh/ssh_host_rsa_key.pub b/test/mocks/pnfsimulator/netconfsimulator/ssh/ssh_host_rsa_key.pub index 8f739114b..8f739114b 100644 --- a/test/mocks/pnfsimulator/ssh/ssh_host_rsa_key.pub +++ b/test/mocks/pnfsimulator/netconfsimulator/ssh/ssh_host_rsa_key.pub diff --git a/test/mocks/pnfsimulator/netconfsimulator/tls/ca.crt b/test/mocks/pnfsimulator/netconfsimulator/tls/ca.crt new file mode 100644 index 000000000..62593ab7c --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/tls/ca.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7TCCAtWgAwIBAgIJAMtE1NGAR5KoMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD +VQQGEwJDWjEWMBQGA1UECAwNU291dGggTW9yYXZpYTENMAsGA1UEBwwEQnJubzEP +MA0GA1UECgwGQ0VTTkVUMQwwCgYDVQQLDANUTUMxEzARBgNVBAMMCmV4YW1wbGUg +Q0ExIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVjYUBsb2NhbGhvc3QwHhcNMTQwNzI0 +MTQxOTAyWhcNMjQwNzIxMTQxOTAyWjCBjDELMAkGA1UEBhMCQ1oxFjAUBgNVBAgM +DVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoMBkNFU05FVDEM +MAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJKoZIhvcNAQkB +FhNleGFtcGxlY2FAbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEArD3TDHPAMT2Z84orK4lMlarbgooIUCcRZyLe+QM+8KY8Hn+mGaxPEOTS +L3ywszqefB/Utm2hPKLHX684iRC14ID9WDGHxPjvoPArhgFhfV+qnPfxKTgxZC12 +uOj4u1V9y+SkTCocFbRfXVBGpojrBuDHXkDMDEWNvr8/52YCv7bGaiBwUHolcLCU +bmtKILCG0RNJyTaJpXQdAeq5Z1SJotpbfYFFtAXB32hVoLug1dzl2tjG9sb1wq3Q +aDExcbC5w6P65qOkNoyym9ne6QlQagCqVDyFn3vcqkRaTjvZmxauCeUxXgJoXkyW +cm0lM1KMHdoTArmchw2Dz0yHHSyDAQIDAQABo1AwTjAdBgNVHQ4EFgQUc1YQIqjZ +sHVwlea0AB4N+ilNI2gwHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAI/1KH60qnw9Xs2RGfi0/ +IKf5EynXt4bQX8EIyVKwSkYKe04zZxYfLIl/Q2HOPYoFmm3daj5ddr0ZS1i4p4fT +UhstjsYWvXs3W/HhVmFUslakkn3PrswhP77fCk6eEJLxdfyJ1C7Uudq2m1isZbKi +h+XF0mG1LxJaDMocSz4eAya7M5brwjy8DoOmA1TnLQFCVcpn+sCr7VC4wE/JqxyV +hBCk/MuGqqM3B1j90bGFZ112ZOecyE0EDSr6IbiRBtmeNbEwOFjKXhNLYdxpBZ9D +8A/368OckZkCrVLGuJNxK9UwCVTe8IhotHUqU9EqFDmxdV8oIdU/OzUwwNPA/Bd/ +9g== +-----END CERTIFICATE----- diff --git a/test/mocks/pnfsimulator/netconfsimulator/tls/server_cert.crt b/test/mocks/pnfsimulator/netconfsimulator/tls/server_cert.crt new file mode 100644 index 000000000..c0e03a3f0 --- /dev/null +++ b/test/mocks/pnfsimulator/netconfsimulator/tls/server_cert.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCQ1ox +FjAUBgNVBAgMDVNvdXRoIE1vcmF2aWExDTALBgNVBAcMBEJybm8xDzANBgNVBAoM +BkNFU05FVDEMMAoGA1UECwwDVE1DMRMwEQYDVQQDDApleGFtcGxlIENBMSIwIAYJ +KoZIhvcNAQkBFhNleGFtcGxlY2FAbG9jYWxob3N0MB4XDTE1MDczMDA3MjU1MFoX +DTM1MDcyNTA3MjU1MFowgYUxCzAJBgNVBAYTAkNaMRYwFAYDVQQIDA1Tb3V0aCBN +b3JhdmlhMQ8wDQYDVQQKDAZDRVNORVQxDDAKBgNVBAsMA1RNQzEXMBUGA1UEAwwO +ZXhhbXBsZSBzZXJ2ZXIxJjAkBgkqhkiG9w0BCQEWF2V4YW1wbGVzZXJ2ZXJAbG9j +YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdI1TBjzX1Pg +QXFuPCw5/kQwU7qkrhirMcFAXhI8EoXepPa9fKAVuMjHW32P6nNzDpnhFe0YGdNl +oIEN3hJJ87cVOqj4o7zZMbq3zVG2L8As7MTA8tYXm2fSC/0rIxxRRemcGUXM0q+4 +LEACjZj2pOKonaivF5VbhgNjPCO1Jj/TamUc0aViE577C9L9EiObGM+bGbabWk/K +WKLsvxUc+sKZXaJ7psTVgpggJAkUszlmwOQgFiMSR53E9/CAkQYhzGVCmH44Vs6H +zs3RZjOTbce4wr4ongiA5LbPeSNSCFjy9loKpaE1rtOjkNBVdiNPCQTmLuODXUTK +gkeL+9v/OwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVu +U1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU83qEtQDFzDvLoaII +vqiU6k7j1uswHwYDVR0jBBgwFoAUc1YQIqjZsHVwlea0AB4N+ilNI2gwDQYJKoZI +hvcNAQELBQADggEBAJ+QOLi4gPWGofMkLTqSsbv5xRvTw0xa/sJnEeiejtygAu3o +McAsyevSH9EYVPCANxzISPzd9SFaO56HxWgcxLn9vi8ZNvo2wIp9zucNu285ced1 +K/2nDZfBmvBxXnj/n7spwqOyuoIc8sR7P7YyI806Qsfhk3ybNZE5UHJFZKDRQKvR +J1t4nk9saeo87kIuNEDfYNdwYZzRfXoGJ5qIJQK+uJJv9noaIhfFowDW/G14Ji5p +Vh/YtvnOPh7aBjOj8jmzk8MqzK+TZgT7GWu48Nd/NaV8g/DNg9hlN047LaNsJly3 +NX3+VBlpMnA4rKwl1OnmYSirIVh9RJqNwqe6k/k= +-----END CERTIFICATE----- diff --git a/test/mocks/pnfsimulator/netopeer_tls_cfg/test_server_key.pem b/test/mocks/pnfsimulator/netconfsimulator/tls/server_key.pem index d61c77bdf..d61c77bdf 100644 --- a/test/mocks/pnfsimulator/netopeer_tls_cfg/test_server_key.pem +++ b/test/mocks/pnfsimulator/netconfsimulator/tls/server_key.pem diff --git a/test/mocks/pnfsimulator/netopeer_tls_cfg/entrypoint.sh b/test/mocks/pnfsimulator/netopeer_tls_cfg/entrypoint.sh deleted file mode 100755 index 45b30a1a1..000000000 --- a/test/mocks/pnfsimulator/netopeer_tls_cfg/entrypoint.sh +++ /dev/null @@ -1,2 +0,0 @@ -nohup /netopeer_tls_cfg/update_tls.sh & -exec /usr/bin/supervisord -c "/etc/supervisord.conf" diff --git a/test/mocks/pnfsimulator/netopeer_tls_cfg/mynetconf.data b/test/mocks/pnfsimulator/netopeer_tls_cfg/mynetconf.data deleted file mode 100644 index 63872eef9..000000000 --- a/test/mocks/pnfsimulator/netopeer_tls_cfg/mynetconf.data +++ /dev/null @@ -1,10 +0,0 @@ -{ - "mynetconf:netconflist": { - "netconf": [ - { - "netconf-id": 3, - "netconf-param": 3 - } - ] - } -} diff --git a/test/mocks/pnfsimulator/netopeer_tls_cfg/mynetconf.yang b/test/mocks/pnfsimulator/netopeer_tls_cfg/mynetconf.yang deleted file mode 100644 index a0c094b40..000000000 --- a/test/mocks/pnfsimulator/netopeer_tls_cfg/mynetconf.yang +++ /dev/null @@ -1,26 +0,0 @@ -module mynetconf { - yang-version 1.1; - namespace "urn:mynetconf:test"; - - prefix nft; - - organization "mynetconf"; - contact "my netconf address"; - description "yang model for mynetconf"; - revision "2019-03-01"{ - description "initial version"; - } - - container netconflist{ - list netconf{ - key netconf-id; - leaf netconf-id{ - type uint16; - } - leaf netconf-param { - type uint32; - } - } - - } -} diff --git a/test/mocks/pnfsimulator/netopeer_tls_cfg/test_server_key.pem.pub b/test/mocks/pnfsimulator/netopeer_tls_cfg/test_server_key.pem.pub deleted file mode 100644 index 9ccec4a0c..000000000 --- a/test/mocks/pnfsimulator/netopeer_tls_cfg/test_server_key.pem.pub +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdI1TBjzX1PgQXFuPCw5 -/kQwU7qkrhirMcFAXhI8EoXepPa9fKAVuMjHW32P6nNzDpnhFe0YGdNloIEN3hJJ -87cVOqj4o7zZMbq3zVG2L8As7MTA8tYXm2fSC/0rIxxRRemcGUXM0q+4LEACjZj2 -pOKonaivF5VbhgNjPCO1Jj/TamUc0aViE577C9L9EiObGM+bGbabWk/KWKLsvxUc -+sKZXaJ7psTVgpggJAkUszlmwOQgFiMSR53E9/CAkQYhzGVCmH44Vs6Hzs3RZjOT -bce4wr4ongiA5LbPeSNSCFjy9loKpaE1rtOjkNBVdiNPCQTmLuODXUTKgkeL+9v/ -OwIDAQAB ------END PUBLIC KEY----- diff --git a/test/mocks/pnfsimulator/netopeer_tls_cfg/update_tls.sh b/test/mocks/pnfsimulator/netopeer_tls_cfg/update_tls.sh deleted file mode 100755 index e0e1ac625..000000000 --- a/test/mocks/pnfsimulator/netopeer_tls_cfg/update_tls.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -sleep 20 -NETOPEER_CONFIG_PATH='/opt/dev/Netopeer2/server/configuration' -MOUNT_PATH='/netopeer_tls_cfg' -KEY_PATH='/usr/local/etc/keystored/keys' -SUBSCRIBE_APP_PATH='/opt/dev/sysrepo/build/examples/application_changes_example' - -# This function uploads test_data and model into netopeer2 server -upload_yang_data_model() -{ - sysrepoctl -i -g $MOUNT_PATH/mynetconf.yang - sleep 5 - echo ' subscribing to mynetconf model.' - $SUBSCRIBE_APP_PATH mynetconf > /dev/null & - sleep 5 - echo ' creating data for mynetconf model.' - sysrepocfg --datastore=running --format=json mynetconf --import=$MOUNT_PATH/mynetconf.data -} - -# This function configures server/trusted certificates into Netopeer -configure_tls() -{ - sed -i "s/>test</>netconf</g" $NETOPEER_CONFIG_PATH/tls_listen.xml - sysrepocfg --datastore=running --format=xml ietf-keystore --merge=$NETOPEER_CONFIG_PATH/load_server_certs.xml - sysrepocfg --datastore=running --format=xml ietf-netconf-server --merge=$NETOPEER_CONFIG_PATH/tls_listen.xml -} - -cp $MOUNT_PATH/test_server_key.pem $KEY_PATH -cp $MOUNT_PATH/test_server_key.pem.pub $KEY_PATH -configure_tls -upload_yang_data_model - diff --git a/test/mocks/pnfsimulator/pnfsimulator/.gitignore b/test/mocks/pnfsimulator/pnfsimulator/.gitignore new file mode 100644 index 000000000..3fa204a3b --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/.gitignore @@ -0,0 +1,4 @@ +.idea +target +*.iml +logs diff --git a/test/mocks/pnfsimulator/pnfsimulator/README.md b/test/mocks/pnfsimulator/pnfsimulator/README.md new file mode 100644 index 000000000..fadb2d4a3 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/README.md @@ -0,0 +1,299 @@ +# PNF Simulator +Simulator that generates VES events related to PNF PNP integration. + +## Usage of simulator +### Setting up +Preferred way to start simulator is to use `docker-compose up -d` command. +All required docker images will be downloaded from ONAP Nexus, however there is possibility to build those +images locally. It can be achieve by invoking `mvn clean package docker:build` from top directory. + +### API +Simulator provides REST endpoints which can be used to trigger sending events to VES. + +*Periodic event sending* +To trigger sending use following endpoint *http://<simulator_ip>:5000/simulator/start*. +Supported method: *POST* +Headers: + - Content-Type - application/json +Parameters: + + simulatorParams: + repeatCount - determines how many events will be sent + repeatInterval - time (in seconds) between events + vesServerUrl - valid path to VES Collector + templateName - name of template file (check *Templates* section) + patch - part of event which will be merged into template + + +Sample Request: + + { + "simulatorParams": { + "repeatCount": 5, + "repeatInterval": 2, + "vesServerUrl": "http://VES-HOST:8080/eventListener/v7" + }, + "templateName": "validExampleMeasurementEvent.json", + "patch": { + "event": { + "commonEventHeader": { + "eventId": "PATCHED_eventId", + "sourceName": "PATCHED_sourceName", + "version": 3.0 + } + } + } + } + +*One-time event sending* +Enables direct, immediate event sending without need to have template deployed on backend. +Keywords are supported,thus once passed, will also be substituted with proper strings. +Passed event body must be valid and complete event according to VES Collector interface. +To trigger sending use following endpoint *http://<simulator_ip>:5000/simulator/event*. + +Supported method: *POST* +Headers: + - Content-Type - application/json +Parameters: + + vesServerUrl - valid URL to VES Collector event listener + event - body of event to be sent directly to VES Collector (it can contain keyword expressions) + + +Sample Request: + + { + "vesServerUrl": "http://VES-HOST:8080/eventListener/v7", + "event": { + "commonEventHeader": { + "eventId": "#RandomString(20)", + "sourceName": "PATCHED_sourceName", + "version": 3.0 + } + } + } + +### Changing simulator configuration +Utility of default configuration has been introduced so as to facilitate sending requests. so far only vesServerUrl states default simulator configuration. +On simulator startup, vesServerUrl is initialized with default value, but must be replaced with correct VES server url by user. +Once vesServerUrl is properly set on simulator, this parameter does not need to be incorporated into every trigger event request. +If user does not provide vesServerUrl in trigger request, default value will be used. +If use does provide vesServerUrl in trigger request, then passed value will be used instead of default one (default value will not be overwritten by provided one). + +It is possible to get and update configuration (current target vesServerUrl) using offered REST API - */simulator/config* endpoint is exposed for that. +To get current configuration *GET* method must be used. +To update vesServerUrl *PUT* method is used, example request: + + { + "vesServerUrl": "http://10.154.164.117:8080/eventListener/v7" + } + +Note: passed vesServerUrl must be wellformed URL. + + +### Running simulator +The recommended way is to checkout PNF Simulator project from ONAP Git repository and use *simulator*.sh script. +If you copy *simulator.sh* script to another location, keep in mind to copy also *docker-compose.yml* and directories: *config and templates*. +In order to run simulator, invoke ./simulator.sh -e build to build required images and then invoke ./simulator.sh -e start +Script downloads if necessary needed Docker images and runs instances of these images. +After simulator start it is advisable to setup default value for target vesServerUrl. + +Example request: + + PUT to http://<simulator_ip>:<simulator_port>/simulator/config + + { + "vesServerUrl": "PUT HERE VALID URL TO YOUR VES EVENT LISTENER" + } + +### Templates +Template is a draft event. Merging event with patch will result in valid VES event. Template itself should be a correct VES event as well as valid json object. +In order to apply custom template, just copy it to ./templates directory. +*notification.json* and *registration.json* are available by default in *./templates* directory. + +#### Template management +The simulator provides means for managing templates. Supported actions: adding, editing (overriding) and deleting are available via HTTP endpoint */template* + +```GET /template/list``` +Lists all templates known to the simulator. + +```GET /template/get-content/{name}``` +Gets template content based on *name* path variable. + +```POST /template/upload?override=true``` +Saves template content under *name* path variable. The non-mandatory parameter *override* allows overwriting an existing template. + +Sample payload: +``` +{ + "name": "someTemplate", + "template": { + "commonEventHeader": { + "domain": "notification", + "eventName": "vFirewallBroadcastPackets" + }, + "notificationFields": { + "arrayOfNamedHashMap": [{ + "name": "A20161221.1031-1041.bin.gz", + "hashMap": { + "fileformatType": "org.3GPP.32.435#measCollec" + } + }] + } + } +} +``` + +### Searching for key-value conditions in stored templates +Simulator allows to search through stored templates and retrieve names of those that satisfy given criteria passed in form of key-value pairs (See examples below). +Following data types are supported in search as values: +-integer +-string +-double +-boolean +Searching for null values as well as incorporating regex expression with intention to find a match is not supported. +Search expression must be valid JSON, thus no duplicate keys are allowed - user could specify the same parameter multiple times, but only last occurrence will be applied to query. +Example search expression: + +{"domain": "notification", "sequence": 1, "startEpochMicrosec": 1531616794, "sampleDouble": 2.5} + +will find all templates that contain all of passed key-value entries. There is an AND condition beetwen given criteria - all of them must be satisfied to qualify template as matching item. + Keys of search expressions are searched in case insensitive way as well as string values. +Where it comes to values of numerical and boolean type exact match is expected. + +API usage: + +```POST /template/search``` +Produces query that returns templates that contain searched criteria + +Sample payload: +``` +{ + "searchExpr": { + "domain": "notification", + "sequence": 1, + "startEpochMicrosec": 1531616794, + "sampleDouble": 2.5 + } +} +``` +Sample response: +``` +[notification.json] +``` + + +Note: Manually deployed templates, or actually existing ones, but modified inside the templates catalog '/app/templates', will be automatically synchronized with schemas stored inside the database. That means that a user can dynamically change the template content using vi editor at simulator container, as well as use any editor at any machine and then push the changes to the template folder. All the changes will be processed 'on the fly' and accessible via the rest API. + +### Periodic events +Simulator has ability to send event periodically. Rest API support parameters: +* repeatCount - count of times that event will be sent to VES +* repeatInterval - interval (in second) between two events. +(Checkout example to see how to use them) + +### Patching +User is able to provide patch in request, which will be merged into template. + +Warning: Patch should be a valid json object (no json primitives nor json arrays are allowed as a full body of patch). + +This mechanism allows to override part of template. +If in "patch" section there are additional parameters (absent in template), those parameters with values will be added to event. +Patching mechanism supports also keywords that enables automatic value generation of appropriate type + +### Keyword support +Simulator supports corresponding keywords: +- \#RandomInteger(start,end) - substitutes keyword with random positive integer within given range (range borders inclusive) +- \#RandomPrimitiveInteger(start,end) - the same as #RandomInteger(start,end), but returns long as result +- \#RandomInteger - substitutes keyword with random positive integer +- \#RandomString(length) - substitutes keyword with random ASCII string with specified length +- \#RandomString - substitutes keyword with random ASCII string with length of 20 characters +- \#Timestamp - substitutes keyword with current timestamp in epoch (calculated just before sending event) +- \#TimestampPrimitive - the same as \#Timestamp, but returns long as result +- \#Increment - substitutes keyword with positive integer starting from 1 - for each consecutive event, value of increment property is incremented by 1 + +Additional hints and restrictions: +All keywords without 'Primitive' in name return string as result. To specify keyword with 2 arguments e.g. #RandomInteger(start,end) no whitespaces between arguments are allowed. +Maximal value of arguments for RandomInteger is limited to the java integer range. Minimal is always 0. (Negative values are prohibited and wont be treated as a correct parts of keyword). +RandomInteger with parameters will automatically find minimal and maximal value form the given attributes so no particular order of those is expected. + +How does it work? +When user do not want to fill in parameter values that are not relevant from user perspective but are mandatory by end system, then keyword feature should be used. +In template, keyword strings are substituted in runtime with appropriate values autogenerated by simulator. +Example can be shown below: + +Example template with keywords: + + { + "event": { + "commonEventHeader": { + "eventId": "123#RandomInteger(8,8)", + "eventType": "pnfRegistration", + "startEpochMicrosec": "#Timestamp", + "vesEventListenerVersion": "7.0.1", + "lastEpochMicrosec": 1539239592379 + }, + "pnfRegistrationFields": { + "pnfRegistrationFieldsVersion":"2.0", + "serialNumber": "#RandomString(7)", + "vendorName": "Nokia", + "oamV4IpAddress": "val3", + "oamV6IpAddress": "val4" + } + } + } + +Corresponding result of keyword substitution (event that will be sent): + + { + "event": { + "commonEventHeader": { + "eventId": "1238", + "eventType": "pnfRegistration", + "startEpochMicrosec": "154046405117", + "vesEventListenerVersion": "7.0.1", + "lastEpochMicrosec": 1539239592379 + }, + "pnfRegistrationFields": { + "pnfRegistrationFieldsVersion":"2.0", + "serialNumber": "6061ZW3", + "vendorName": "Nokia", + "oamV4IpAddress": "val3", + "oamV6IpAddress": "val4" + } + } + } + + +### Logging +Every start of simulator will generate new logs that can be found in docker pnf-simualtor container under path: +/var/log/ONAP/pnfsimulator/pnfsimulator_output.log + +### Swagger +Detailed view of simulator REST API is available via Swagger UI +Swagger UI is available on *http://<simulator_ip>:5000/swagger-ui.html* + +### History +User is able to view events history. +In order to browse history, go to *http://<simulator_ip>:8081/db/pnf_simulator/eventData* + +### TLS Support +Simulator is able to communicate with VES using HTTPS protocol. +CA certificates are incorporated into simulator docker image, thus no additional actions are required from user. + +Certificates can be found in docker container under path: */usr/local/share/ca-certificates/* + +Simulator works with VES that uses both self-signed certificate (already present in keystore) and VES integrated to AAF. + + +## Developers Guide + +### Integration tests +Integration tests are located in folder 'integration'. Tests are using docker-compose from root folder. +This docker-compose has pnfsimulator image set on nexus3.onap.org:10003/onap/pnf-simulator:5.0.0-SNAPSHOT. +To test your local changes before running integration tests please build project using: + + 'mvn clean package docker:build' + +then go to 'integration' folder and run: + + 'mvn test' diff --git a/test/mocks/pnfsimulator/pnfsimulator/config/config.json b/test/mocks/pnfsimulator/pnfsimulator/config/config.json new file mode 100644 index 000000000..819f7d751 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/config/config.json @@ -0,0 +1,9 @@ +{ + "simulatorParams": { + "vesServerUrl": "http://VES-HOST:VES-PORT/eventListener/v7", + "repeatInterval": 10, + "repeatCount": 2 + }, + "templateName": "notification.json", + "patch":{} +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/db/pnf_simulator.js b/test/mocks/pnfsimulator/pnfsimulator/db/pnf_simulator.js new file mode 100644 index 000000000..f5a03c3d0 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/db/pnf_simulator.js @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +const res = [ + db.createUser({ user: 'pnf_simulator_user', pwd: 'zXcVbN123!', roles: ['readWrite', 'dbAdmin'] }), + db.simulatorConfig.insert({"vesServerUrl": "http://xdcae-ves-collector.onap:8080/eventListener/v7"}), + db.createCollection("template"), + db.createView("flatTemplatesView", "template", [{"$project":{"keyValues":{"$objectToArray": "$$ROOT.flatContent"}}}]) +]; + +printjson(res); diff --git a/test/mocks/pnfsimulator/deployment/PnP_PNF_sim_heat_template.yml b/test/mocks/pnfsimulator/pnfsimulator/deployment/PnP_PNF_sim_heat_template.yml index 4bf6758d9..4bf6758d9 100644 --- a/test/mocks/pnfsimulator/deployment/PnP_PNF_sim_heat_template.yml +++ b/test/mocks/pnfsimulator/pnfsimulator/deployment/PnP_PNF_sim_heat_template.yml diff --git a/test/mocks/pnfsimulator/pnfsimulator/docker-compose.yml b/test/mocks/pnfsimulator/pnfsimulator/docker-compose.yml new file mode 100644 index 000000000..c6a0531c9 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/docker-compose.yml @@ -0,0 +1,36 @@ +version: '3' + +services: + + mongo: + image: mongo + restart: always + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: zXcVbN123! + MONGO_INITDB_DATABASE: pnf_simulator + volumes: + - ./db:/docker-entrypoint-initdb.d + ports: + - "27017:27017" + + mongo-express: + image: mongo-express + restart: always + ports: + - 8081:8081 + environment: + ME_CONFIG_MONGODB_ADMINUSERNAME: root + ME_CONFIG_MONGODB_ADMINPASSWORD: zXcVbN123! + + pnf-simulator: + image: nexus3.onap.org:10003/onap/pnfsimulator:5.0.0-SNAPSHOT + ports: + - "5000:5000" + volumes: + - ./logs:/var/log + - ./templates:/app/templates + restart: on-failure + depends_on: + - mongo + - mongo-express diff --git a/test/mocks/pnfsimulator/pnfsimulator/docker/Dockerfile b/test/mocks/pnfsimulator/pnfsimulator/docker/Dockerfile new file mode 100644 index 000000000..814cf64a4 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/docker/Dockerfile @@ -0,0 +1,8 @@ +FROM openjdk:8-jre-alpine +ADD libs /app/libs +ADD pnfsimulator-5.0.0-SNAPSHOT.jar /app/pnf-simulator.jar +CMD apk update +CMD apk add ca-certificates +ADD certificates /usr/local/share/ca-certificates/ +RUN update-ca-certificates +CMD java -cp /app/libs/*:/app/pnf-simulator.jar org.onap.pnfsimulator.Main diff --git a/test/mocks/pnfsimulator/pnfsimulator/docker/certificates/AAF_RootCA.crt b/test/mocks/pnfsimulator/pnfsimulator/docker/certificates/AAF_RootCA.crt new file mode 100644 index 000000000..e9a50d7ea --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/docker/certificates/AAF_RootCA.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFPjCCAyagAwIBAgIJAJ6u7cCnzrWdMA0GCSqGSIb3DQEBCwUAMCwxDjAMBgNV +BAsMBU9TQUFGMQ0wCwYDVQQKDARPTkFQMQswCQYDVQQGEwJVUzAeFw0xODA0MDUx +NDE1MjhaFw0zODAzMzExNDE1MjhaMCwxDjAMBgNVBAsMBU9TQUFGMQ0wCwYDVQQK +DARPTkFQMQswCQYDVQQGEwJVUzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAMA5pkgRs7NhGG4ew5JouhyYakgYUyFaG121+/h8qbSdt0hVQv56+EA41Yq7 +XGie7RYDQK9NmAFF3gruE+6X7wvJiChp+Cyd7sFMnb65uWhxEdxWTM2BJFrgfzUn +H8ZCxgaCo3XH4PzlKRy2LQQJEJECwl/RZmRCXijMt5e9h8XoZY/fKkKcZZUsWNCM +pTo266wjvA9MXLmdgReRj0+vrCjrNqy+htwJDztoiHWiYPqT6o8EvGcgjNqjlZx7 +NUNf8MfLDByqKF6+wRbHv1GKjn3/Vijd45Fv8riyRYROiFanvbV6jIfBkv8PZbXg +2VDWsYsgp8NAvMxK+iV8cO+Ck3lBI2GOPZbCEqpPVTYbLUz6sczAlCXwQoPzDIZY +wYa3eR/gYLY1gP2iEVHORag3bLPap9ZX5E8DZkzTNTjovvLk8KaCmfcaUMJsBtDd +ApcUitz10cnRyZc1sX3gE1f3DpzQM6t9C5sOVyRhDcSrKqqwb9m0Ss04XAS9FsqM +P3UWYQyqDXSxlUAYaX892u8mV1hxnt2gjb22RloXMM6TovM3sSrJS0wH+l1nznd6 +aFXftS/G4ZVIVZ/LfT1is4StoyPWZCwwwly1z8qJQ/zhip5NgZTxQw4mi7ww35DY +PdAQOCoajfSvFjqslQ/cPRi/MRCu079heVb5fQnnzVtnpFQRAgMBAAGjYzBhMB0G +A1UdDgQWBBRTVTPyS+vQUbHBeJrBKDF77+rtSTAfBgNVHSMEGDAWgBRTVTPyS+vQ +UbHBeJrBKDF77+rtSTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAN +BgkqhkiG9w0BAQsFAAOCAgEAPx/IaK94n02wPxpnYTy+LVLIxwdq/kawNd6IbiMz +L87zmNMDmHcGbfoRCj8OkhuggX9Lx1/CkhpXimuYsZOFQi5blr/u+v4mIbsgbmi9 +7j+cUHDP0zLycvSvxKHty51LwmaX9a4wkJl5zBU4O1sd/H9tWcEmwJ39ltKoBKBx +c94Zc3iMm5ytRWGj+0rKzLDAXEWpoZ5bE5PLJauA6UDCxDLfs3FwhbS7uDggxYvf +jySF5FCNET94oJ+m8s7VeHvoa8iPGKvXrIqdd7XDHnqJJlVKr7m9S0fMbyEB8ci2 +RtOXDt93ifY1uhoEtEykn4dqBSp8ezvNMnwoXdYPDvTd9uCAFeWFLVreBAWxd25h +PsBTkZA5hpa/rA+mKv6Af4VBViYr8cz4dZCsFChuioVebe9ighrfjB//qKepFjPF +CyjzKN1u0JKm/2x/ORqxkTONG8p3uDwoIOyimUcTtTMv42bfYD88RKakqSFXE9G+ +Z0LlaKABqfjK49o/tsAp+c5LoNlYllKhnetO3QAdraHwdmC36BhoghzR1jpX751A +cZn2VH3Q4XKyp01cJNCJIrua+A+bx6zh3RyW6zIIkbRCbET+UD+4mr8WIcSE3mtR +ZVlnhUDO4z9//WKMVzwS9Rh8/kuszrGFI1KQozXCHLrce3YP6RYZfOed79LXaRwX +dYY= +-----END CERTIFICATE----- diff --git a/test/mocks/pnfsimulator/pnfsimulator/docker/certificates/dcaelocal.crt b/test/mocks/pnfsimulator/pnfsimulator/docker/certificates/dcaelocal.crt new file mode 100644 index 000000000..1be5a6fb2 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/docker/certificates/dcaelocal.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSDCCAjCgAwIBAgIEWAkZ5jANBgkqhkiG9w0BAQUFADBmMQswCQYDVQQGEwJV +UzELMAkGA1UECBMCTkoxEzARBgNVBAcTCk1pZGRsZXRvd24xDTALBgNVBAoTBERD +QUUxEjAQBgNVBAsTCU9QRU4tRENBRTESMBAGA1UEAxMJRENBRUxPQ0FMMB4XDTE2 +MTAyMDE5MjQyMloXDTE3MDExODE5MjQyMlowZjELMAkGA1UEBhMCVVMxCzAJBgNV +BAgTAk5KMRMwEQYDVQQHEwpNaWRkbGV0b3duMQ0wCwYDVQQKEwREQ0FFMRIwEAYD +VQQLEwlPUEVOLURDQUUxEjAQBgNVBAMTCURDQUVMT0NBTDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALoR0omXk1Xou3TdDydwhCF9V0ZSgQtMlMr8qYxe +wLg/UGZbTea5HHqBmjWTVEKFGea7V7pnEiGWCPftIy/4D8ZSDaEQQ0WYCf6jNxeI +T6PSiM+db/TwPToqPNMQwoftpsAEkJEJFB9rgUXoDD9FY5kUQW+fYOLyUeOb/rDE +cRnSZX2qp1M/jAm1puIeNQcqiPExOMHqnN2bIgAZoHaFucdyOQUxuhIAgxoqe8Zt +s451hm94g42F92I8KLy4EyOhXmSMjaLmgOqdjOPyBubOde4R39+6KAyQNGAnm5I4 +xq2J80R7qU0+4nnfjs2ScfAB/HUsWoVaGr9Ii4e34CW8JG8CAwEAATANBgkqhkiG +9w0BAQUFAAOCAQEARqQmWg1gtwbgPbamWy0vdNWLQZm78y1ETR0ro9cazD25sD5/ +anDJ2RA97pGQFgncAI+Fzg4YygWBIext0OE92wQeKaHkxSujAe09F0wPcwc00Vyq +NtBPcP17n18FkpFW1hkurlWiHOpGDRW2MmwhLj4lSFJmxMBAbzlfKrTBgj116UT+ +d4AGyuovS4LkmBWYFN//yoddGyrO26ar1M9ORdbDkjzOK4DkioTx3bwbdKPW7V4a ++Ns1KDFZ7FpjcWPZc6uDV4lBIhNUZuQZLy5hWBUeNhh4i2lL6xMrPzRa5kV1M7og +ipv/ReVCixJqsGhx+8I4OPUbPoUYzRF+JmYUzA== +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/pom.xml b/test/mocks/pnfsimulator/pnfsimulator/integration/pom.xml new file mode 100644 index 000000000..21c2f3c49 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/pom.xml @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.simulator</groupId> + <artifactId>simulator-parent</artifactId> + <version>5.0.0-SNAPSHOT</version> + </parent> + + <artifactId>pnf-simulator-integration</artifactId> + <repositories> + <repository> + <id>dl.bintray.com</id> + <url>https://dl.bintray.com/palantir/releases</url> + </repository> + </repositories> + + <properties> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> + + <dependencies> + + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.9.1</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter</artifactId> + <version>2.0.2.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + <version>2.0.2.RELEASE</version> + </dependency> + + <dependency> + <groupId>io.rest-assured</groupId> + <artifactId>rest-assured</artifactId> + <version>3.2.0</version> + </dependency> + <dependency> + <groupId>org.mongodb</groupId> + <artifactId>mongo-java-driver</artifactId> + <version>3.9.1</version> + </dependency> + + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <version>5.0.4.RELEASE</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <version>2.0.1.RELEASE</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.8.2</version> + </dependency> + <dependency> + <groupId>com.palantir.docker.compose</groupId> + <artifactId>docker-compose-rule-junit4</artifactId> + <version>0.34.0</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <executions> + <execution> + <id>onap-license</id> + <phase>none</phase> + </execution> + <execution> + <id>onap-java-style</id> + <phase>none</phase> + </execution> + </executions> + <artifactId>maven-checkstyle-plugin</artifactId> + <version>2.17</version> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.12.1</version> + <configuration> + <includes> + <!--Execute only suites from the test folder--> + <include>**/*Suite.java</include> + </includes> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/java/org/onap/pnfsimulator/integration/Main.java index 244eef6bd..7288c2a28 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/java/org/onap/pnfsimulator/integration/Main.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,14 +17,10 @@ * limitations under the License. * ============LICENSE_END========================================================= */ +package org.onap.pnfsimulator.integration; -package org.onap.pnfsimulator; - -import org.onap.pnfsimulator.message.MessageProvider; -import org.onap.pnfsimulator.simulator.validation.JSONValidator; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @@ -34,16 +30,6 @@ public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); } - - @Bean - public MessageProvider messageProvider() { - return new MessageProvider(); - } - - @Bean - public JSONValidator jsonValidator() { - return new JSONValidator(); - } } diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/java/org/onap/pnfsimulator/integration/VesSimulatorController.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/java/org/onap/pnfsimulator/integration/VesSimulatorController.java new file mode 100644 index 000000000..70e0c609c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/java/org/onap/pnfsimulator/integration/VesSimulatorController.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.integration; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequestMapping("ves-simulator") +@RestController +public class VesSimulatorController { + + private final VesSimulatorService vesSimulatorService; + private final Gson gson; + + @Autowired + public VesSimulatorController(VesSimulatorService vesSimulatorService, Gson gson) { + this.vesSimulatorService = vesSimulatorService; + this.gson = gson; + } + + @PostMapping("eventListener/v5") + String sendEventToDmaapV5(@RequestBody String body) { + System.out.println("Received event" + body); + JsonObject jsonObject = gson.fromJson(body, JsonObject.class); + vesSimulatorService.sendEventToDmaapV5(jsonObject); + return "MessageAccepted"; + } + + @PostMapping("eventListener/v7") + String sendEventToDmaapV7(@RequestBody String body) { + System.out.println("Received event" + body); + JsonObject jsonObject = gson.fromJson(body, JsonObject.class); + vesSimulatorService.sendEventToDmaapV7(jsonObject); + return "MessageAccepted"; + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/java/org/onap/pnfsimulator/integration/VesSimulatorService.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/java/org/onap/pnfsimulator/integration/VesSimulatorService.java new file mode 100644 index 000000000..65e5d3e13 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/java/org/onap/pnfsimulator/integration/VesSimulatorService.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.integration; + +import com.google.gson.JsonObject; +import org.springframework.stereotype.Service; + +@Service +public class VesSimulatorService { + + void sendEventToDmaapV5(JsonObject jsonObject) { + //JUST FOR TESTING PURPOSE + } + + void sendEventToDmaapV7(JsonObject jsonObject) { + //JUST FOR TESTING PURPOSE + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/resources/application.properties b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/resources/application.properties new file mode 100644 index 000000000..205ed95fb --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8000
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/resources/keystore b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/resources/keystore Binary files differnew file mode 100644 index 000000000..26a16f756 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/main/resources/keystore diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/BasicAvailabilityTest.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/BasicAvailabilityTest.java new file mode 100644 index 000000000..9f11a00a0 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/BasicAvailabilityTest.java @@ -0,0 +1,235 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.integration; + +import static io.restassured.RestAssured.given; +import static io.restassured.RestAssured.when; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import com.google.gson.JsonObject; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.UUID; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.internal.util.Timer; +import org.mockito.internal.verification.VerificationOverTimeImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Main.class, TestConfiguration.class}, webEnvironment = WebEnvironment.DEFINED_PORT) +public class BasicAvailabilityTest { + + @Autowired + VesSimulatorController vesSimulatorController; + + @Autowired + VesSimulatorService vesSimulatorService; + + private final String ACTION_START = "start"; + + private String currenVesSimulatorIp; + + @Before + public void setUp() throws Exception { + currenVesSimulatorIp = getCurrentIpAddress(); + } + + @After + public void tearDown() { + Mockito.reset(vesSimulatorService); + } + + @Test + public void simulatorShouldFailWhenTriggeredNonexistentTemplate(){ + //given + String startUrl = prepareRequestUrl(ACTION_START); + String body = "{\n" + + "\"templateName\": \"any_nonexistent_template.json\",\n" + + "\"patch\":{},\n" + + "\"simulatorParams\": {\n" + + "\"vesServerUrl\": \"https://" + currenVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" + + "\"repeatInterval\": 1,\n" + + "\"repeatCount\": 1\n" + + "}\n" + + "}"; + + //when + given() + .contentType("application/json") + .body(body) + .when() + .post(startUrl) + .then() + .statusCode(400) + .body("message", equalTo("Cannot start simulator - template any_nonexistent_template.json not found.")); + } + + @Test + public void whenTriggeredSimulatorShouldSendSingleEventToVes() { + //given + String startUrl = prepareRequestUrl(ACTION_START); + String body = "{\n" + + "\"templateName\": \"notification.json\",\n" + + "\"patch\":{},\n" + + "\"simulatorParams\": {\n" + + "\"vesServerUrl\": \"https://" + currenVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" + + "\"repeatInterval\": 1,\n" + + "\"repeatCount\": 1\n" + + "}\n" + + "}"; + ArgumentCaptor<JsonObject> parameterCaptor = ArgumentCaptor.forClass(JsonObject.class); + + //when + given() + .contentType("application/json") + .body(body) + .when() + .post(startUrl) + .then() + .statusCode(200) + .body("message", equalTo("Request started")); + + Mockito.verify(vesSimulatorService, + Mockito.timeout(3000)) + .sendEventToDmaapV5(parameterCaptor.capture()); + + assertThat(parameterCaptor.getValue() + .getAsJsonObject("event") + .getAsJsonObject("commonEventHeader") + .get("domain").getAsString()).isEqualTo("notification"); + } + + @Test + public void simulatorShouldCorrectlyRespondOnCancellAllEvent() { + //given + String ACTION_CANCEL_ALL = "cancel"; + String cancelAllUrl = prepareRequestUrl(ACTION_CANCEL_ALL); + + //when + when() + .post(cancelAllUrl) + .then() + .statusCode(200) + .body("message", equalTo("Event(s) was cancelled")); + + } + + @Test + public void simulatorBeAbleToUseNewlyAddedTemplate() throws IOException { + //given + String templateBody = "{\"fake\":\"template\"}\n"; + String fileName = UUID.randomUUID() + ".json"; + String requestBody = "{\n" + + "\"templateName\": \"" + fileName + "\",\n" + + "\"patch\":{},\n" + + "\"simulatorParams\": {\n" + + "\"vesServerUrl\": \"https://" + currenVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" + + "\"repeatInterval\": 1,\n" + + "\"repeatCount\": 1\n" + + "}\n" + + "}"; + ArgumentCaptor<JsonObject> parameterCaptor = ArgumentCaptor.forClass(JsonObject.class); + + //when + Path newFile = Files.createFile(Paths.get("..", "templates", fileName)); + Files.write(newFile, templateBody.getBytes()); + + given() + .contentType("application/json") + .body(requestBody) + .when() + .post(prepareRequestUrl(ACTION_START)); + + Files.delete(newFile); + + //then + Mockito.verify(vesSimulatorService, Mockito.timeout(3000)) + .sendEventToDmaapV5(parameterCaptor.capture()); + assertThat(parameterCaptor.getValue() + .get("fake").getAsString()).isEqualTo("template"); + + } + + @Test + public void whenTriggeredSimulatorShouldSendGivenAmountOfEventsToVes() { + //given + String startUrl = prepareRequestUrl(ACTION_START); + String body = "{\n" + + "\"templateName\": \"notification.json\",\n" + + "\"patch\":{},\n" + + "\"simulatorParams\": {\n" + + "\"vesServerUrl\": \"https://" + currenVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" + + "\"repeatInterval\": 1,\n" + + "\"repeatCount\": 4\n" + + "}\n" + + "}"; + ArgumentCaptor<JsonObject> parameterCaptor = ArgumentCaptor.forClass(JsonObject.class); + + //when + given() + .contentType("application/json") + .body(body) + .when() + .post(startUrl) + .then() + .statusCode(200) + .body("message", equalTo("Request started")); + + VerificationOverTimeImpl verificator = new VerificationOverTimeImpl(100, Mockito.times(4), false, new Timer(6000)); + Mockito.verify(vesSimulatorService, verificator).sendEventToDmaapV5(parameterCaptor.capture()); + + for (JsonObject value : parameterCaptor.getAllValues()) { + assertThat(value + .getAsJsonObject("event") + .getAsJsonObject("commonEventHeader") + .get("domain").getAsString()).isEqualTo("notification"); + } + } + + private String prepareRequestUrl(String action) { + return "http://0.0.0.0:5000/simulator/" + action; + } + + private String getCurrentIpAddress() throws SocketException { + return Collections.list(NetworkInterface.getNetworkInterfaces()).stream() + .flatMap(i -> Collections.list(i.getInetAddresses()).stream()) + .filter(ip -> ip instanceof Inet4Address) + .map(e -> (Inet4Address) e) + .findFirst() + .orElseThrow(RuntimeException::new) + .getHostAddress(); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/OptionalTemplatesTest.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/OptionalTemplatesTest.java new file mode 100644 index 000000000..a5ffe4d47 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/OptionalTemplatesTest.java @@ -0,0 +1,204 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.integration; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import com.google.gson.JsonObject; +import com.mongodb.MongoClient; +import com.mongodb.MongoClientOptions; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.MongoDatabase; +import java.time.Instant; +import java.net.Inet4Address; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.Collections; +import org.assertj.core.api.Assertions; +import org.bson.Document; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Main.class, TestConfiguration.class}, webEnvironment = WebEnvironment.DEFINED_PORT) +public class OptionalTemplatesTest { + + private static final String PNF_SIMULATOR_DB = "pnf_simulator"; + private static final String COMMON_EVENT_HEADER = "commonEventHeader"; + private static final String PNF_SIMULATOR_DB_PSWD = "zXcVbN123!"; + private static final String PNF_SIMULATOR_DB_USER = "pnf_simulator_user"; + private static final String PATCHED = "patched"; + private static final String SINGLE_EVENT_URL = "http://0.0.0.0:5000/simulator/event"; + + @Autowired + VesSimulatorController vesSimulatorController; + + @Autowired + private VesSimulatorService vesSimulatorService; + + private String currentVesSimulatorIp; + + @Before + public void setUp() throws Exception { + currentVesSimulatorIp = getCurrentIpAddress(); + } + + @After + public void tearDown() { + Mockito.reset(vesSimulatorService); + } + + @Test + public void whenTriggeredSimulatorWithoutTemplateShouldSendSingleEventToVes() { + //given + long currentTimestamp = Instant.now().getEpochSecond(); + + String body = "{\n" + + "\"vesServerUrl\": \"https://" + currentVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" + + "\"event\": { \n" + + "\"commonEventHeader\": {\n" + + "\"eventId1\": \"#RandomString(20)\",\n" + + "\"eventId2\": \"#RandomInteger(10,10)\",\n" + + "\"eventId3\": \"#Increment\",\n" + + "\"eventId4\": \"#RandomPrimitiveInteger(10,10)\",\n" + + "\"eventId5\": \"#TimestampPrimitive\",\n" + + "\"sourceName\": \"Single_sourceName\",\n" + + "\"version\": 3" + + "}\n" + + "}\n" + + "}"; + ArgumentCaptor<JsonObject> parameterCaptor = ArgumentCaptor.forClass(JsonObject.class); + + //when + given() + .contentType("application/json") + .body(body) + .when() + .post(SINGLE_EVENT_URL) + .then() + .statusCode(202) + .body("message", equalTo("One-time direct event sent successfully")); + + //then + long afterExecution = Instant.now().getEpochSecond(); + Mockito.verify(vesSimulatorService, + Mockito.timeout(3000)) + .sendEventToDmaapV5(parameterCaptor.capture()); + + JsonObject value = parameterCaptor.getValue(); + assertThat(value + .getAsJsonObject(COMMON_EVENT_HEADER) + .get("sourceName").getAsString()).isEqualTo("Single_sourceName"); + assertThat(value + .getAsJsonObject(COMMON_EVENT_HEADER) + .get("eventId1").getAsString().length()).isEqualTo(20); + assertThat(value + .getAsJsonObject(COMMON_EVENT_HEADER) + .get("eventId2").getAsString()).isEqualTo("10"); + assertThat(value + .getAsJsonObject(COMMON_EVENT_HEADER) + .get("eventId3").getAsString()).isEqualTo("1"); + assertThat(value + .getAsJsonObject(COMMON_EVENT_HEADER) + .get("eventId4").getAsInt()).isEqualTo(10); + assertThat(value + .getAsJsonObject(COMMON_EVENT_HEADER) + .get("eventId5").getAsLong()).isBetween(currentTimestamp, afterExecution); + } + + @Test + public void whenTriggeredSimulatorWithoutTemplateEventShouldBeVisibleInDB() throws UnknownHostException { + //given + String body = "{\n" + + "\"vesServerUrl\": \"https://" + currentVesSimulatorIp + ":9443/ves-simulator/eventListener/v5\",\n" + + "\"event\": { \n" + + "\"commonEventHeader\": {\n" + + "\"sourceName\": \"HistoricalEvent\",\n" + + "\"version\": 3" + + "}\n" + + "}\n" + + "}"; + ArgumentCaptor<JsonObject> parameterCaptor = ArgumentCaptor.forClass(JsonObject.class); + + //when + given() + .contentType("application/json") + .body(body) + .when() + .post(SINGLE_EVENT_URL) + .then() + .statusCode(202) + .body("message", equalTo("One-time direct event sent successfully")); + + //then + Mockito.verify(vesSimulatorService, + Mockito.timeout(3000)) + .sendEventToDmaapV5(parameterCaptor.capture()); + + Document sourceNameInMongoDB = findSourceNameInMongoDB(); + Assertions.assertThat(sourceNameInMongoDB.get(PATCHED)) + .isEqualTo("{\"commonEventHeader\":{\"sourceName\":\"HistoricalEvent\",\"version\":3}}"); + } + + private Document findSourceNameInMongoDB() throws UnknownHostException { + MongoCredential credential = MongoCredential + .createCredential(PNF_SIMULATOR_DB_USER, PNF_SIMULATOR_DB, PNF_SIMULATOR_DB_PSWD.toCharArray()); + MongoClient mongoClient = new MongoClient(new ServerAddress(Inet4Address.getLocalHost(), 27017), + credential, MongoClientOptions.builder().build()); + MongoDatabase pnfSimulatorDb = mongoClient.getDatabase(PNF_SIMULATOR_DB); + MongoCollection<Document> table = pnfSimulatorDb.getCollection("eventData"); + Document searchQuery = new Document(); + searchQuery.put(PATCHED, new Document("$regex", ".*" + "HistoricalEvent" + ".*")); + FindIterable<Document> findOfPatched = table.find(searchQuery); + Document dbObject = null; + MongoCursor<Document> cursor = findOfPatched.iterator(); + if (cursor.hasNext()) { + dbObject = cursor.next(); + } + return dbObject; + } + + private String getCurrentIpAddress() throws SocketException { + return Collections.list(NetworkInterface.getNetworkInterfaces()).stream() + .flatMap(i -> Collections.list(i.getInetAddresses()).stream()) + .filter(ip -> ip instanceof Inet4Address) + .map(e -> (Inet4Address) e) + .findFirst() + .orElseThrow(RuntimeException::new) + .getHostAddress(); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/SearchInTemplatesTest.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/SearchInTemplatesTest.java new file mode 100644 index 000000000..9d4ff3b8e --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/SearchInTemplatesTest.java @@ -0,0 +1,269 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.integration; + +import static io.restassured.RestAssured.given; +import static java.nio.file.Files.readAllBytes; + +import io.restassured.http.Header; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import org.hamcrest.Matchers; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.util.ResourceUtils; + +public class SearchInTemplatesTest { + + private static final String UPLOAD = "upload"; + private static final String SEARCH = "search"; + private static final String APPLICATION_JSON = "application/json"; + private static final String CONTENT_TYPE = "Content-Type"; + + @BeforeClass + public static void setUp() throws IOException { + for (File file : readFileFromTemplatesFolder()) { + byte[] body = readAllBytes(file.toPath()); + + given() + .body(body) + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(UPLOAD) + "?override=true") + .then() + .statusCode(201); + } + } + + @Test + public void shouldFindNothingWhenNonexistentValueIsProvided(){ + given() + .body("{\"searchExpr\": { \"child3\": \"nonexistentValue\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.empty()); + } + + @Test + public void shouldFindNothingWhenNonexistentKeyIsProvided(){ + given() + .body("{\"searchExpr\": { \"nonexistentKey\": \"Any value 1\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.empty()); + } + + @Test + public void shouldFindNothingWhenPartOfKeyIsProvided(){ + given() + .body("{\"searchExpr\": { \"child\": \"Any value 1\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.empty()); + } + + @Test + public void shouldFindNothingWhenPartOfValueIsProvided(){ + given() + .body("{\"searchExpr\": { \"child5\": \"Any\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.empty()); + } + + @Test + public void shouldBeAbleToSearchForString(){ + given() + .body("{\"searchExpr\": { \"child1\": \"Any value 1\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("template_with_array.json", "complicated_template.json", "simple_template.json")); + + given() + .body("{\"searchExpr\": { \"child2\": \"any value 4\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("template_with_array.json")); + } + + @Test + public void shouldBeAbleToSearchForManyStrings(){ + given() + .body("{\"searchExpr\": { \"child1\": \"Any value 1\", \"child2\": \"any value 2\"}}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("simple_template.json", "complicated_template.json")); + } + + @Test + public void shouldBeAbleToSearchForStarSign(){ + given() + .body("{\"searchExpr\": { \"child2\": \"*\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("complicated_template.json")); + } + + @Test + public void shouldBeAbleToSearchForQuestionMark(){ + given() + .body("{\"searchExpr\": { \"child1\": \"?\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("complicated_template.json")); + } + + @Test + public void shouldBeAbleToSearchForBrackets(){ + given() + .body("{\"searchExpr\": { \"parent2\": \"[]\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("template_with_array.json")); + } + + @Test + public void shouldInformThatSearchForNullsIsProhibited(){ + given() + .body("{\"searchExpr\": { \"child3\": null }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(400); + } + + @Test + public void shouldBeAbleToSearchForURI(){ + given() + .body("{\"searchExpr\": { \"child3\": \"https://url.com?param1=test¶m2=*\" }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("complicated_template.json")); + } + + @Test + public void shouldBeAbleToSearchForFloats(){ + given() + .body("{\"searchExpr\": { \"child2\": 4.44 }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("template_with_array.json")); + + given() + .body("{\"searchExpr\": { \"child5\": 4.4 }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("complicated_template.json", "template_with_floats.json")); + } + + @Test + public void shouldBeAbleToSearchForIntegers(){ + given() + .body("{\"searchExpr\": { \"child2\": 1 }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("template_with_array.json", "template_with_ints.json")); + + given() + .body("{\"searchExpr\": { \"child2\": 4 }}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("template_with_array.json")); + } + + @Test + public void shouldBeAbleToSearchForBooleans(){ + given() + .body("{\"searchExpr\": { \"child4\": true}}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("template_with_booleans.json")); + + given() + .body("{\"searchExpr\": { \"parent2\": false}}") + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(SEARCH)) + .then() + .statusCode(200) + .body("", Matchers.hasItems("template_with_booleans.json")); + } + + + private static String prepareRequestUrl(String action) { + return "http://0.0.0.0:5000/template/" + action; + } + + private static File[] readFileFromTemplatesFolder() throws FileNotFoundException { + return ResourceUtils.getFile("classpath:templates/search").listFiles(); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TemplatesManagementTest.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TemplatesManagementTest.java new file mode 100644 index 000000000..7e74dd493 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TemplatesManagementTest.java @@ -0,0 +1,175 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.integration; + +import static io.restassured.RestAssured.given; + +import io.restassured.http.Header; +import io.restassured.path.json.JsonPath; +import io.restassured.path.json.config.JsonPathConfig; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import org.hamcrest.Matchers; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.util.ResourceUtils; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {Main.class, TestConfiguration.class}, webEnvironment = WebEnvironment.DEFINED_PORT) +public class TemplatesManagementTest { + + private static final String LIST_URL = "list"; + private static final String GET_URL = "get/"; + private static final String UPLOAD = "upload"; + private static final String NOTIFICATION_JSON = "notification.json"; + private static final String REGISTRATION_JSON = "registration.json"; + private static final String UPLOAD_TEMPLATE_JSON = "upload_template.json"; + private static final String OVERWRITE_TEMPLATE_JSON = "overwrite_template.json"; + private static final String OVERWRITTEN_TEMPLATE_JSON = "overwritten_template.json"; + private static final String APPLICATION_JSON = "application/json"; + private static final String CONTENT_TYPE = "Content-Type"; + private static final String FORCE_FLAG = "?override=true"; + private static final String CONTENT = "content"; + private static final String TEMPLATE = "template"; + private static final String ID = "id"; + + @Test + public void whenCallingGetShouldReceiveNotificationTemplate() throws IOException { + given() + .when() + .get(prepareRequestUrl(GET_URL) + NOTIFICATION_JSON) + .then() + .statusCode(200) + .body(ID, Matchers.equalTo(NOTIFICATION_JSON)) + .body(CONTENT, Matchers.equalTo(readTemplateFromResources(NOTIFICATION_JSON).getMap(CONTENT))); + } + + @Test + public void whenCallingGetShouldReceiveRegistrationTemplate() throws IOException { + given() + .when() + .get(prepareRequestUrl(GET_URL) + REGISTRATION_JSON) + .then() + .statusCode(200) + .body(ID, Matchers.equalTo(REGISTRATION_JSON)) + .body(CONTENT, Matchers.equalTo(readTemplateFromResources(REGISTRATION_JSON).getMap(CONTENT))); + } + + @Test + public void whenCallingListShouldReceiveAllPredefinedTemplates() throws IOException { + Map<Object, Object> registration = readTemplateFromResources(REGISTRATION_JSON).getMap(CONTENT); + Map<Object, Object> notification = readTemplateFromResources(NOTIFICATION_JSON).getMap(CONTENT); + + given() + .when() + .get(prepareRequestUrl(LIST_URL)) + .then() + .statusCode(200) + .body(CONTENT, Matchers.<Map>hasItems( + registration, + notification + )); + } + + @Test + public void whenCallingUploadAndGetShouldReceiveNewTemplate() throws IOException { + byte[] body = Files.readAllBytes(readFileFromTemplatesFolder(UPLOAD_TEMPLATE_JSON)); + + given() + .body(body) + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(UPLOAD)) + .then() + .statusCode(201); + + given() + .when() + .get(prepareRequestUrl(GET_URL) + UPLOAD_TEMPLATE_JSON) + .then() + .statusCode(200) + .body(ID, Matchers.equalTo(UPLOAD_TEMPLATE_JSON)) + .body(CONTENT, Matchers.equalTo(readTemplateFromResources(UPLOAD_TEMPLATE_JSON).getMap(TEMPLATE))); + } + + @Test + public void whenCallingOverrideAndGetShouldReceiveNewTemplate() throws IOException, JSONException { + byte[] body = Files.readAllBytes(readFileFromTemplatesFolder(OVERWRITE_TEMPLATE_JSON)); + + given() + .body(body) + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(UPLOAD)) + .then() + .statusCode(201); + + JSONObject overwrittenBody = new JSONObject(new String(body)); + JSONObject overwrittenTemplate = new JSONObject("{\"field1\": \"overwritten_field1\"}"); + overwrittenBody.put(TEMPLATE, overwrittenTemplate); + + given() + .body(overwrittenBody.toString().getBytes()) + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(UPLOAD)) + .then() + .statusCode(409); + + given() + .body(overwrittenBody.toString().getBytes()) + .header(new Header(CONTENT_TYPE, APPLICATION_JSON)) + .when() + .post(prepareRequestUrl(UPLOAD + FORCE_FLAG)) + .then() + .statusCode(201); + + given() + .when() + .get(prepareRequestUrl(GET_URL) + OVERWRITE_TEMPLATE_JSON) + .then() + .statusCode(200) + .body(ID, Matchers.equalTo(OVERWRITE_TEMPLATE_JSON)) + .body(CONTENT, Matchers.equalTo(readTemplateFromResources(OVERWRITTEN_TEMPLATE_JSON).getMap(CONTENT))); + } + + private String prepareRequestUrl(String action) { + return "http://0.0.0.0:5000/template/" + action; + } + + private JsonPath readTemplateFromResources(String templateName) throws IOException { + byte[] content = Files.readAllBytes(readFileFromTemplatesFolder(templateName)); + return new JsonPath(new String(content)).using(new JsonPathConfig("UTF-8")); + } + + private Path readFileFromTemplatesFolder(String templateName) throws FileNotFoundException { + return ResourceUtils.getFile("classpath:templates/"+templateName).toPath(); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TestConfiguration.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TestConfiguration.java new file mode 100644 index 000000000..19ae050c5 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/TestConfiguration.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.integration; + +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +@Configuration +public class TestConfiguration { + + @Bean + @Primary + VesSimulatorService provideVesSimulatorService() { + return Mockito.mock(VesSimulatorService.class); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java new file mode 100644 index 000000000..cc2ac588f --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/java/org/onap/pnfsimulator/integration/suites/DockerBasedTestsSuite.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.integration.suites; + +import com.palantir.docker.compose.DockerComposeRule; +import com.palantir.docker.compose.connection.waiting.HealthChecks; +import org.junit.ClassRule; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; +import org.onap.pnfsimulator.integration.BasicAvailabilityTest; +import org.onap.pnfsimulator.integration.OptionalTemplatesTest; +import org.onap.pnfsimulator.integration.SearchInTemplatesTest; +import org.onap.pnfsimulator.integration.TemplatesManagementTest; + +@RunWith(Suite.class) +@SuiteClasses({BasicAvailabilityTest.class, TemplatesManagementTest.class, OptionalTemplatesTest.class, + SearchInTemplatesTest.class}) +public class DockerBasedTestsSuite { + + @ClassRule + public static DockerComposeRule docker = DockerComposeRule.builder() + .file("../docker-compose.yml") + .waitingForService("pnf-simulator", HealthChecks.toHaveAllPortsOpen()) + .waitingForService("mongo", HealthChecks.toHaveAllPortsOpen()) + .build(); + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/application.properties b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/application.properties new file mode 100644 index 000000000..c3e147200 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/application.properties @@ -0,0 +1,6 @@ +server.port=9443 +security.require-ssl=true +server.ssl.key-store=src/main/resources/keystore +server.ssl.key-store-password=collector +server.ssl.keyStoreType=JKS +server.ssl.keyAlias=tomcat
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/notification.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/notification.json new file mode 100644 index 000000000..7b3e668aa --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/notification.json @@ -0,0 +1,45 @@ +{ + "id": "notification.json", + "content": { + "event": { + "commonEventHeader": { + "domain": "notification", + "eventName": "vFirewallBroadcastPackets", + "eventId": "4cfc-91cf-31a46", + "priority": "Normal", + "reportingEntityName": "myVNF", + "sequence": 1, + "sourceName": "ClosedLoopVNF", + "startEpochMicrosec": 1531616794, + "lastEpochMicrosec": 1531719042, + "vesEventListenerVersion": "7.0.1", + "version": "4.0.1" + }, + "notificationFields": { + "changeIdentifier": "PM_MEAS_FILES", + "changeType": "FileReady", + "arrayOfNamedHashMap": [ + { + "name": "A20161221.1031-1041.bin.gz", + "hashMap": { + "fileformatType": "org.3GPP.32.435#measCollec", + "fileFormatVersion": "V10", + "location": "ftpes://192.169.0.1:22/ftp/rop/A20161224.1030-1045.bin.gz", + "compression": "gzip" + } + }, + { + "name": "A20161222.1042-1102.bin.gz", + "hashMap": { + "fileFormatType": "org.3GPP.32.435#measCollec", + "fileFormatVersion": "V10", + "location": "ftpes://192.168.0.102:22/ftp/rop/A20161224.1045-1100.bin.gz", + "compression": "gzip" + } + } + ], + "notificationFieldsVersion": "2.0" + } + } + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/overwrite_template.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/overwrite_template.json new file mode 100644 index 000000000..d6d94f7a7 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/overwrite_template.json @@ -0,0 +1,6 @@ +{ + "name": "overwrite_template.json", + "template": { + "field1": "field1" + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/overwritten_template.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/overwritten_template.json new file mode 100644 index 000000000..f7848d415 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/overwritten_template.json @@ -0,0 +1,6 @@ +{ + "id": "overwrite_template.json", + "content": { + "field1": "overwritten_field1" + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/registration.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/registration.json new file mode 100644 index 000000000..bf0ac717c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/registration.json @@ -0,0 +1,36 @@ +{ + "id": "registration.json", + "content": { + "event": { + "commonEventHeader": { + "eventId": "registration_39239592", + "eventType": "pnfRegistration", + "reportingEntityName": "NOK6061ZW3", + "domain": "pnfRegistration", + "nfcNamingCode": "oam", + "sequence": 0, + "sourceId": "val13", + "internalHeaderFields": {}, + "priority": "Normal", + "sourceName": "NOK6061ZW3", + "eventName": "pnfRegistration_Nokia_5gDu", + "version": "4.0.1", + "nfNamingCode": "gNB", + "startEpochMicrosec": 1539239592379, + "vesEventListenerVersion": "7.0.1", + "lastEpochMicrosec": 1539239592379 + }, + "pnfRegistrationFields": { + "pnfRegistrationFieldsVersion": "2.0", + "serialNumber": "6061ZW3", + "vendorName": "Nokia", + "oamV4IpAddress": "val3", + "oamV6IpAddress": "val4", + "unitFamily": "BBU", + "modelNumber": "val6", + "softwareVersion": "val7", + "unitType": "val8" + } + } + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/complicated_template.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/complicated_template.json new file mode 100644 index 000000000..0edbb62dc --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/complicated_template.json @@ -0,0 +1,43 @@ +{ + "name": "complicated_template.json", + "template": { + "parent": { + "child1": "Any value 1", + "child2": { + "parent": { + "child1": "Any value 1", + "child2": "Any value 2", + "child3": { + "child4": "Any value 4" + }, + "child4": [ + "Any value 1", + "Any value 2, Any value 3" + ], + "child5": [ + "Any value 4", + 1, + 2, + 4.4, + { + "child6": [ + 1, + 2, + 4.4 + ] + } + ] + } + }, + "child3": { + "child4": "Any value 4" + } + }, + "parent2": "Any value 2", + "parent3": { + "child1": "?", + "child2": "*", + "child3": "https://url.com?param1=test¶m2=*" + } + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/simple_template.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/simple_template.json new file mode 100644 index 000000000..ad2a64aff --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/simple_template.json @@ -0,0 +1,12 @@ +{ + "name": "simple_template.json", + "template": { + "parent": { + "child1": "Any value 1", + "child2": "Any value 2", + "child3": { + "child4": "Any value 4" + } + } + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_array.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_array.json new file mode 100644 index 000000000..bb3235e2c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_array.json @@ -0,0 +1,23 @@ +{ + "name": "template_with_array.json", + "template": { + "parent": { + "child1": [ + { + "child1": "Any value 1", + "child2": [ + 4, + 4.44 + ] + } + ], + "child2": [ + 1, + "Any value 4", + 3.3, + 5 + ] + }, + "parent2": "[]" + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_booleans.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_booleans.json new file mode 100644 index 000000000..8bf54080c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_booleans.json @@ -0,0 +1,12 @@ +{ + "name": "template_with_booleans.json", + "template": { + "parent": { + "child1": true, + "child3": { + "child4": true + } + }, + "parent2": false + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_floats.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_floats.json new file mode 100644 index 000000000..aab3243e1 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_floats.json @@ -0,0 +1,13 @@ +{ + "name": "template_with_floats.json", + "template": { + "parent": { + "child1": 6.4, + "child2": 1.2, + "child3": { + "child5": 4.4, + "child2": "1" + } + } + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_ints.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_ints.json new file mode 100644 index 000000000..015cc46f3 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/search/template_with_ints.json @@ -0,0 +1,12 @@ +{ + "name": "template_with_ints.json", + "template": { + "parent": { + "child1": 6, + "child2": 1, + "child3": { + "child4": 4 + } + } + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/upload_template.json b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/upload_template.json new file mode 100644 index 000000000..4c49f0e17 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/integration/src/test/resources/templates/upload_template.json @@ -0,0 +1,6 @@ +{ + "name": "upload_template.json", + "template": { + "field1": "field1" + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/pom.xml b/test/mocks/pnfsimulator/pnfsimulator/pom.xml new file mode 100644 index 000000000..01d68ddc0 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/pom.xml @@ -0,0 +1,366 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + + +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.simulator</groupId> + <artifactId>simulator-parent</artifactId> + <version>5.0.0-SNAPSHOT</version> + </parent> + + <artifactId>pnfsimulator</artifactId> + <version>5.0.0-SNAPSHOT</version> + + <name>pnfsimulator</name> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + <maven.build.timestamp.format>yyyyMMdd'T'HHmmss</maven.build.timestamp.format> + + <simulator.main.class>org.onap.pnfsimulator.Main</simulator.main.class> + <docker.image.tag>latest</docker.image.tag> + <junit.jupiter.version>5.1.0</junit.jupiter.version> + <junit.vintage.version>5.1.0</junit.vintage.version> + <spring.boot.version>2.1.6.RELEASE</spring.boot.version> + <docker.image.name>onap/${project.artifactId}</docker.image.name> + + <dependency.directory.name>libs</dependency.directory.name> + <dependency.directory.location>${project.build.directory}/${dependency.directory.name} + </dependency.directory.location> + + <onap.nexus.dockerregistry.daily>nexus3.onap.org:10003</onap.nexus.dockerregistry.daily> + <onap.nexus.url>http://nexus3.onap.org</onap.nexus.url> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter</artifactId> + <version>${spring.boot.version}</version> + <exclusions> + <exclusion> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-logging</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + <version>${spring.boot.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-mongodb</artifactId> + <version>${spring.boot.version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>1.2.3</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + <version>1.2.3</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.25</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.6</version> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20180130</version> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.8.2</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.5.5</version> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>21.0</version> + </dependency> + <dependency> + <groupId>commons-cli</groupId> + <artifactId>commons-cli</artifactId> + <version>1.4</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>3.7</version> + </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.2</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.datatype</groupId> + <artifactId>jackson-datatype-jdk8</artifactId> + <version>2.9.7</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.datatype</groupId> + <artifactId>jackson-datatype-jsr310</artifactId> + <version>2.9.7</version> + </dependency> + <dependency> + <groupId>io.vavr</groupId> + <artifactId>vavr-match</artifactId> + <version>0.9.2</version> + </dependency> + <dependency> + <groupId>io.vavr</groupId> + <artifactId>vavr</artifactId> + <version>0.9.2</version> + </dependency> + + + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>${junit.jupiter.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-migrationsupport</artifactId> + <version>${junit.jupiter.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.9.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>2.18.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <version>5.0.4.RELEASE</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <version>${spring.boot.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger2</artifactId> + <version>2.9.2</version> + </dependency> + <dependency> + <groupId>io.springfox</groupId> + <artifactId>springfox-swagger-ui</artifactId> + <version>2.9.2</version> + </dependency> + <dependency> + <groupId>org.quartz-scheduler</groupId> + <artifactId>quartz</artifactId> + <version>2.2.1</version> + </dependency> + <dependency> + <groupId>org.quartz-scheduler</groupId> + <artifactId>quartz-jobs</artifactId> + <version>2.2.1</version> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <configuration> + <descriptor>src/assembly/resources.xml</descriptor> + <finalName>${project.artifactId}-${project.version}</finalName> + </configuration> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.7.0</version> + <configuration> + <source>${maven.compiler.source}</source> + <target>${maven.compiler.target}</target> + <showWarnings>true</showWarnings> + <showDeprecation>true</showDeprecation> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>3.0.2</version> + <configuration> + <archive> + <manifestEntries> + <Main-Class>${simulator.main.class}</Main-Class> + <Build-Time>${maven.build.timestamp}</Build-Time> + </manifestEntries> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>pl.project13.maven</groupId> + <artifactId>git-commit-id-plugin</artifactId> + <version>2.2.4</version> + <executions> + <execution> + <id>get-commit-info</id> + <goals> + <goal>revision</goal> + </goals> + </execution> + </executions> + <configuration> + <dotGitDirectory>${project.basedir}/.git</dotGitDirectory> + <generateGitPropertiesFile>true</generateGitPropertiesFile> + <includeOnlyProperties>git.commit.id.abbrev</includeOnlyProperties> + </configuration> + </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.19</version> + <dependencies> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-surefire-provider</artifactId> + <version>1.1.1</version> + </dependency> + </dependencies> + <configuration> + <detail>true</detail> + <printSummary>true</printSummary> + <useSystemClassLoader>false</useSystemClassLoader> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <configuration> + <outputDirectory>${dependency.directory.location}</outputDirectory> + <includeScope>runtime</includeScope> + <silent>true</silent> + </configuration> + <executions> + <execution> + <id>copy-external-dependencies</id> + <phase>package</phase> + <goals> + <goal>copy-dependencies</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>1.1.1</version> + <configuration> + <registryUrl>${onap.nexus.dockerregistry.daily}</registryUrl> + <imageName>${onap.nexus.dockerregistry.daily}/${docker.image.name}</imageName> + <dockerDirectory>${project.basedir}/docker</dockerDirectory> + <forceTags>true</forceTags> + <imageTags> + <tag>latest</tag> + <tag>${project.version}</tag> + <tag>${project.version}-${maven.build.timestamp}</tag> + </imageTags> + + <resources> + <resource> + <targetPath>${dependency.directory.name}</targetPath> + <directory>${dependency.directory.location}</directory> + </resource> + <resource> + <targetPath>/</targetPath> + <directory>${project.build.directory}</directory> + <include>${project.build.finalName}.jar</include> + </resource> + </resources> + <forceTags>true</forceTags> + </configuration> + </plugin> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.8.1</version> + <configuration> + <excludes> + <exclude>org/onap/pnfsimulator/Main.class</exclude> + </excludes> + </configuration> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>report</id> + <phase>prepare-package</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/assembly/resources.xml b/test/mocks/pnfsimulator/pnfsimulator/src/assembly/resources.xml new file mode 100644 index 000000000..35dd3b2e2 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/assembly/resources.xml @@ -0,0 +1,57 @@ +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + +<assembly> + <id>resources</id> + <formats> + <format>zip</format> + </formats> + + <fileSets> + <fileSet> + <includes> + <include>simulator.sh</include> + </includes> + <lineEnding>unix</lineEnding> + <fileMode>0755</fileMode> + </fileSet> + <fileSet> + <includes> + <include>docker-compose.yml</include> + </includes> + <lineEnding>unix</lineEnding> + <fileMode>0644</fileMode> + </fileSet> + <fileSet> + <directory>config</directory> + <outputDirectory>config</outputDirectory> + <includes> + <include>**/*</include> + </includes> + </fileSet> + <fileSet> + <directory>deployment</directory> + <outputDirectory>deployment</outputDirectory> + <includes> + <include>**/*</include> + </includes> + </fileSet> + </fileSets> +</assembly> diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java new file mode 100644 index 000000000..e0eace2d0 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/Main.java @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator; + +import javax.annotation.PostConstruct; + +import org.onap.pnfsimulator.filesystem.WatcherService; +import org.onap.pnfsimulator.template.FsToDbTemplateSynchronizer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; + +@SpringBootApplication +@EnableAsync +public class Main { + + private final WatcherService watcherService; + private final FsToDbTemplateSynchronizer fsToDbTemplateSynchronizer; + + @Autowired + public Main(WatcherService watcherService, + FsToDbTemplateSynchronizer fsToDbTemplateSynchronizer) { + this.watcherService = watcherService; + this.fsToDbTemplateSynchronizer = fsToDbTemplateSynchronizer; + } + + public static void main(String[] args) { + SpringApplication.run(Main.class, args); + } + + @PostConstruct + public void createWatchers() { + fsToDbTemplateSynchronizer.synchronize(); + watcherService.createWatcher(); + } +} + + diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageProvider.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java index fee574597..90a5ecb03 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageProvider.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/SwaggerConfig.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018-2019 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,25 +18,26 @@ * ============LICENSE_END========================================================= */ -package org.onap.pnfsimulator.message; +package org.onap.pnfsimulator; -import org.json.JSONObject; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; -public class MessageProvider { +@Configuration +@EnableSwagger2 +public class SwaggerConfig { - public JSONObject createMessageWithNotification(JSONObject commonEventHeaderParams, - JSONObject notificationParams) { - return MessageBuilder - .withCommonEventHeaderParams(commonEventHeaderParams) - .withNotificationParams(notificationParams) + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("org.onap.pnfsimulator")) + .paths(PathSelectors.any()) .build(); } - - public JSONObject createMessageWithPnfRegistration(JSONObject commonEventHeaderParams, JSONObject pnfRegistrationParams) { - return MessageBuilder - .withCommonEventHeaderParams(commonEventHeaderParams) - .withPnfRegistrationParams(pnfRegistrationParams) - .build(); - } - } diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Row.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Row.java new file mode 100644 index 000000000..f9a167b93 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Row.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.db; + +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Field; + +public abstract class Row { + @Id + @Field("_id") + protected String id; + + public String getId() { + return id; + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Storage.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Storage.java new file mode 100644 index 000000000..ad98ce0af --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/db/Storage.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.db; + +import com.google.gson.JsonObject; + +import java.util.List; +import java.util.Optional; + +public interface Storage<T extends Row> { + + List<T> getAll(); + + Optional<T> get(String rowId); + + void persist(T row); + + boolean tryPersistOrOverwrite(T row, boolean overwrite); + + void delete(String rowId); + + List<String> getIdsByContentCriteria(JsonObject queryJson); +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventData.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventData.java new file mode 100644 index 000000000..23b1c21a7 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventData.java @@ -0,0 +1,76 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.event; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Field; + +@Builder +@Getter +@Setter +public class EventData { + @Id + private String id; + + @Field("template") + @JsonInclude + private String template; + + @Field("patched") + @JsonInclude + private String patched; + + @Field("input") + @JsonInclude + private String input; + + @Field("keywords") + @JsonInclude + private String keywords; + + @Field("incrementValue") + @JsonInclude + private int incrementValue; + + protected EventData(String id, String template, String patched, String input, String keywords, int incrementValue) { + this.id = id; + this.template = template; + this.patched = patched; + this.input = input; + this.keywords = keywords; + this.incrementValue = incrementValue; + } + + @Override + public String toString() { + return "EventData{" + + "id='" + id + '\'' + + ", template='" + template + '\'' + + ", patched='" + patched + '\'' + + ", input='" + input + '\'' + + ", keywords='" + keywords + '\'' + + '}'; + } +} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/ValidationException.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataRepository.java index a9349174a..d1a66ab0a 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/ValidationException.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataRepository.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,9 @@ * ============LICENSE_END========================================================= */ -package org.onap.pnfsimulator.simulator.validation; +package org.onap.pnfsimulator.event; -public class ValidationException extends Exception { +import org.springframework.data.mongodb.repository.MongoRepository; - public ValidationException(String message) { - super(message); - } +public interface EventDataRepository extends MongoRepository<EventData, String> { } diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataService.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataService.java new file mode 100644 index 000000000..3568f0178 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/event/EventDataService.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.event; + +import com.google.gson.JsonObject; +import java.util.List; +import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class EventDataService { + private final EventDataRepository repository; + + @Autowired + public EventDataService(EventDataRepository repository) { + this.repository = repository; + } + + private EventData persistEventData(String templateString, String patchedString, String inputString, String keywordsString) { + EventData eventData = EventData.builder() + .template(templateString) + .patched(patchedString) + .input(inputString) + .keywords(keywordsString) + .build(); + return repository.save(eventData); + } + + public EventData persistEventData(JsonObject templateJson, JsonObject patchedJson, JsonObject inputJson, + JsonObject keywordsJson) { + return persistEventData(templateJson.toString(), + patchedJson.toString(), + inputJson.toString(), + keywordsJson.toString()); + } + + public List<EventData> getAllEvents() { + return repository.findAll(); + } + + public Optional<EventData> getById(String id) { + return repository.findById(id); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherConfig.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherConfig.java new file mode 100644 index 000000000..3535e3322 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherConfig.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.filesystem; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +public class WatcherConfig { + + @Bean + public TaskExecutor watcherTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setThreadNamePrefix("pnfsimulator_fs_watcher"); + executor.initialize(); + return executor; + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessor.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessor.java new file mode 100644 index 000000000..56a569671 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessor.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.filesystem; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchEvent.Kind; +import java.time.Instant; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import lombok.extern.slf4j.Slf4j; +import org.bson.json.JsonParseException; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.template.Template; +import org.bson.Document; + +@Slf4j +public enum WatcherEventProcessor { + CREATED(StandardWatchEventKinds.ENTRY_CREATE) { + @Override + public void processEvent(Path path, Storage<Template> storage) throws IOException { + String content = getContent(path); + String fileName = path.getFileName().toString(); + Document documentsContent = Document.parse(content); + storage.persist(new Template(fileName, documentsContent, Instant.now().getNano())); + log.info("DB record created for template: " + fileName); + } + }, + MODIFIED(StandardWatchEventKinds.ENTRY_MODIFY) { + @Override + public void processEvent(Path path, Storage<Template> storage) throws IOException { + String fileName = path.getFileName().toString(); + String content = getContent(path); + Document documentsContent = Document.parse(content); + Template template = storage.get(fileName).orElse(new Template(fileName, documentsContent, Instant.now().getNano())); + template.setContent(documentsContent); + storage.persist(template); + log.info("DB record modified for template: " + fileName); + } + }, + DELETED(StandardWatchEventKinds.ENTRY_DELETE) { + @Override + public void processEvent(Path path, Storage<Template> storage) { + String fileName = path.getFileName().toString(); + storage.delete(fileName); + log.info("DB record deleted for template: " + fileName); + } + }; + + private final Kind<Path> pathKind; + + String getContent(Path path) throws IOException { + try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) { + return lines.collect(Collectors.joining(System.lineSeparator())); + } catch (IOException e) { + log.error("Could not get content due to: " + e.getMessage() + " " + e.getCause(), e); + throw e; + } + } + + WatcherEventProcessor(Kind<Path> pathKind) { + this.pathKind = pathKind; + } + + public abstract void processEvent(Path templateName, Storage<Template> storage) throws IOException; + + static void process(WatchEvent<?> event, Storage<Template> storage, Path templatesDir) { + Optional<WatcherEventProcessor> watcherEventProcessor = getWatcherEventProcessor(event); + watcherEventProcessor.ifPresent(processor -> { + try { + final Path templatePath = templatesDir.resolve((Path) event.context()); + processor.processEvent(templatePath, storage); + } catch (IOException e) { + log.error("Error during processing DB record for template.", e); + } catch (JsonParseException e) { + log.error("Invalid JSON format provided for template.", e); + } + }); + } + + private static Optional<WatcherEventProcessor> getWatcherEventProcessor(WatchEvent<?> event) { + return Arrays.stream(values()).filter(value -> value.pathKind.equals(event.kind())).findFirst(); + } + +} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConnectionParams.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherService.java index 1d6eb89bf..26b684df9 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConnectionParams.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherService.java @@ -1,8 +1,8 @@ -/* +/*- * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER + * Simulator * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2019 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,28 +18,27 @@ * ============LICENSE_END========================================================= */ -package org.onap.pnfsimulator.netconfmonitor.netconf; +package org.onap.pnfsimulator.filesystem; -public class NetconfConnectionParams { +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.task.TaskExecutor; +import org.springframework.stereotype.Service; - public final String address; - public final int port; - public final String user; - public final String password; +@Service +public class WatcherService { - public NetconfConnectionParams(String address, int port, String user, String password) { - this.address = address; - this.port = port; - this.user = user; - this.password = password; + private TaskExecutor taskExecutor; + private ApplicationContext applicationContext; + + @Autowired + public WatcherService(ApplicationContext applicationContext, TaskExecutor taskExecutor) { + this.taskExecutor = taskExecutor; + this.applicationContext = applicationContext; } - @Override - public String toString() { - return String.format("NetconfConnectionParams{address=%s, port=%d, user=%s, password=%s}", - address, - port, - user, - password); + public void createWatcher() { + taskExecutor.execute(applicationContext.getBean(WatcherThread.class)); } -}
\ No newline at end of file + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherThread.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherThread.java new file mode 100644 index 000000000..a202b1f9e --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/filesystem/WatcherThread.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.filesystem; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import lombok.extern.slf4j.Slf4j; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.template.Template; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class WatcherThread implements Runnable { + + private final WatchService watchService; + private final Storage<Template> storage; + private final Path templatesDir; + + WatcherThread(String templatesDir, WatchService watchService, Storage<Template> storage) throws IOException { + this.watchService = watchService; + this.storage = storage; + this.templatesDir = Paths.get(templatesDir); + registerDirectory(this.templatesDir); + } + + @Autowired + public WatcherThread(@Value("${templates.dir}") String templatesDir, Storage<Template> storage) throws IOException { + this(templatesDir, FileSystems.getDefault().newWatchService(), storage); + } + + private void registerDirectory(Path path) throws IOException { + path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, + StandardWatchEventKinds.ENTRY_MODIFY); + } + + @Override + public void run() { + while (true) { + WatchKey key; + try { + key = watchService.take(); + for (WatchEvent<?> event : key.pollEvents()) { + WatcherEventProcessor.process(event, storage, templatesDir); + } + key.reset(); + } catch (InterruptedException e) { + log.error("Watch service interrupted.", e.getMessage()); + Thread.currentThread().interrupt(); + return; + } + + } + } +} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/logging/MDCVariables.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/logging/MDCVariables.java index 8f6fe3b66..5678f4fa3 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/logging/MDCVariables.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/logging/MDCVariables.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java new file mode 100644 index 000000000..88648f91d --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java @@ -0,0 +1,211 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonSyntaxException; +import org.json.JSONException; +import org.onap.pnfsimulator.event.EventData; +import org.onap.pnfsimulator.event.EventDataService; +import org.onap.pnfsimulator.rest.model.FullEvent; +import org.onap.pnfsimulator.rest.model.SimulatorRequest; +import org.onap.pnfsimulator.rest.util.DateUtil; +import org.onap.pnfsimulator.rest.util.ResponseBuilder; +import org.onap.pnfsimulator.simulator.SimulatorService; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfig; +import org.quartz.SchedulerException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.io.IOException; +import java.net.MalformedURLException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.onap.pnfsimulator.logging.MDCVariables.INSTANCE_UUID; +import static org.onap.pnfsimulator.logging.MDCVariables.INVOCATION_ID; +import static org.onap.pnfsimulator.logging.MDCVariables.REQUEST_ID; +import static org.onap.pnfsimulator.logging.MDCVariables.RESPONSE_CODE; +import static org.onap.pnfsimulator.logging.MDCVariables.SERVICE_NAME; +import static org.onap.pnfsimulator.logging.MDCVariables.X_INVOCATION_ID; +import static org.onap.pnfsimulator.logging.MDCVariables.X_ONAP_REQUEST_ID; +import static org.onap.pnfsimulator.rest.util.ResponseBuilder.MESSAGE; +import static org.onap.pnfsimulator.rest.util.ResponseBuilder.TIMESTAMP; +import static org.springframework.http.HttpStatus.ACCEPTED; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.OK; + +@RestController +@RequestMapping("/simulator") +public class SimulatorController { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimulatorController.class); + private static final Marker ENTRY = MarkerFactory.getMarker("ENTRY"); + private static final String INCORRECT_TEMPLATE_MESSAGE = "Cannot start simulator, template %s is not in valid format: %s"; + private static final String NOT_EXISTING_TEMPLATE = "Cannot start simulator - template %s not found."; + private final DateFormat responseDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss,SSS"); + private final SimulatorService simulatorService; + private EventDataService eventDataService; + + @Autowired + public SimulatorController(SimulatorService simulatorService, + EventDataService eventDataService) { + this.simulatorService = simulatorService; + this.eventDataService = eventDataService; + } + + @PostMapping("test") + @Deprecated + public ResponseEntity test(@Valid @RequestBody SimulatorRequest simulatorRequest) { + MDC.put("test", "test"); + LOGGER.info(ENTRY, simulatorRequest.toString()); + return buildResponse(OK, ImmutableMap.of(MESSAGE, "message1234")); + } + + @PostMapping(value = "start") + public ResponseEntity start(@RequestHeader HttpHeaders headers, + @Valid @RequestBody SimulatorRequest triggerEventRequest) { + logContextHeaders(headers, "/simulator/start"); + LOGGER.info(ENTRY, "Simulator started"); + + try { + return processRequest(triggerEventRequest); + + } catch (JSONException | JsonSyntaxException e) { + MDC.put(RESPONSE_CODE, BAD_REQUEST.toString()); + LOGGER.warn("Cannot trigger event, invalid json format: {}", e.getMessage()); + LOGGER.debug("Received json has invalid format", e); + return buildResponse(BAD_REQUEST, ImmutableMap.of(MESSAGE, String + .format(INCORRECT_TEMPLATE_MESSAGE, triggerEventRequest.getTemplateName(), + e.getMessage()))); + } catch (IOException e) { + MDC.put(RESPONSE_CODE, BAD_REQUEST.toString()); + LOGGER.warn("Json validation failed: {}", e.getMessage()); + return buildResponse(BAD_REQUEST, + ImmutableMap.of(MESSAGE, String.format(NOT_EXISTING_TEMPLATE, triggerEventRequest.getTemplateName()))); + } catch (Exception e) { + MDC.put(RESPONSE_CODE, INTERNAL_SERVER_ERROR.toString()); + LOGGER.error("Cannot trigger event - unexpected exception", e); + return buildResponse(INTERNAL_SERVER_ERROR, + ImmutableMap.of(MESSAGE, "Unexpected exception: " + e.getMessage())); + } finally { + MDC.clear(); + } + } + + @GetMapping("all-events") + @Deprecated + public ResponseEntity allEvents() { + List<EventData> eventDataList = eventDataService.getAllEvents(); + StringBuilder sb = new StringBuilder(); + eventDataList.forEach(e -> sb.append(e).append(System.lineSeparator())); + + return ResponseBuilder + .status(OK).put(MESSAGE, sb.toString()) + .build(); + } + + @GetMapping("config") + public ResponseEntity getConfig() { + SimulatorConfig configToGet = simulatorService.getConfiguration(); + return buildResponse(OK, ImmutableMap.of("simulatorConfig", configToGet)); + } + + @PutMapping("config") + public ResponseEntity updateConfig(@Valid @RequestBody SimulatorConfig newConfig) { + SimulatorConfig updatedConfig = simulatorService.updateConfiguration(newConfig); + return buildResponse(OK, ImmutableMap.of("simulatorConfig", updatedConfig)); + } + + @PostMapping("cancel/{jobName}") + public ResponseEntity cancelEvent(@PathVariable String jobName) throws SchedulerException { + LOGGER.info(ENTRY, "Cancel called on {}.", jobName); + boolean isCancelled = simulatorService.cancelEvent(jobName); + return createCancelEventResponse(isCancelled); + } + + @PostMapping("cancel") + public ResponseEntity cancelAllEvent() throws SchedulerException { + LOGGER.info(ENTRY, "Cancel called on all jobs"); + boolean isCancelled = simulatorService.cancelAllEvents(); + return createCancelEventResponse(isCancelled); + } + + @PostMapping("event") + public ResponseEntity sendEventDirectly(@RequestHeader HttpHeaders headers, @Valid @RequestBody FullEvent event) throws MalformedURLException { + logContextHeaders(headers, "/simulator/event"); + LOGGER.info(ENTRY, "Trying to send one-time event directly to VES Collector"); + simulatorService.triggerOneTimeEvent(event); + return buildResponse(ACCEPTED, ImmutableMap.of(MESSAGE, "One-time direct event sent successfully")); + } + + private ResponseEntity processRequest(SimulatorRequest triggerEventRequest) + throws IOException, SchedulerException { + + String jobName = simulatorService.triggerEvent(triggerEventRequest); + MDC.put(RESPONSE_CODE, OK.toString()); + return buildResponse(OK, ImmutableMap.of(MESSAGE, "Request started", "jobName", jobName)); + } + + private ResponseEntity buildResponse(HttpStatus endStatus, Map<String, Object> parameters) { + ResponseBuilder builder = ResponseBuilder + .status(endStatus) + .put(TIMESTAMP, DateUtil.getTimestamp(responseDateFormat)); + parameters.forEach(builder::put); + return builder.build(); + } + + private void logContextHeaders(HttpHeaders headers, String serviceName) { + MDC.put(REQUEST_ID, headers.getFirst(X_ONAP_REQUEST_ID)); + MDC.put(INVOCATION_ID, headers.getFirst(X_INVOCATION_ID)); + MDC.put(INSTANCE_UUID, UUID.randomUUID().toString()); + MDC.put(SERVICE_NAME, serviceName); + } + + private ResponseEntity createCancelEventResponse(boolean isCancelled) { + if (isCancelled) { + return buildResponse(OK, ImmutableMap.of(MESSAGE, "Event(s) was cancelled")); + } else { + return buildResponse(NOT_FOUND, ImmutableMap.of(MESSAGE, "Simulator was not able to cancel event(s)")); + } + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/TemplateController.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/TemplateController.java new file mode 100644 index 000000000..444e23bae --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/TemplateController.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import javax.validation.Valid; + +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.rest.model.TemplateRequest; +import org.onap.pnfsimulator.rest.model.SearchExp; +import org.onap.pnfsimulator.template.Template; +import org.onap.pnfsimulator.template.search.IllegalJsonValueException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + + +@RestController +@RequestMapping("/template") +public class TemplateController { + static final String TEMPLATE_NOT_FOUND_MSG = "A template with given name does not exist"; + static final String CANNOT_OVERRIDE_TEMPLATE_MSG = "Cannot overwrite existing template. Use override=true to override"; + private final Storage<Template> service; + private static final Logger LOG = LoggerFactory.getLogger(TemplateController.class); + + @Autowired + public TemplateController(Storage<Template> service) { + this.service = service; + } + + @GetMapping("list") + public ResponseEntity<?> list() { + return new ResponseEntity<>(service.getAll(), HttpStatus.OK); + } + + @GetMapping("get/{templateName}") + public ResponseEntity<?> get(@PathVariable String templateName) { + Optional<Template> template = service.get(templateName); + if (!template.isPresent()) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.TEXT_PLAIN); + return new ResponseEntity<>(TEMPLATE_NOT_FOUND_MSG, headers, HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(template, HttpStatus.OK); + } + + @PostMapping("upload") + public ResponseEntity<?> upload( + @RequestBody @Valid TemplateRequest templateRequest, + @RequestParam(required = false) boolean override) { + String msg = ""; + HttpStatus status = HttpStatus.CREATED; + Template template = new Template(templateRequest.getName(), templateRequest.getTemplate(), Instant.now().getNano()); + if (!service.tryPersistOrOverwrite(template, override)) { + status = HttpStatus.CONFLICT; + msg = CANNOT_OVERRIDE_TEMPLATE_MSG; + } + return new ResponseEntity<>(msg, status); + } + + @PostMapping("search") + public ResponseEntity<?> searchByCriteria(@RequestBody SearchExp queryJson) { + try { + List<String> templateNames = service.getIdsByContentCriteria(queryJson.getSearchExpr()); + return new ResponseEntity<>(templateNames, HttpStatus.OK); + } catch (IllegalJsonValueException ex) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, String.format("Try again with correct parameters. Cause: %s", ex.getMessage()), ex); + } + + } + + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/FullEvent.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/FullEvent.java new file mode 100644 index 000000000..77d9b3da1 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/FullEvent.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * FULL-EVENT + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.gson.JsonObject; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.rest.util.JsonObjectDeserializer; +import org.springframework.lang.Nullable; + +import javax.validation.constraints.NotNull; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@ToString +@EqualsAndHashCode +public class FullEvent { + + @Nullable + private String vesServerUrl; + + @NotNull + @JsonDeserialize(using = JsonObjectDeserializer.class) + private JsonObject event; +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SearchExp.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SearchExp.java new file mode 100644 index 000000000..41d112fd9 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SearchExp.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.gson.JsonObject; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.rest.util.JsonObjectDeserializer; + +import javax.validation.constraints.NotNull; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class SearchExp { + + @NotNull + @JsonDeserialize(using = JsonObjectDeserializer.class) + private JsonObject searchExpr; +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorParams.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorParams.java new file mode 100644 index 000000000..787583e7d --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorParams.java @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest.model; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import org.springframework.lang.Nullable; + +@Getter +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +public class SimulatorParams { + + @NotNull + private String vesServerUrl; + + @Nullable + private Integer repeatInterval; + + @Nullable + private Integer repeatCount; + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java new file mode 100644 index 000000000..2b0665813 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/SimulatorRequest.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.google.gson.JsonObject; +import javax.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.rest.util.JsonObjectDeserializer; +import org.springframework.lang.Nullable; + +@Getter +@ToString +@EqualsAndHashCode +@AllArgsConstructor +@NoArgsConstructor +public class SimulatorRequest { + + @NotNull + private SimulatorParams simulatorParams; + + @NotNull + private String templateName; + + @Nullable + @JsonDeserialize(using = JsonObjectDeserializer.class) + private JsonObject patch; + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/TemplateRequest.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/TemplateRequest.java new file mode 100644 index 000000000..d5a77f055 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/model/TemplateRequest.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest.model; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.bson.Document; + +@Getter +@Setter +@ToString +public class TemplateRequest { + private String name; + private Document template; + + public TemplateRequest(String name, Document template) { + this.name = name; + this.template = template; + } + + public TemplateRequest() { + } +} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/DateUtil.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/DateUtil.java index 284d58904..9a5c9ca9e 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/DateUtil.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/DateUtil.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/JsonObjectDeserializer.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/JsonObjectDeserializer.java new file mode 100644 index 000000000..f89c4a7b8 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/JsonObjectDeserializer.java @@ -0,0 +1,42 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest.util; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import java.io.IOException; + +public class JsonObjectDeserializer extends JsonDeserializer<JsonObject> { + private Gson gson = new Gson(); + + @Override + public JsonObject deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + ObjectCodec oc = jsonParser.getCodec(); + JsonNode node = oc.readTree(jsonParser); + return gson.fromJson(node.toString(), JsonObject.class); + } +} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/ResponseBuilder.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/ResponseBuilder.java index 98f4588c1..5fca25ad0 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/ResponseBuilder.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/util/ResponseBuilder.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/DBTemplateReader.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/DBTemplateReader.java new file mode 100644 index 000000000..6c1125434 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/DBTemplateReader.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.io.IOException; +import org.onap.pnfsimulator.template.Template; +import org.onap.pnfsimulator.template.TemplateService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class DBTemplateReader implements TemplateReader { + private final TemplateService service; + private final Gson gson; + + @Autowired + public DBTemplateReader(TemplateService service, Gson gson) { + this.service = service; + this.gson = gson; + } + + @Override + public JsonObject readTemplate(String templateName) throws IOException { + Template template = service.get(templateName).orElseThrow(() -> new IOException("Template does not exist")); + JsonElement jsonElement = gson.toJsonTree(template.getContent()); + return jsonElement.getAsJsonObject(); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/EventNotFoundException.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/EventNotFoundException.java new file mode 100644 index 000000000..4f43d8c49 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/EventNotFoundException.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +public class EventNotFoundException extends RuntimeException { + private static final String NOT_FOUND = "Not found an event with id: "; + public EventNotFoundException(String eventId) { + super(NOT_FOUND + eventId); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/FilesystemTemplateReader.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/FilesystemTemplateReader.java new file mode 100644 index 000000000..a405a2e1e --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/FilesystemTemplateReader.java @@ -0,0 +1,54 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class FilesystemTemplateReader implements TemplateReader { + + private final Path templatesDir; + private final Gson gson; + + @Autowired + FilesystemTemplateReader(@Value("${templates.dir}") String templatesDir, Gson gson) { + this.templatesDir = Paths.get(templatesDir); + this.gson = gson; + } + + public JsonObject readTemplate(String templateFileName) throws IOException { + Path absTemplateFilePath = templatesDir.resolve(templateFileName); + try (Stream<String> lines = Files.lines(absTemplateFilePath)) { + String content = lines.collect(Collectors.joining("\n")); + return gson.fromJson(content, JsonObject.class); + } + } +} + diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProvider.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProvider.java new file mode 100644 index 000000000..ea87ae6b3 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProvider.java @@ -0,0 +1,26 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +@FunctionalInterface +public interface IncrementProvider { + int getAndIncrement(String id); +} diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/ResourceReader.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProviderImpl.java index b5721533f..16c0a0ee7 100644 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/ResourceReader.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/IncrementProviderImpl.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2019 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,26 +20,28 @@ package org.onap.pnfsimulator.simulator; -import com.google.common.io.Resources; +import org.onap.pnfsimulator.event.EventData; +import org.onap.pnfsimulator.event.EventDataRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; -import java.io.IOException; -import java.net.URL; -import java.nio.charset.StandardCharsets; +@Service +public class IncrementProviderImpl implements IncrementProvider { + private final EventDataRepository repository; -public class ResourceReader { - private final String baseDirectory; + @Autowired + public IncrementProviderImpl(EventDataRepository repository) { + this.repository = repository; + } - public ResourceReader(String baseDirectory) { - this.baseDirectory = baseDirectory; - } - - public String readResource(String resourceName) { - try { - URL pnfRegistrationJson = Resources.getResource(baseDirectory + resourceName); - return Resources.toString(pnfRegistrationJson, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + @Override + public int getAndIncrement(String id) { + EventData eventData = repository.findById(id) + .orElseThrow(() -> new EventNotFoundException(id)); + int value = eventData.getIncrementValue() + 1; + eventData.setIncrementValue(value); + repository.save(eventData); + return value; + } } diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/JsonTokenProcessor.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/JsonTokenProcessor.java new file mode 100644 index 000000000..da0026a19 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/JsonTokenProcessor.java @@ -0,0 +1,134 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator; + +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.stream.Collectors; + +public enum JsonTokenProcessor { + STRING(JsonToken.STRING) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + String originalString = reader.nextString(); + if (keywordsExtractor.isPrimitive(originalString)) { + writer.value(keywordsExtractor.substitutePrimitiveKeyword(originalString)); + } else { + String possibleSubstitution = Arrays.stream(originalString.split(" ")) + .map(singleWord -> keywordsExtractor.substituteStringKeyword(singleWord, incrementValue)).collect( + Collectors.joining(" ")); + writer.value(originalString.equals(possibleSubstitution) ? originalString : possibleSubstitution); + } + } + }, + BEGIN_ARRAY(JsonToken.BEGIN_ARRAY) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.beginArray(); + writer.beginArray(); + } + }, + END_ARRAY(JsonToken.END_ARRAY) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.endArray(); + writer.endArray(); + } + }, + BEGIN_OBJECT(JsonToken.BEGIN_OBJECT) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.beginObject(); + writer.beginObject(); + } + }, + END_OBJECT(JsonToken.END_OBJECT) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.endObject(); + writer.endObject(); + } + }, + NAME(JsonToken.NAME) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + writer.name(reader.nextName()); + } + }, + NUMBER(JsonToken.NUMBER) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + writer.value(new BigDecimal(reader.nextString())); + } + }, + BOOLEAN(JsonToken.BOOLEAN) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + writer.value(reader.nextBoolean()); + } + }, + NULL(JsonToken.NULL) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + reader.nextNull(); + writer.nullValue(); + } + }, + END_DOCUMENT(JsonToken.END_DOCUMENT) { + @Override + void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) + throws IOException { + // do nothing + } + }; + + private JsonToken jsonToken; + + JsonTokenProcessor(JsonToken jsonToken) { + this.jsonToken = jsonToken; + } + + boolean isProcessorFor(JsonToken jsonToken) { + return this.jsonToken == jsonToken; + } + + abstract void process(JsonReader reader, JsonWriter writer, int incrementValue, KeywordsExtractor keywordsExtractor) throws IOException; + + private static final String INVALID_JSON_BODY_UNSUPPORTED_JSON_TOKEN = "Invalid json body. Unsupported JsonToken."; + + static JsonTokenProcessor getProcessorFor(JsonToken jsonToken) throws IOException { + return Arrays.stream(JsonTokenProcessor.values()).filter(processor -> processor.isProcessorFor(jsonToken)).findFirst() + .orElseThrow(() -> new IOException(INVALID_JSON_BODY_UNSUPPORTED_JSON_TOKEN)); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsExtractor.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsExtractor.java new file mode 100644 index 000000000..23c383f37 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsExtractor.java @@ -0,0 +1,118 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator; + +import static io.vavr.API.$; +import static io.vavr.API.Case; +import static io.vavr.API.Match; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getEpochSecond; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomLimitedInteger; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomInteger; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomLimitedString; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomString; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getRandomPrimitiveInteger; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.getTimestampPrimitive; +import static org.onap.pnfsimulator.simulator.keywords.NonParameterKeywordPatterns.$nonParameterKeyword; +import static org.onap.pnfsimulator.simulator.keywords.SingleParameterKeywordPatterns.$singleParameterKeyword; +import static org.onap.pnfsimulator.simulator.keywords.TwoParameterKeywordPatterns.$twoParameterKeyword; +import io.vavr.API.Match.Pattern1; +import org.onap.pnfsimulator.simulator.keywords.Keyword; +import org.onap.pnfsimulator.simulator.keywords.NonParameterKeyword; +import org.onap.pnfsimulator.simulator.keywords.SingleParameterKeyword; +import org.onap.pnfsimulator.simulator.keywords.TwoParameterKeyword; +import org.springframework.stereotype.Component; + +@Component +public class KeywordsExtractor { + + String substituteStringKeyword(String text, int increment) { + return Match(text).of( + Case(isRandomStringParamKeyword(), + spk -> spk.substituteKeyword(getRandomString().apply(spk.getAdditionalParameter()))), + Case(isRandomStringNonParamKeyword(), + npk -> npk.substituteKeyword(getRandomLimitedString().apply())), + Case(isRandomIntegerParamKeyword(), + tpk -> tpk.substituteKeyword(getRandomInteger().apply(tpk.getAdditionalParameter1(), tpk.getAdditionalParameter2()))), + Case(isRandomIntegerNonParamKeyword(), + npk -> npk.substituteKeyword(getRandomLimitedInteger().apply())), + Case(isIncrementKeyword(), + ik -> ik.substituteKeyword(String.valueOf(increment))), + Case(isTimestampNonParamKeyword(), + npk -> npk.substituteKeyword(getEpochSecond().apply())), + Case( + $(), + () -> text + )); + } + + Long substitutePrimitiveKeyword(String text) { + return Match(text).of( + Case(isRandomPrimitiveIntegerParamKeyword(), + tpk -> + getRandomPrimitiveInteger().apply(tpk.getAdditionalParameter1(), tpk.getAdditionalParameter2())), + Case(isTimestampPrimitiveNonParamKeyword(), + tpk -> + getTimestampPrimitive().apply()), + Case( + $(), + () -> 0L + )); + } + + boolean isPrimitive(String text) { + return Match(text).of( + Case(isRandomPrimitiveIntegerParamKeyword(), () -> true), + Case(isTimestampPrimitiveNonParamKeyword(), () -> true), + Case($(), () -> false)); + } + + private Pattern1<String, SingleParameterKeyword> isRandomStringParamKeyword() { + return $singleParameterKeyword($(spk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(spk, "RandomString"))); + } + + private Pattern1<String, NonParameterKeyword> isRandomStringNonParamKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "RandomString"))); + } + + private Pattern1<String, NonParameterKeyword> isIncrementKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "Increment"))); + } + + private Pattern1<String, TwoParameterKeyword> isRandomIntegerParamKeyword() { + return $twoParameterKeyword($(tpk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(tpk, "RandomInteger"))); + } + + private Pattern1<String, TwoParameterKeyword> isRandomPrimitiveIntegerParamKeyword() { + return $twoParameterKeyword($(tpk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(tpk, "RandomPrimitiveInteger"))); + } + + private Pattern1<String, NonParameterKeyword> isTimestampPrimitiveNonParamKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "TimestampPrimitive"))); + } + + private Pattern1<String, NonParameterKeyword> isRandomIntegerNonParamKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "RandomInteger"))); + } + + private Pattern1<String, NonParameterKeyword> isTimestampNonParamKeyword() { + return $nonParameterKeyword($(npk -> Keyword.IS_MATCHING_KEYWORD_NAME.apply(npk, "Timestamp"))); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsHandler.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsHandler.java new file mode 100644 index 000000000..51e0c1f16 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsHandler.java @@ -0,0 +1,72 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import org.springframework.stereotype.Component; + +@Component +public class KeywordsHandler { + + private KeywordsExtractor keywordsExtractor; + private IncrementProvider incrementProvider; + + public KeywordsHandler(KeywordsExtractor keywordsExtractor, IncrementProvider incrementProvider) { + this.keywordsExtractor = keywordsExtractor; + this.incrementProvider = incrementProvider; + } + + public JsonElement substituteKeywords(JsonElement jsonBody, String jobId) { + int counter = incrementProvider.getAndIncrement(jobId); + try ( + JsonReader reader = new JsonReader(new StringReader(jsonBody.toString())); + StringWriter stringWriter = new StringWriter(); + JsonWriter jsonWriter = new JsonWriter(stringWriter); + ) { + modify(reader, jsonWriter, counter); + return new Gson().fromJson(stringWriter.getBuffer().toString(), JsonElement.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void modify(JsonReader reader, JsonWriter writer, int incrementValue) throws IOException { + JsonTokenProcessor jsonTokenProcessor; + do { + JsonToken token = reader.peek(); + jsonTokenProcessor = JsonTokenProcessor.getProcessorFor(token); + jsonTokenProcessor.process(reader, writer, incrementValue, keywordsExtractor); + } while (isJsonProcessingFinished(jsonTokenProcessor)); + } + + private boolean isJsonProcessingFinished(JsonTokenProcessor jsonTokenProcessor) { + return !jsonTokenProcessor.isProcessorFor(JsonToken.END_DOCUMENT); + } + +} + + diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsValueProvider.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsValueProvider.java new file mode 100644 index 000000000..3bcfa5bca --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/KeywordsValueProvider.java @@ -0,0 +1,80 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator; + +import io.vavr.Function0; +import io.vavr.Function1; +import io.vavr.Function2; + +import java.time.Instant; +import java.util.Random; + +import org.apache.commons.lang3.RandomStringUtils; + +class KeywordsValueProvider { + + private KeywordsValueProvider() { + } + + static final int DEFAULT_STRING_LENGTH = 20; + public static final int RANDOM_INTEGER_MAX_LIMITATION = 9; + public static final int RANDOM_INTEGER_MIN_LIMITATION = 0; + + private static Function2<Integer, Integer, Integer> bigger = (left, right) -> left >= right ? left : right; + private static Function2<Integer, Integer, Integer> smaller = (left, right) -> left < right ? left : right; + private static Function2<Integer, Integer, Integer> randomPrimitiveIntegerFromSortedRange = (min, max) -> new Random().nextInt(max - min + 1) + min; + private static Function2<Integer, Integer, String> randomIntegerFromSortedRange = (min, max) -> Integer.toString(new Random().nextInt(max - min + 1) + min); + + private static Function1<Integer, String> randomString = RandomStringUtils::randomAscii; + private static Function2<Integer, Integer, String> randomInteger = (left, right) -> randomIntegerFromSortedRange.apply(smaller.apply(left, right), bigger.apply(left, right)); + private static Function0<String> randomLimitedInteger = () -> randomInteger.apply(RANDOM_INTEGER_MIN_LIMITATION, RANDOM_INTEGER_MAX_LIMITATION); + private static Function0<String> randomLimitedString = () -> RandomStringUtils.randomAscii(DEFAULT_STRING_LENGTH); + private static Function0<String> epochSecond = () -> Long.toString(Instant.now().getEpochSecond()); + private static Function2<Integer, Integer, Long> randomPrimitiveInteger = (left, right) -> randomPrimitiveIntegerFromSortedRange.apply(smaller.apply(left, right), bigger.apply(left, right)).longValue(); + private static Function0<Long> timestampPrimitive = () -> Instant.now().getEpochSecond(); + + public static Function1<Integer, String> getRandomString() { + return randomString; + } + + public static Function2<Integer, Integer, String> getRandomInteger() { + return randomInteger; + } + + public static Function0<String> getRandomLimitedInteger() { + return randomLimitedInteger; + } + + public static Function0<String> getRandomLimitedString() { + return randomLimitedString; + } + + public static Function0<String> getEpochSecond() { + return epochSecond; + } + + public static Function2<Integer, Integer, Long> getRandomPrimitiveInteger() { + return randomPrimitiveInteger; + } + + public static Function0<Long> getTimestampPrimitive() { + return timestampPrimitive; + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java new file mode 100644 index 000000000..704905584 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorService.java @@ -0,0 +1,117 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import com.google.common.base.Strings; +import com.google.gson.JsonObject; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Optional; +import org.onap.pnfsimulator.event.EventData; +import org.onap.pnfsimulator.event.EventDataService; +import org.onap.pnfsimulator.rest.model.FullEvent; +import org.onap.pnfsimulator.rest.model.SimulatorParams; +import org.onap.pnfsimulator.rest.model.SimulatorRequest; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.onap.pnfsimulator.simulator.scheduler.EventScheduler; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfig; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfigService; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SimulatorService { + + private final TemplatePatcher templatePatcher; + private final TemplateReader templateReader; + private final EventDataService eventDataService; + private final EventScheduler eventScheduler; + private SimulatorConfigService simulatorConfigService; + private static final JsonObject EMPTY_JSON_OBJECT = new JsonObject(); + + @Autowired + public SimulatorService(TemplatePatcher templatePatcher, TemplateReader templateReader, + EventScheduler eventScheduler, EventDataService eventDataService, + SimulatorConfigService simulatorConfigService) { + this.templatePatcher = templatePatcher; + this.templateReader = templateReader; + this.eventDataService = eventDataService; + this.eventScheduler = eventScheduler; + this.simulatorConfigService = simulatorConfigService; + } + + public String triggerEvent(SimulatorRequest simulatorRequest) throws IOException, SchedulerException { + String templateName = simulatorRequest.getTemplateName(); + SimulatorParams simulatorParams = simulatorRequest.getSimulatorParams(); + JsonObject template = templateReader.readTemplate(templateName); + JsonObject input = Optional.ofNullable(simulatorRequest.getPatch()).orElse(new JsonObject()); + JsonObject patchedJson = templatePatcher + .mergeTemplateWithPatch(template, input); + JsonObject keywords = new JsonObject(); + + EventData eventData = eventDataService.persistEventData(template, patchedJson, input, keywords); + + String targetVesUrl = getDefaultUrlIfNotProvided(simulatorParams.getVesServerUrl()); + return eventScheduler + .scheduleEvent(targetVesUrl, Optional.ofNullable(simulatorParams.getRepeatInterval()).orElse(1), + Optional.ofNullable(simulatorParams.getRepeatCount()).orElse(1), simulatorRequest.getTemplateName(), + eventData.getId(), + patchedJson); + } + + public void triggerOneTimeEvent(FullEvent event) throws MalformedURLException { + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), id -> 1); + JsonObject withKeywordsSubstituted = keywordsHandler.substituteKeywords(event.getEvent(), "").getAsJsonObject(); + + HttpClientAdapter client = createHttpClientAdapter(event.getVesServerUrl()); + eventDataService.persistEventData(EMPTY_JSON_OBJECT, withKeywordsSubstituted, event.getEvent(), EMPTY_JSON_OBJECT); + + client.send(withKeywordsSubstituted.toString()); + } + + public SimulatorConfig getConfiguration() { + return simulatorConfigService.getConfiguration(); + } + + public SimulatorConfig updateConfiguration(SimulatorConfig newConfig) { + return simulatorConfigService.updateConfiguration(newConfig); + } + + public boolean cancelAllEvents() throws SchedulerException { + return eventScheduler.cancelAllEvents(); + } + + public boolean cancelEvent(String jobName) throws SchedulerException { + return eventScheduler.cancelEvent(jobName); + } + + HttpClientAdapter createHttpClientAdapter(String vesServerUrl) throws MalformedURLException { + String targetVesUrl = getDefaultUrlIfNotProvided(vesServerUrl); + return new HttpClientAdapterImpl(targetVesUrl); + } + + private String getDefaultUrlIfNotProvided(String vesUrlSimulatorParam) { + return Strings.isNullOrEmpty(vesUrlSimulatorParam) + ? simulatorConfigService.getConfiguration().getVesServerUrl().toString() : vesUrlSimulatorParam; + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplatePatcher.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplatePatcher.java new file mode 100644 index 000000000..1114d3c1b --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplatePatcher.java @@ -0,0 +1,53 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +class TemplatePatcher { + + JsonObject mergeTemplateWithPatch(JsonObject templateJson, JsonObject patchJson) { + JsonObject template = templateJson.deepCopy(); + patchTemplateNode(template, patchJson); + return template; + } + + private void patchTemplateNode(JsonObject templateJson, JsonObject patchJson) { + for (Map.Entry<String, JsonElement> stringJsonElementEntry : patchJson.entrySet()) { + String patchKey = stringJsonElementEntry.getKey(); + JsonElement patchValue = stringJsonElementEntry.getValue(); + JsonElement templateElement = templateJson.get(patchKey); + + if (!patchValue.isJsonObject() || templateElement == null || !templateElement.isJsonObject()) { + templateJson.remove(patchKey); + templateJson.add(patchKey, patchValue); + } else { + patchTemplateNode(templateElement.getAsJsonObject(), patchValue.getAsJsonObject()); + } + + } + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateReader.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateReader.java new file mode 100644 index 000000000..bf06381d3 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/TemplateReader.java @@ -0,0 +1,28 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import com.google.gson.JsonObject; +import java.io.IOException; + +public interface TemplateReader { + JsonObject readTemplate(String templateName) throws IOException; +} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapter.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapter.java index 47f2e3112..e7d113dce 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapter.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapter.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,5 +22,5 @@ package org.onap.pnfsimulator.simulator.client; public interface HttpClientAdapter { - void send(String content, String url); + void send(String content); } diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java index f0c9917f5..6b0761975 100644 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImpl.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,14 +26,16 @@ import static org.onap.pnfsimulator.logging.MDCVariables.X_ONAP_REQUEST_ID; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; import java.util.UUID; + import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; +import org.onap.pnfsimulator.simulator.client.utils.ssl.SslSupportLevel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; @@ -42,43 +44,45 @@ import org.slf4j.MarkerFactory; public class HttpClientAdapterImpl implements HttpClientAdapter { + public static final int CONNECTION_TIMEOUT = 1000; private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientAdapterImpl.class); private static final String CONTENT_TYPE = "Content-Type"; private static final String APPLICATION_JSON = "application/json"; - private final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); private static final RequestConfig CONFIG = RequestConfig.custom() - .setConnectTimeout(1000) - .setConnectionRequestTimeout(1000) - .setSocketTimeout(1000) - .build(); - + .setConnectTimeout(CONNECTION_TIMEOUT) + .setConnectionRequestTimeout(CONNECTION_TIMEOUT) + .setSocketTimeout(CONNECTION_TIMEOUT) + .build(); + private static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); private HttpClient client; + private final String targetUrl; - public HttpClientAdapterImpl() { - this.client = HttpClientBuilder - .create() - .setDefaultRequestConfig(CONFIG) - .build(); + public HttpClientAdapterImpl(String targetUrl) throws MalformedURLException { + this.client = SslSupportLevel.getSupportLevelBasedOnProtocol(targetUrl).getClient(CONFIG); + this.targetUrl = targetUrl; + } + + HttpClientAdapterImpl(HttpClient client, String targetUrl) { + this.client = client; + this.targetUrl = targetUrl; } @Override - public void send(String content, String url) { + public void send(String content) { try { - HttpPost request = createRequest(content, url); + HttpPost request = createRequest(content); HttpResponse response = client.execute(request); + + //response has to be fully consumed otherwise apache won't release connection EntityUtils.consumeQuietly(response.getEntity()); LOGGER.info(INVOKE, "Message sent, ves response code: {}", response.getStatusLine()); } catch (IOException e) { - LOGGER.warn("Error sending message to ves: {}", e.getMessage()); + LOGGER.warn("Error sending message to ves: " + e.getMessage(), e.getCause()); } } - HttpClientAdapterImpl(HttpClient client) { - this.client = client; - } - - private HttpPost createRequest(String content, String url) throws UnsupportedEncodingException { - HttpPost request = new HttpPost(url); + private HttpPost createRequest(String content) throws UnsupportedEncodingException { + HttpPost request = new HttpPost(this.targetUrl); StringEntity stringEntity = new StringEntity(content); request.addHeader(CONTENT_TYPE, APPLICATION_JSON); request.addHeader(X_ONAP_REQUEST_ID, MDC.get(REQUEST_ID)); @@ -86,4 +90,6 @@ public class HttpClientAdapterImpl implements HttpClientAdapter { request.setEntity(stringEntity); return request; } -}
\ No newline at end of file + + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java new file mode 100644 index 000000000..29416341d --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevel.java @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator.client.utils.ssl; + +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.TrustAllStrategy; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContextBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLContext; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; + +public enum SslSupportLevel { + + NONE { + public HttpClient getClient(RequestConfig requestConfig) { + LOGGER.info("<!-----IN SslSupportLevel.NONE, Creating BasicHttpClient for http protocol----!>"); + return HttpClientBuilder + .create() + .setDefaultRequestConfig(requestConfig) + .build(); + } + }, + ALWAYS_TRUST { + public HttpClient getClient(RequestConfig requestConfig) { + LoggerFactory.getLogger(SslSupportLevel.class).info("<!-----IN SslSupportLevel.ALWAYS_TRUST, Creating client with SSL support for https protocol----!>"); + HttpClient client; + try { + SSLContext alwaysTrustSslContext = SSLContextBuilder.create().loadTrustMaterial(TRUST_STRATEGY_ALWAYS).build(); + client = HttpClients.custom() + .setSSLContext(alwaysTrustSslContext) + .setSSLHostnameVerifier(new NoopHostnameVerifier()) + .setDefaultRequestConfig(requestConfig) + .build(); + + } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { + LOGGER.error("Could not initialize client due to SSL exception: {}. Default client without SSL support will be used instead.\nCause: {}", e.getMessage(), e.getCause()); + client = NONE.getClient(requestConfig); + } + return client; + } + }; + + private static final Logger LOGGER = LoggerFactory.getLogger(SslSupportLevel.class); + private static final TrustStrategy TRUST_STRATEGY_ALWAYS = new TrustAllStrategy(); + + public static SslSupportLevel getSupportLevelBasedOnProtocol(String url) throws MalformedURLException { + return "https".equals(new URL(url).getProtocol()) ? SslSupportLevel.ALWAYS_TRUST : SslSupportLevel.NONE; + } + + public abstract HttpClient getClient(RequestConfig requestConfig); + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/Keyword.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/Keyword.java new file mode 100644 index 000000000..edafe8f04 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/Keyword.java @@ -0,0 +1,74 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator.keywords; + +import io.vavr.Function1; +import io.vavr.Function2; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.stream.Collectors; +import lombok.Getter; + +@Getter +public class Keyword { + + protected static final String LETTERS_REGEX = "([a-zA-Z]+)"; + protected static final String NONLETTERS_REGEX = "([^a-zA-Z]+)"; + + protected static final Function1<String, String> OPTIONAL = + (regex) -> regex + "?"; + + private final String name; + private final List<String> meaningfulParts; + + public static final Function2<Keyword, String, Boolean> IS_MATCHING_KEYWORD_NAME = (keyword, key) -> + keyword != null && keyword.getName() != null && keyword.getName().equals(key); + + /** + * Returns list of independent parts inside the keyword. Current implementation assumes that customer can join keywords with integer values, so + * keyword is decomposed to parts then some parts of the keyword is skipped because of replacement process. + * + * @param matcher - Matcher to check find independent groups inside the keyword + * @param skipGroups Informs this method about which groups should be consider as part of the replacement process + * @return list of independent parts inside the keywords + */ + static List<String> extractPartsFrom(Matcher matcher, List skipGroups) { + List<String> parts = new ArrayList<String>(); + for (int i = 1; i <= matcher.groupCount(); i++) { + if (matcher.group(i) != null && !skipGroups.contains(i)) { + parts.add(matcher.group(i)); + } + } + return parts; + } + + Keyword(String name, List<String> meaningfulParts) { + this.name = name; + this.meaningfulParts = meaningfulParts; + } + + public String substituteKeyword(String substitution) { + return meaningfulParts.stream() + .map(part -> part.equals(name) ? substitution : part) + .collect(Collectors.joining()); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/NonParameterKeyword.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/NonParameterKeyword.java new file mode 100644 index 000000000..5e44550bc --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/NonParameterKeyword.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator.keywords; + +import io.vavr.Tuple; +import io.vavr.Tuple1; +import io.vavr.match.annotation.Patterns; +import io.vavr.match.annotation.Unapply; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.Setter; +import lombok.val; + +@Patterns +@Getter +@Setter +public class NonParameterKeyword extends Keyword { + + public static final int KEYWORD_NAME_GROUP = 2; + + private static final String KEYWORD_REGEX = new StringBuilder() + .append(OPTIONAL.apply(NONLETTERS_REGEX)) + .append("#") + .append(LETTERS_REGEX) + .append("(?!\\()") + .append(OPTIONAL.apply(NONLETTERS_REGEX)) + .toString(); + + private NonParameterKeyword(String name, List<String> meaningfulParts) { + super(name, meaningfulParts); + } + + @Unapply + static Tuple1<NonParameterKeyword> nonParameterKeyword(String keyword) { + val matcher = Pattern.compile(KEYWORD_REGEX).matcher(keyword); + NonParameterKeyword npk = null; + if (matcher.find()) { + npk = new NonParameterKeyword( + matcher.group(KEYWORD_NAME_GROUP), + extractPartsFrom(matcher, Collections.emptyList()) + ); + } + return Tuple.of(npk); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/SingleParameterKeyword.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/SingleParameterKeyword.java new file mode 100644 index 000000000..b1c38c883 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/SingleParameterKeyword.java @@ -0,0 +1,73 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator.keywords; + +import io.vavr.Tuple; +import io.vavr.Tuple1; +import io.vavr.match.annotation.Patterns; +import io.vavr.match.annotation.Unapply; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.Setter; +import lombok.val; + +@Patterns +@Getter +@Setter +public class SingleParameterKeyword extends Keyword { + + public static final int KEYWORD_NAME_GROUP = 2; + public static final int ADDITIONAL_PARAMETER_GROUP = 3; + + private static final String KEYWORD_REGEX = new StringBuilder() + .append(OPTIONAL.apply(NONLETTERS_REGEX)) + .append("#") + .append(LETTERS_REGEX) + .append("\\((\\d+)\\)") + .append(OPTIONAL.apply(NONLETTERS_REGEX)) + .toString(); + public static final int SKIPPED_GROUP_NUMBER = 3; + + private Integer additionalParameter; + + private SingleParameterKeyword(String name, List<String> meaningfulParts, + Integer additionalParameter) { + super(name, meaningfulParts); + this.additionalParameter = additionalParameter; + } + + @Unapply + static Tuple1<SingleParameterKeyword> singleParameterKeyword(String keyword) { + val matcher = Pattern.compile(KEYWORD_REGEX).matcher(keyword); + SingleParameterKeyword spk = null; + if (matcher.find()) { + spk = new SingleParameterKeyword( + matcher.group(KEYWORD_NAME_GROUP), + extractPartsFrom(matcher, Collections.singletonList(SKIPPED_GROUP_NUMBER)), + Integer.parseInt(matcher.group(ADDITIONAL_PARAMETER_GROUP)) + ); + } + return Tuple.of(spk); + } +} + + diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/TwoParameterKeyword.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/TwoParameterKeyword.java new file mode 100644 index 000000000..6fecfa63b --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/keywords/TwoParameterKeyword.java @@ -0,0 +1,80 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator.keywords; + +import io.vavr.Tuple; +import io.vavr.Tuple1; +import io.vavr.match.annotation.Patterns; +import io.vavr.match.annotation.Unapply; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.Setter; +import lombok.val; + +@Patterns +@Getter +@Setter +public class TwoParameterKeyword extends Keyword { + + public static final int ADDITIONAL_PARAMETER_1_GROUP = 3; + public static final int ADDITIONAL_PARAMETER_2_GROUP = 4; + public static final int KEYWORD_NAME_GROUP = 2; + protected static final List<Integer> ADDITIONAL_PARAMETERS_GROUPS = Arrays.asList(ADDITIONAL_PARAMETER_1_GROUP, ADDITIONAL_PARAMETER_2_GROUP); + + private static final String NON_LIMITED_NUMBER_REGEX = "\\((\\d+)"; + private static final String COLON_REGEX = "\\s?,\\s?"; + private static final String OPTIONAL_NUMBER_PARAM_REGEX = "(\\d+)\\)"; + + private static final String KEYWORD_REGEX = OPTIONAL.apply(NONLETTERS_REGEX) + + "#" + + LETTERS_REGEX + + NON_LIMITED_NUMBER_REGEX + + COLON_REGEX + + OPTIONAL_NUMBER_PARAM_REGEX + + OPTIONAL.apply(NONLETTERS_REGEX); + + private Integer additionalParameter1; + private Integer additionalParameter2; + + private TwoParameterKeyword(String name, List<String> meaningfulParts, Integer additionalParameter1, + Integer additionalParameter2) { + super(name, meaningfulParts); + this.additionalParameter1 = additionalParameter1; + this.additionalParameter2 = additionalParameter2; + } + + @Unapply + static Tuple1<TwoParameterKeyword> twoParameterKeyword(String keyword) { + val matcher = Pattern.compile(KEYWORD_REGEX).matcher(keyword); + TwoParameterKeyword tpk = null; + if (matcher.find()) { + tpk = new TwoParameterKeyword( + matcher.group(KEYWORD_NAME_GROUP), + extractPartsFrom(matcher, ADDITIONAL_PARAMETERS_GROUPS), + Integer.parseInt(matcher.group(ADDITIONAL_PARAMETER_1_GROUP)), + Integer.parseInt(matcher.group(ADDITIONAL_PARAMETER_2_GROUP)) + ); + } + return Tuple.of(tpk); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java new file mode 100644 index 000000000..52d076fad --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventJob.java @@ -0,0 +1,88 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator.scheduler; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.onap.pnfsimulator.simulator.KeywordsHandler; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.MalformedURLException; +import java.util.Optional; + +public class EventJob implements Job { + + private static final Logger LOGGER = LoggerFactory.getLogger(EventJob.class); + + static final String TEMPLATE_NAME = "TEMPLATE_NAME"; + static final String VES_URL = "VES_URL"; + static final String BODY = "BODY"; + static final String CLIENT_ADAPTER = "CLIENT_ADAPTER"; + static final String KEYWORDS_HANDLER = "KEYWORDS_HANDLER"; + static final String EVENT_ID = "EVENT_ID"; + + @Override + public void execute(JobExecutionContext jobExecutionContext) { + JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); + String templateName = jobDataMap.getString(TEMPLATE_NAME); + String vesUrl = jobDataMap.getString(VES_URL); + JsonObject body = (JsonObject) jobDataMap.get(BODY); + String id = jobDataMap.getString(EVENT_ID); + Optional<HttpClientAdapter> httpClientAdapter = getHttpClientAdapter(jobDataMap, vesUrl); + + if (httpClientAdapter.isPresent()) { + KeywordsHandler keywordsHandler = (KeywordsHandler) jobDataMap.get(KEYWORDS_HANDLER); + JsonElement processedBody = keywordsHandler.substituteKeywords(body, id); + String processedBodyString = processedBody.toString(); + String jobKey = jobExecutionContext.getJobDetail().getKey().toString(); + + logEventDetails(templateName, vesUrl, body.toString(), jobKey); + httpClientAdapter.get().send(processedBodyString); + } else { + LOGGER.error("Could not send event as client is not available"); + } + } + private Optional<HttpClientAdapter> getHttpClientAdapter(JobDataMap jobDataMap, String vesUrl) { + HttpClientAdapter adapter = null; + try { + adapter = (HttpClientAdapter) jobDataMap + .getOrDefault(CLIENT_ADAPTER, new HttpClientAdapterImpl(vesUrl)); + } catch (MalformedURLException e) { + LOGGER.error("Invalid format of vesServerUr: {}", vesUrl); + } + return Optional.ofNullable(adapter); + } + + private void logEventDetails(String templateName, String vesUrl, String body, String jobKey) { + LOGGER.info(String.format("Job %s:Sending event to %s from template %s", + jobKey, vesUrl, templateName)); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(String.format("Job %s: Request body %s", jobKey, body)); + } + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java new file mode 100644 index 000000000..1b1746fa5 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/EventScheduler.java @@ -0,0 +1,116 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator.scheduler; + + +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.BODY; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.CLIENT_ADAPTER; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.EVENT_ID; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.KEYWORDS_HANDLER; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.TEMPLATE_NAME; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.VES_URL; +import static org.quartz.SimpleScheduleBuilder.simpleSchedule; + +import com.google.gson.JsonObject; + +import java.net.MalformedURLException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.onap.pnfsimulator.simulator.KeywordsHandler; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; +import org.quartz.JobBuilder; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.SimpleTrigger; +import org.quartz.TriggerBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class EventScheduler { + + + private final Scheduler scheduler; + private final KeywordsHandler keywordsHandler; + + @Autowired + public EventScheduler(Scheduler scheduler, KeywordsHandler keywordsHandler) { + this.scheduler = scheduler; + this.keywordsHandler = keywordsHandler; + } + + public String scheduleEvent(String vesUrl, Integer repeatInterval, Integer repeatCount, + String templateName, String eventId, JsonObject body) + throws SchedulerException, MalformedURLException { + + JobDetail jobDetail = createJobDetail(vesUrl, templateName, eventId, body); + SimpleTrigger trigger = createTrigger(repeatInterval, repeatCount); + + scheduler.scheduleJob(jobDetail, trigger); + return jobDetail.getKey().getName(); + } + + public boolean cancelAllEvents() throws SchedulerException { + List<JobKey> jobKeys = getActiveJobsKeys(); + return scheduler.deleteJobs(jobKeys); + } + + public boolean cancelEvent(String jobName) throws SchedulerException { + Optional<JobKey> activeJobKey = getActiveJobsKeys().stream().filter(e -> e.getName().equals(jobName)).findFirst(); + return activeJobKey.isPresent() && scheduler.deleteJob(activeJobKey.get()); + } + + private SimpleTrigger createTrigger(int interval, int repeatCount) { + return TriggerBuilder.newTrigger() + .withSchedule(simpleSchedule() + .withIntervalInSeconds(interval) + .withRepeatCount(repeatCount - 1)) + .build(); + } + + private JobDetail createJobDetail(String vesUrl, String templateName, String eventId, JsonObject body) throws MalformedURLException { + JobDataMap jobDataMap = new JobDataMap(); + jobDataMap.put(TEMPLATE_NAME, templateName); + jobDataMap.put(VES_URL, vesUrl); + jobDataMap.put(EVENT_ID, eventId); + jobDataMap.put(KEYWORDS_HANDLER, keywordsHandler); + jobDataMap.put(BODY, body); + jobDataMap.put(CLIENT_ADAPTER, new HttpClientAdapterImpl(vesUrl)); + + return JobBuilder + .newJob(EventJob.class) + .withDescription(templateName) + .usingJobData(jobDataMap) + .build(); + } + + private List<JobKey> getActiveJobsKeys() throws SchedulerException { + return scheduler.getCurrentlyExecutingJobs() + .stream() + .map(JobExecutionContext::getJobDetail) + .map(JobDetail::getKey) + .collect(Collectors.toList()); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/QuartzConfiguration.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/QuartzConfiguration.java new file mode 100644 index 000000000..2beb9dc5e --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/scheduler/QuartzConfiguration.java @@ -0,0 +1,38 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.pnfsimulator.simulator.scheduler; + +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.impl.StdSchedulerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +class QuartzConfiguration { + + @Bean + Scheduler provideScheduler() throws SchedulerException { + StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); + Scheduler scheduler = stdSchedulerFactory.getScheduler(); + scheduler.start(); + return scheduler; + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfig.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfig.java new file mode 100644 index 000000000..0baa47796 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfig.java @@ -0,0 +1,49 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulatorconfig; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Field; + +import javax.validation.constraints.NotNull; +import java.net.URL; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@ToString +public class SimulatorConfig { + + @JsonIgnore + @Id + private String id; + + @NotNull + @Field("vesServerUrl") + private URL vesServerUrl; +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigRepository.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigRepository.java new file mode 100644 index 000000000..5e63ee493 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigRepository.java @@ -0,0 +1,26 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulatorconfig; + +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface SimulatorConfigRepository extends MongoRepository<SimulatorConfig, String> { +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigService.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigService.java new file mode 100644 index 000000000..206335117 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigService.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulatorconfig; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class SimulatorConfigService { + + private final SimulatorConfigRepository repository; + + @Autowired + public SimulatorConfigService(SimulatorConfigRepository repository) { + this.repository = repository; + } + + + public SimulatorConfig getConfiguration() { + List<SimulatorConfig> configs = repository.findAll(); + if (configs.isEmpty()) { + throw new IllegalStateException("No configuration found in db"); + } + return configs.get(0); + } + + public SimulatorConfig updateConfiguration(SimulatorConfig configuration) { + SimulatorConfig currentConfig = getConfiguration(); + currentConfig.setVesServerUrl(configuration.getVesServerUrl()); + return repository.save(currentConfig); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/FsToDbTemplateSynchronizer.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/FsToDbTemplateSynchronizer.java new file mode 100644 index 000000000..881585bd6 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/FsToDbTemplateSynchronizer.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Stream; + +import org.bson.json.JsonParseException; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.filesystem.WatcherEventProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +public class FsToDbTemplateSynchronizer { + + private static final String CANNOT_SYNC = "Cannot synchronize templates. Check whether the proper folder exists."; + private static final Logger LOGGER = LoggerFactory.getLogger(FsToDbTemplateSynchronizer.class); + + private final String templatesDir; + private final Storage<Template> storage; + + @Autowired + public FsToDbTemplateSynchronizer(@Value("${templates.dir}") String templatesDir, + Storage<Template> storage) { + this.templatesDir = templatesDir; + this.storage = storage; + } + + public void synchronize() { + try { + processTemplatesFolder(); + } catch (IOException e) { + LOGGER.error(CANNOT_SYNC, e); + } + } + + private void processTemplatesFolder() throws IOException { + try (Stream<Path> walk = Files.walk(Paths.get(templatesDir))) { + walk.filter(Files::isRegularFile).forEach(path -> { + try { + WatcherEventProcessor.MODIFIED.processEvent(path, storage); + } catch (IOException | JsonParseException e) { + LOGGER + .error("Cannot synchronize template: " + path.getFileName().toString(), e); + } + }); + } + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/Template.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/Template.java new file mode 100644 index 000000000..c84b8d0b7 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/Template.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.db.Row; +import org.bson.Document; +import org.onap.pnfsimulator.template.search.JsonUtils; +import org.springframework.data.mongodb.core.mapping.Field; + +@NoArgsConstructor +@ToString +public class Template extends Row { + + @Field("content") + private Document content; + + @Field("flatContent") + private Document flatContent; + + @Field("lmod") + private long lmod; + + public Template(String name, Document content, long lmod) { + this.id = name; + this.content = content; + this.lmod = lmod; + this.flatContent = new JsonUtils().flatten(content); + } + + public Template(String name, String template, long lmod) { + this.id = name; + this.content = Document.parse(template); + this.lmod = lmod; + this.flatContent = new JsonUtils().flatten(this.content); + } + + public void setContent(Document content) { + this.content = content; + this.flatContent = new JsonUtils().flatten(content); + } + + public Document getContent() { + return new Document(this.content); + } + + @JsonIgnore + public Document getFlatContent() { + return new Document(this.flatContent); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Template template = (Template) o; + return Objects.equals(content, template.content) + && Objects.equals(id, template.id) + && Objects.equals(lmod, template.lmod); + } + + @Override + public int hashCode() { + return Objects.hash(content, id); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateRepository.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateRepository.java new file mode 100644 index 000000000..78c9c77e0 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateRepository.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template; + +import org.springframework.data.mongodb.repository.MongoRepository; + +public interface TemplateRepository extends MongoRepository<Template, String> { +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateService.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateService.java new file mode 100644 index 000000000..3e245e123 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/TemplateService.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template; + +import java.util.List; +import java.util.Optional; + +import com.google.gson.JsonObject; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.template.search.TemplateSearchHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; + +@Primary +@Service +public class TemplateService implements Storage<Template> { + + private final TemplateRepository templateRepository; + private TemplateSearchHelper searchHelper; + + + @Autowired + public TemplateService(TemplateRepository templateRepository, TemplateSearchHelper searchHelper) { + this.templateRepository = templateRepository; + this.searchHelper = searchHelper; + } + + @Override + public List<Template> getAll() { + return templateRepository.findAll(); + } + + @Override + public Optional<Template> get(String name) { + return templateRepository.findById(name); + } + + @Override + public void persist(Template template) { + templateRepository.save(template); + } + + @Override + public boolean tryPersistOrOverwrite(Template template, boolean overwrite) { + if (templateRepository.existsById(template.getId()) && !overwrite) { + return false; + } + templateRepository.save(template); + return true; + } + + @Override + public void delete(String templateName) { + templateRepository.deleteById(templateName); + } + + @Override + public List<String> getIdsByContentCriteria(JsonObject stringQueryJson) { + return searchHelper.getIdsOfDocumentMatchingCriteria(stringQueryJson); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/IllegalJsonValueException.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/IllegalJsonValueException.java new file mode 100644 index 000000000..6890382ea --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/IllegalJsonValueException.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search; + +public class IllegalJsonValueException extends IllegalArgumentException { + + IllegalJsonValueException(String s) { + super(s); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/JsonUtils.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/JsonUtils.java new file mode 100644 index 000000000..b595b4f36 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/JsonUtils.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search; + +import com.google.common.base.Strings; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.bson.Document; + +/** + * This util flattens nested json and produces json with keys transformed to form of json path + * where default separator between parent object key and object key is ':' + * For easing searching of boolean values, they are converted to its string representation + */ +public class JsonUtils { + + private static final String DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR = ":"; + private static final String SEED_PREFIX = ""; + private static final Gson GSON = new Gson(); + + public JsonObject flatten(JsonObject original) { + return flattenWithPrefixedKeys(DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR, original.deepCopy(), SEED_PREFIX, new JsonObject()); + } + + public JsonObject flatten(String parentKeyToKeySeparator, JsonObject original) { + return flattenWithPrefixedKeys(parentKeyToKeySeparator, original.deepCopy(), SEED_PREFIX, new JsonObject()); + } + + public Document flatten(Document original) { + return flatten(DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR, original); + } + + public Document flatten(String parentKeyToKeySeparator, Document original) { + JsonObject originalJsonObject = GSON.fromJson(original.toJson(), JsonObject.class); + JsonObject flattenedJson = flatten(parentKeyToKeySeparator, originalJsonObject); + return Document.parse(flattenedJson.toString()); + } + + private JsonObject flattenWithPrefixedKeys(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) { + if (topLevelElem.isJsonPrimitive()) { + handleJsonPrimitive(topLevelElem, prefix, acc); + } else if (topLevelElem.isJsonArray()) { + handleJsonArray(parentKeyToKeySeparator, topLevelElem, prefix, acc); + } else if (topLevelElem.isJsonObject()) { + handleJsonObject(parentKeyToKeySeparator, topLevelElem, prefix, acc); + } else { + acc.add(prefix, topLevelElem.getAsJsonNull()); + } + return acc.deepCopy(); + } + + private void handleJsonObject(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) { + boolean isEmpty = true; + JsonObject thisToplevelObj = topLevelElem.getAsJsonObject(); + for (String key : thisToplevelObj.keySet()) { + isEmpty = false; + String keyPrefix = String.format("%s%s%s", prefix, parentKeyToKeySeparator, key); + flattenWithPrefixedKeys(parentKeyToKeySeparator, thisToplevelObj.get(key), keyPrefix, acc); + } + if (isEmpty && !Strings.isNullOrEmpty(prefix)) { + acc.add(prefix, new JsonObject()); + } + } + + private void handleJsonArray(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) { + JsonArray asJsonArray = topLevelElem.getAsJsonArray(); + if (asJsonArray.size() == 0) { + acc.add(prefix, new JsonArray()); + } + for (int i = 0; i < asJsonArray.size(); i++) { + flattenWithPrefixedKeys(parentKeyToKeySeparator, asJsonArray.get(i), String.format("%s[%s]", prefix, i), acc); + } + } + + private void handleJsonPrimitive(JsonElement topLevelElem, String prefix, JsonObject acc) { + JsonPrimitive jsonPrimitive = topLevelElem.getAsJsonPrimitive(); + if (jsonPrimitive.isBoolean()) { + acc.add(prefix, new JsonPrimitive(jsonPrimitive.getAsString())); + } else { + acc.add(prefix, topLevelElem.getAsJsonPrimitive()); + } + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/TemplateSearchHelper.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/TemplateSearchHelper.java new file mode 100644 index 000000000..3f22b1adf --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/TemplateSearchHelper.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.onap.pnfsimulator.template.search.handler.PrimitiveValueCriteriaBuilder; +import org.onap.pnfsimulator.template.search.viewmodel.FlatTemplateContent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Component +public class TemplateSearchHelper { + private static final String PARENT_TO_CHILD_KEY_SEPARATOR = ":"; //compliant with flat json stored in db + private static final String FLATTENED_JSON_KEY_REGEX = PARENT_TO_CHILD_KEY_SEPARATOR + "%s(?:(\\[[\\d]+\\]))?$"; + private static final String FLATTENED_TEMPLATES_VIEW = "flatTemplatesView"; + + private MongoTemplate mongoTemplate; + private PrimitiveValueCriteriaBuilder criteriaBuilder; + + @Autowired + public TemplateSearchHelper(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + this.criteriaBuilder = new PrimitiveValueCriteriaBuilder(); + } + + public List<String> getIdsOfDocumentMatchingCriteria(JsonObject jsonCriteria) { + if (isNullValuePresentInCriteria(jsonCriteria)) { + throw new IllegalJsonValueException("Null values in search criteria are not supported."); + } + Criteria mongoDialectCriteria = composeCriteria(jsonCriteria); + Query query = new Query(mongoDialectCriteria); + List<FlatTemplateContent> flatTemplateContents = mongoTemplate.find(query, FlatTemplateContent.class, FLATTENED_TEMPLATES_VIEW); + return flatTemplateContents + .stream() + .map(FlatTemplateContent::getId) + .collect(Collectors.toList()); + } + + + private Criteria composeCriteria(JsonObject criteria) { + Criteria[] criteriaArr = criteria.entrySet() + .stream() + .map(this::mapEntryCriteriaWithRegex) + .toArray(Criteria[]::new); + return criteriaArr.length > 0 ? new Criteria().andOperator(criteriaArr) : new Criteria(); + } + + private Criteria mapEntryCriteriaWithRegex(Map.Entry<String, JsonElement> entry) { + Pattern primitiveOrArrayElemKeyRegex = getCaseInsensitive(String.format(FLATTENED_JSON_KEY_REGEX, entry.getKey())); + Criteria criteriaForJsonKey = Criteria.where("k").regex(primitiveOrArrayElemKeyRegex); + Criteria criteriaWithValue = criteriaBuilder.applyValueCriteriaBasedOnPrimitiveType(criteriaForJsonKey.and("v"), entry.getValue().getAsJsonPrimitive()); + return Criteria.where("keyValues").elemMatch(criteriaWithValue); + + } + + private boolean isNullValuePresentInCriteria(JsonObject jsonObject) { + return jsonObject.entrySet() + .stream() + .map(Map.Entry::getValue) + .anyMatch(JsonElement::isJsonNull); + } + + static Pattern getCaseInsensitive(String base) { + return Pattern.compile(base, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + } +} + + diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilder.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilder.java new file mode 100644 index 000000000..79d64b7dd --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilder.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search.handler; + +import com.google.common.collect.Lists; +import com.google.gson.JsonPrimitive; +import org.springframework.data.mongodb.core.query.Criteria; + +import java.util.List; +import java.util.regex.Pattern; + +/** + * This class is a helper class for constructing apropriate criteria for query send to mongodb based on type of value. + * Query is build to search mongodb for templates that contains key-value pairs that satisfy given criteria. + * Value is oftype JsonPrimitive, based on its primitive java type following criteria are build to get proper document: + * -for string - there is a regex expression that ignores every meta character inside passed argument and searches for exact literal match ignoring case; + * -for number - all numbers are treated as double (mongodb number type equivalent) + * -for boolean - exact match, used string representation of boolean in search + **/ + +public class PrimitiveValueCriteriaBuilder { + + private final List<ValueTypeHandler> typeHandlers; + + public PrimitiveValueCriteriaBuilder() { + typeHandlers = Lists.newArrayList(new StringValueHandler(), new NumberValueHandler(), new BoolValueHandler()); + } + + public Criteria applyValueCriteriaBasedOnPrimitiveType(Criteria baseCriteria, JsonPrimitive jsonPrimitive) { + ValueTypeHandler typeHandler = typeHandlers.stream() + .filter(el -> el.isProperTypeHandler(jsonPrimitive)) + .findFirst() + .orElseThrow(() -> + new IllegalArgumentException(String.format( + "Expected json primitive, but given value: %s is of type: %s and could not be decoded", + jsonPrimitive, jsonPrimitive.getClass().toString()))); + return typeHandler.chainCriteriaForValue(baseCriteria, jsonPrimitive); + } + + private interface ValueTypeHandler { + boolean isProperTypeHandler(JsonPrimitive value); + + Criteria chainCriteriaForValue(Criteria criteria, JsonPrimitive value); + } + + private class BoolValueHandler implements ValueTypeHandler { + public boolean isProperTypeHandler(JsonPrimitive value) { + return value.isBoolean(); + } + + public Criteria chainCriteriaForValue(Criteria criteria, JsonPrimitive value) { + return criteria.is(value.getAsString()); + } + + } + + private class NumberValueHandler implements ValueTypeHandler { + public boolean isProperTypeHandler(JsonPrimitive value) { + return value.isNumber(); + } + + public Criteria chainCriteriaForValue(Criteria baseCriteria, JsonPrimitive value) { + return baseCriteria.is(value.getAsDouble()); + } + } + + private class StringValueHandler implements ValueTypeHandler { + public boolean isProperTypeHandler(JsonPrimitive value) { + return value.isString(); + } + + public Criteria chainCriteriaForValue(Criteria baseCriteria, JsonPrimitive value) { + return baseCriteria.regex(makeRegexCaseInsensitive(value.getAsString())); + } + + private Pattern makeRegexCaseInsensitive(String base) { + String metaCharEscaped = convertToIgnoreMetaChars(base); + return Pattern.compile("^" + metaCharEscaped + "$", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + } + + private String convertToIgnoreMetaChars(String valueWithMetaChars) { + return Pattern.quote(valueWithMetaChars); + } + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/FlatTemplateContent.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/FlatTemplateContent.java new file mode 100644 index 000000000..84235f709 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/FlatTemplateContent.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search.viewmodel; + + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.onap.pnfsimulator.db.Row; + +import java.util.List; + +@Getter +@NoArgsConstructor +@ToString +public class FlatTemplateContent extends Row { + + private List<KeyValuePair> keyValues; + + + public FlatTemplateContent(String name, List<KeyValuePair> keyValues) { + this.id = name; + this.keyValues = keyValues; + } +} + + diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/KeyValuePair.java b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/KeyValuePair.java new file mode 100644 index 000000000..5e44452d3 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/java/org/onap/pnfsimulator/template/search/viewmodel/KeyValuePair.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search.viewmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Getter +@ToString +@NoArgsConstructor +@AllArgsConstructor +/** + * POJO for mongo structure after $objectToArray mapping where object consists of fields: k and v + */ +public class KeyValuePair { + + private String k; + private String v; + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/application.properties b/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/application.properties new file mode 100644 index 000000000..ae21b674c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/application.properties @@ -0,0 +1,7 @@ +server.port=5000 +templates.dir=/app/templates +spring.data.mongodb.host=mongo +spring.data.mongodb.port=27017 +spring.data.mongodb.username=pnf_simulator_user +spring.data.mongodb.password=zXcVbN123! +spring.data.mongodb.database=pnf_simulator diff --git a/test/mocks/pnfsimulator/src/main/resources/logback.xml b/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/logback.xml index de34b9ae3..8569b562f 100644 --- a/test/mocks/pnfsimulator/src/main/resources/logback.xml +++ b/test/mocks/pnfsimulator/pnfsimulator/src/main/resources/logback.xml @@ -1,4 +1,24 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + <Configuration complete="true" compact="true"> <Property name="outputFilename" value="pnfsimulator_output"/> diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/event/EventDataServiceTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/event/EventDataServiceTest.java new file mode 100644 index 000000000..5ed51cc34 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/event/EventDataServiceTest.java @@ -0,0 +1,133 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.event; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.hamcrest.collection.IsIterableContainingInOrder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +public class EventDataServiceTest { + + @Mock + private EventDataRepository repositoryMock; + + @InjectMocks + private EventDataService service; + + private static EventData sampleEventData(String id, String template, + String patched, String input, String keywords) { + return EventData.builder() + .id(id) + .template(template) + .patched(patched) + .input(input) + .keywords(keywords) + .build(); + } + + @BeforeEach + void resetMocks() { + initMocks(this); + } + + @Test + void persistEventDataJsonObjectTest() { + JsonParser parser = new JsonParser(); + JsonObject template = parser.parse("{ \"bla1\": \"bla2\"}").getAsJsonObject(); + JsonObject patched = parser.parse("{ \"bla3\": \"bla4\"}").getAsJsonObject(); + JsonObject input = parser.parse("{ \"bla5\": \"bla6\"}").getAsJsonObject(); + JsonObject keywords = parser.parse("{ \"bla7\": \"bla8\"}").getAsJsonObject(); + ArgumentCaptor<EventData> argumentCaptor = ArgumentCaptor.forClass(EventData.class); + + service.persistEventData(template, patched, input, keywords); + + verify(repositoryMock).save(argumentCaptor.capture()); + EventData captured = argumentCaptor.getValue(); + + assertEquals(captured.getTemplate(), template.toString()); + assertEquals(captured.getPatched(), patched.toString()); + assertEquals(captured.getInput(), input.toString()); + assertEquals(captured.getKeywords(), keywords.toString()); + } + + @Test + void getAllEventsTest() { + + List<EventData> eventDataList = new ArrayList<>(); + EventData ed1 = sampleEventData("id1", "t1", "p1", "i1", "k1"); + EventData ed2 = sampleEventData("id2", "t2", "p2", "i2", "k2"); + eventDataList.add(ed1); + eventDataList.add(ed2); + + when(repositoryMock.findAll()).thenReturn(eventDataList); + List<EventData> actualList = service.getAllEvents(); + + assertEquals(eventDataList.size(), actualList.size()); + assertThat(actualList, IsIterableContainingInOrder.contains(ed1, ed2)); + } + + @Test + void findByIdPresentTest() { + String id = "some_object"; + EventData eventData = sampleEventData(id, "template", "patched", "input", "keywords"); + Optional<EventData> optional = Optional.of(eventData); + + when(repositoryMock.findById(id)).thenReturn(optional); + + Optional<EventData> actualOptional = service.getById(id); + assertTrue(actualOptional.isPresent()); + EventData actualObject = actualOptional.get(); + assertEquals(eventData.getId(), actualObject.getId()); + assertEquals(eventData.getTemplate(), actualObject.getTemplate()); + assertEquals(eventData.getPatched(), actualObject.getPatched()); + assertEquals(eventData.getInput(), actualObject.getInput()); + assertEquals(eventData.getKeywords(), actualObject.getKeywords()); + + } + + @Test + void findByIdNotPresentTest() { + String id = "some_object"; + Optional<EventData> optional = Optional.empty(); + + when(repositoryMock.findById(id)).thenReturn(optional); + + Optional<EventData> actualOptional = service.getById(id); + assertTrue(!actualOptional.isPresent()); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/filesystem/InMemoryTemplateStorage.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/filesystem/InMemoryTemplateStorage.java new file mode 100644 index 000000000..98c4bc51c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/filesystem/InMemoryTemplateStorage.java @@ -0,0 +1,71 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.filesystem; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import com.google.gson.JsonObject; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.template.Template; + +public class InMemoryTemplateStorage implements Storage<Template> { + + private List<Template> storage = new ArrayList<>(); + + @Override + public List<Template> getAll() { + return new ArrayList<>(storage); + } + + @Override + public Optional<Template> get(String name) { + return storage.stream().filter(template -> template.getId().equals(name)).findFirst(); + } + + @Override + public void persist(Template template) { + if (!storage.contains(template)){ + storage.add(template); + } + } + + @Override + public boolean tryPersistOrOverwrite(Template template, boolean overwrite) { + if (!storage.contains(template) || overwrite){ + storage.add(template); + return true; + } + return false; + } + + @Override + public void delete(String templateName) { + get(templateName).ifPresent(template -> storage.remove(template)); + } + + @Override + public List<String> getIdsByContentCriteria(JsonObject queryJson) { + throw new RuntimeException("Method is not implemented."); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessorTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessorTest.java new file mode 100644 index 000000000..42ed4d397 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/filesystem/WatcherEventProcessorTest.java @@ -0,0 +1,124 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.filesystem; + +import static junit.framework.TestCase.fail; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.time.Instant; +import java.util.Collections; +import java.util.HashMap; +import java.util.Optional; +import org.bson.Document; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.template.Template; + +class WatcherEventProcessorTest { + + @Mock + private WatchEvent watchEvent; + @Mock + private Path templatesDir; + + private Storage<Template> storage; + private static Path jsonFilePath; + + @BeforeAll + static void init() { + jsonFilePath = Paths.get("src/test/resources/org/onap/pnfsimulator/simulator/filesystem/test1.json"); + } + + @BeforeEach + void resetMocks() { + initMocks(this); + storage = new InMemoryTemplateStorage(); + initStubs(); + } + + @Test + void shouldProcessCreatedEventTest() { + // when + Mockito.when(watchEvent.kind()).thenReturn(StandardWatchEventKinds.ENTRY_CREATE); + WatcherEventProcessor.process(watchEvent, storage, templatesDir); + // then + verifyPersistedValue(); + } + + @Test + void shouldProcessModifiedEventTest() { + //given + storage.persist(new Template("test1.json", new Document(Collections.emptyMap()), Instant.now().getNano())); + // when + Mockito.when(watchEvent.kind()).thenReturn(StandardWatchEventKinds.ENTRY_MODIFY); + WatcherEventProcessor.process(watchEvent, storage, templatesDir); + // then + verifyPersistedValue(); + } + + private void verifyPersistedValue() { + Assertions.assertEquals(storage.getAll().size(), 1); + Optional<Template> templateFromStorage = storage.get("test1.json"); + if (templateFromStorage.isPresent()) { + Template retrievedTemplate = templateFromStorage.get(); + Document templateContent = retrievedTemplate.getContent(); + Document flatContent = retrievedTemplate.getFlatContent(); + Assertions.assertEquals(templateContent.getString("field1"), "value1"); + Assertions.assertEquals(templateContent.getInteger("field2", 0), 2); + Assertions.assertEquals(flatContent.getInteger(":nested:key1[0]", 0), 1); + Assertions.assertEquals(flatContent.getInteger(":nested:key1[1]", 0), 2); + Assertions.assertEquals(flatContent.getInteger(":nested:key1[2]", 0), 3); + Assertions.assertEquals(flatContent.getString(":nested:key2"), "sampleValue2"); + } else { + fail(); + } + } + + @Test + void shouldProcessDeletedEventTest() { + //given + HashMap<String, Object> legacyObject = new HashMap<>(); + legacyObject.put("field1", "value1"); + legacyObject.put("field2", 2); + + storage.persist(new Template("test1.json", new Document(legacyObject), Instant.now().getNano())); + // when + Mockito.when(watchEvent.kind()).thenReturn(StandardWatchEventKinds.ENTRY_DELETE); + WatcherEventProcessor.process(watchEvent, storage, templatesDir); + // then + Assertions.assertEquals(storage.getAll().size(), 0); + } + + private void initStubs() { + Mockito.when(templatesDir.resolve(jsonFilePath)).thenReturn(jsonFilePath); + Mockito.when(watchEvent.context()).thenReturn(jsonFilePath); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java new file mode 100644 index 000000000..36e8e6609 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java @@ -0,0 +1,211 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.onap.pnfsimulator.rest.model.FullEvent; +import org.onap.pnfsimulator.rest.model.SimulatorParams; +import org.onap.pnfsimulator.rest.model.SimulatorRequest; +import org.onap.pnfsimulator.rest.util.JsonObjectDeserializer; +import org.onap.pnfsimulator.simulator.SimulatorService; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfig; +import org.quartz.SchedulerException; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import java.io.IOException; +import java.net.URL; + +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +class SimulatorControllerTest { + + private static final String START_ENDPOINT = "/simulator/start"; + private static final String CONFIG_ENDPOINT = "/simulator/config"; + private static final String EVENT_ENDPOINT = "/simulator/event"; + private static final String JSON_MSG_EXPRESSION = "$.message"; + + private static final String NEW_URL = "http://0.0.0.0:8090/eventListener/v7"; + private static final String UPDATE_SIM_CONFIG_VALID_JSON = "{\"vesServerUrl\": \"" + NEW_URL + "\"}"; + private static final String SAMPLE_ID = "sampleId"; + private static final Gson GSON_OBJ = new Gson(); + private static String simulatorRequestBody; + private MockMvc mockMvc; + @InjectMocks + private SimulatorController controller; + @Mock + private SimulatorService simulatorService; + + @BeforeAll + static void beforeAll() { + SimulatorParams simulatorParams = new SimulatorParams("http://0.0.0.0:8080", 1, 1); + SimulatorRequest simulatorRequest = new SimulatorRequest(simulatorParams, + "testTemplate.json", new JsonObject()); + + simulatorRequestBody = GSON_OBJ.toJson(simulatorRequest); + } + + @BeforeEach + void setup() throws IOException, SchedulerException { + MockitoAnnotations.initMocks(this); + when(simulatorService.triggerEvent(any())).thenReturn("jobName"); + mockMvc = MockMvcBuilders + .standaloneSetup(controller) + .build(); + } + + @Test + void shouldStartSimulatorProperly() throws Exception { + startSimulator(); + SimulatorRequest simulatorRequest = new Gson().fromJson(simulatorRequestBody, SimulatorRequest.class); + + verify(simulatorService).triggerEvent(eq(simulatorRequest)); + } + + @Test + void testShouldGetConfigurationWhenRequested() throws Exception { + String newUrl = "http://localhost:8090/eventListener/v7"; + SimulatorConfig expectedConfig = new SimulatorConfig(SAMPLE_ID, new URL(newUrl)); + when(simulatorService.getConfiguration()).thenReturn(expectedConfig); + + MvcResult getResult = mockMvc + .perform(get(CONFIG_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON) + .content(UPDATE_SIM_CONFIG_VALID_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + String expectedVesUrlJsonPart = createStringReprOfJson("vesServerUrl", newUrl); + assertThat(getResult.getResponse().getContentAsString()).contains(expectedVesUrlJsonPart); + } + + @Test + void testShouldSuccessfullyUpdateConfigurationWithNewVesUrl() throws Exception { + String oldUrl = "http://localhost:8090/eventListener/v7"; + SimulatorConfig expectedConfigBeforeUpdate = new SimulatorConfig(SAMPLE_ID, new URL(oldUrl)); + SimulatorConfig expectedConfigAfterUpdate = new SimulatorConfig(SAMPLE_ID, new URL(NEW_URL)); + + when(simulatorService.getConfiguration()).thenReturn(expectedConfigBeforeUpdate); + when(simulatorService.updateConfiguration(any(SimulatorConfig.class))).thenReturn(expectedConfigAfterUpdate); + + MvcResult postResult = mockMvc + .perform(put(CONFIG_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON) + .content(UPDATE_SIM_CONFIG_VALID_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + String expectedVesUrlJsonPart = createStringReprOfJson("vesServerUrl", expectedConfigAfterUpdate.getVesServerUrl().toString()); + assertThat(postResult.getResponse().getContentAsString()).contains(expectedVesUrlJsonPart); + } + + @Test + void testShouldRaiseExceptionWhenUpdateConfigWithIncorrectPayloadWasSent() throws Exception { + mockMvc + .perform(put(CONFIG_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"vesUrl\": \"" + NEW_URL + "\"}")) + .andExpect(status().isBadRequest()); + } + + @Test + void testShouldRaiseExceptionWhenUrlInInvalidFormatIsSent() throws Exception { + mockMvc + .perform(put(CONFIG_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"vesUrl\": \"http://0.0.0.0:VES-PORT/eventListener/v7\"}")) + .andExpect(status().isBadRequest()); + } + + @Test + void testShouldSendEventDirectly() throws Exception { + String contentAsString = mockMvc + .perform(post(EVENT_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE) + .content("{\"vesServerUrl\":\"http://0.0.0.0:8080/simulator/v7\",\n" + + " \"event\":{ \n" + + " \"commonEventHeader\":{ \n" + + " \"domain\":\"notification\",\n" + + " \"eventName\":\"vFirewallBroadcastPackets\"\n" + + " },\n" + + " \"notificationFields\":{ \n" + + " \"arrayOfNamedHashMap\":[ \n" + + " { \n" + + " \"name\":\"A20161221.1031-1041.bin.gz\",\n" + + " \"hashMap\":{ \n" + + " \"fileformatType\":\"org.3GPP.32.435#measCollec\"}}]}}}")) + .andExpect(status().isAccepted()).andReturn().getResponse().getContentAsString(); + assertThat(contentAsString).contains("One-time direct event sent successfully"); + } + + @Test + void testShouldReplaceKeywordsAndSendEventDirectly() throws Exception { + String contentAsString = mockMvc + .perform(post(EVENT_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE) + .content("{\"vesServerUrl\": \"http://localhost:9999/eventListener\",\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"eventId\": \"#RandomString(20)\",\n" + + " \"sourceName\": \"PATCHED_sourceName\",\n" + + " \"version\": 3.0\n}}}")) + .andExpect(status().isAccepted()).andReturn().getResponse().getContentAsString(); + assertThat(contentAsString).contains("One-time direct event sent successfully"); + + verify(simulatorService, Mockito.times(1)).triggerOneTimeEvent(any(FullEvent.class)); + } + + + private void startSimulator() throws Exception { + mockMvc + .perform(post(START_ENDPOINT) + .content(simulatorRequestBody) + .contentType(MediaType.APPLICATION_JSON).characterEncoding("utf-8")) + .andExpect(status().isOk()) + .andExpect(jsonPath(JSON_MSG_EXPRESSION).value("Request started")); + + } + + private String createStringReprOfJson(String key, String value) { + return GSON_OBJ.toJson(ImmutableMap.of(key, value)); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/TemplateControllerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/TemplateControllerTest.java new file mode 100644 index 000000000..f34d73cd9 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/TemplateControllerTest.java @@ -0,0 +1,256 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.rest; + +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.onap.pnfsimulator.rest.TemplateController.CANNOT_OVERRIDE_TEMPLATE_MSG; +import static org.onap.pnfsimulator.rest.TemplateController.TEMPLATE_NOT_FOUND_MSG; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.assertj.core.util.Lists; +import org.bson.Document; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import static org.mockito.Mockito.times; +import org.mockito.MockitoAnnotations; +import org.onap.pnfsimulator.db.Storage; +import org.onap.pnfsimulator.rest.model.SearchExp; +import org.onap.pnfsimulator.template.Template; +import org.onap.pnfsimulator.template.search.IllegalJsonValueException; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +class TemplateControllerTest { + + private static final String LIST_URL = "/template/list"; + private static final String GET_FORMAT_STR = "/template/get/%s"; + private static final String SEARCH_ENDPOINT = "/template/search"; + private static final String UPLOAD_URL_NOFORCE = "/template/upload"; + private static final String UPLOAD_URL_FORCE = "/template/upload?override=true"; + private static final String SAMPLE_TEMPLATE_JSON = "{\"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"measurementsForVfScaling\",\n" + + " \"eventName\": \"vFirewallBroadcastPackets\",\n" + + " }" + + "}}"; + + public static final String TEMPLATE_REQUEST = "{\n" + + " \"name\": \"someTemplate\",\n" + + " \"template\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"notification\",\n" + + " \"eventName\": \"vFirewallBroadcastPackets\"\n" + + " },\n" + + " \"notificationFields\": {\n" + + " \"arrayOfNamedHashMap\": [{\n" + + " \"name\": \"A20161221.1031-1041.bin.gz\",\n" + + "\n" + + " \"hashMap\": {\n" + + " \"fileformatType\": \"org.3GPP.32.435#measCollec\"\n" + + " }\n" + + " }]\n" + + " }\n" + + " }\n" + + "}"; + private static final Document SAMPLE_TEMPLATE_BSON = Document.parse(SAMPLE_TEMPLATE_JSON); + private static final List<String> SAMPLE_TEMPLATE_NAME_LIST = Lists.newArrayList("notification.json", "registration.json"); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private static final Gson GSON_OBJ = new GsonBuilder().create(); + private MockMvc mockMvc; + + @Mock + private Storage<Template> templateService; + @InjectMocks + private TemplateController controller; + + @BeforeEach + void setup() { + MockitoAnnotations.initMocks(this); + mockMvc = MockMvcBuilders + .standaloneSetup(controller) + .build(); + } + + @Test + void shouldGetAllTemplates() throws Exception { + List<Template> templateList = createTemplatesList(); + when(templateService.getAll()).thenReturn(templateList); + + MvcResult getResult = mockMvc + .perform(get(LIST_URL) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andReturn(); + + Type listType = new TypeToken<ArrayList<Template>>() {}.getType(); + List<Template> resultList = GSON_OBJ.fromJson(getResult.getResponse().getContentAsString(), listType); + assertThat(resultList).containsExactlyInAnyOrderElementsOf(templateList); + } + + @Test + void shouldListEmptyCollectionWhenNoTemplatesAvailable() throws Exception { + List<Template> templateList = Collections.emptyList(); + when(templateService.getAll()).thenReturn(templateList); + + MvcResult getResult = mockMvc + .perform(get(LIST_URL)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andReturn(); + + String templatesAsString = GSON_OBJ.toJson(templateList); + assertThat(getResult.getResponse().getContentAsString()).containsSequence(templatesAsString); + } + + @Test + void shouldSuccessfullyGetExisitngTemplateByName() throws Exception { + String sampleTemplateName = "someTemplate"; + String requestUrl = String.format(GET_FORMAT_STR, sampleTemplateName); + Template sampleTemplate = new Template(sampleTemplateName, SAMPLE_TEMPLATE_BSON, 0L); + + when(templateService.get(sampleTemplateName)).thenReturn(Optional.of(sampleTemplate)); + + MvcResult getResult = mockMvc + .perform(get(requestUrl)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andReturn(); + + Template result = new Gson().fromJson(getResult.getResponse().getContentAsString(), Template.class); + assertThat(result).isEqualTo(sampleTemplate); + } + + @Test + void shouldReturnNotFoundWhenGetNonExisitngTemplateByName() throws Exception { + String sampleTemplateName = "doesNotExist"; + String requestUrl = String.format(GET_FORMAT_STR, sampleTemplateName); + + when(templateService.get(sampleTemplateName)).thenReturn(Optional.empty()); + + MvcResult getResult = mockMvc + .perform(get(requestUrl)) + .andExpect(status().isNotFound()) + .andExpect(content().contentType(MediaType.TEXT_PLAIN_VALUE)) + .andReturn(); + + assertThat(getResult.getResponse().getContentLength()).isEqualTo(TEMPLATE_NOT_FOUND_MSG.length()); + } + + + @Test + void shouldReturnNamesOfTemplatesThatSatisfyGivenCriteria() throws Exception { + when(templateService.getIdsByContentCriteria(any(JsonObject.class))).thenReturn(SAMPLE_TEMPLATE_NAME_LIST); + SearchExp expr = new SearchExp(new JsonObject()); + + String responseContent = mockMvc + .perform(post(SEARCH_ENDPOINT).content(GSON_OBJ.toJson(expr)).contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andReturn().getResponse().getContentAsString(); + + List<String> actualTemplates = OBJECT_MAPPER.readValue(responseContent, new TypeReference<List<String>>() {}); + verify(templateService, times(1)).getIdsByContentCriteria(any(JsonObject.class)); + assertThat(actualTemplates).isEqualTo(SAMPLE_TEMPLATE_NAME_LIST); + } + + @Test + void shouldRaiseBadRequestWhenNullValueProvidedInSearchJsonAsJsonValue() throws Exception { + when(templateService.getIdsByContentCriteria(any(JsonObject.class))).thenThrow(IllegalJsonValueException.class); + SearchExp expr = new SearchExp(new JsonObject()); + + mockMvc.perform(post(SEARCH_ENDPOINT) + .content(GSON_OBJ.toJson(expr)) + .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(status().isBadRequest()); + } + + + @Test + void testTryUploadNewTemplate() throws Exception { + when(templateService.tryPersistOrOverwrite(any(Template.class), eq(false))).thenReturn(true); + + MvcResult postResult = mockMvc + .perform(post(UPLOAD_URL_NOFORCE) + .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE) + .content(TEMPLATE_REQUEST)) + .andExpect(status().isCreated()) + .andReturn(); + } + + @Test + void testTryUploadNewTemplateWithForce() throws Exception { + when(templateService.tryPersistOrOverwrite(any(Template.class), eq(true))).thenReturn(true); + + MvcResult postResult = mockMvc + .perform(post(UPLOAD_URL_FORCE) + .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE) + .content(TEMPLATE_REQUEST)) + .andExpect(status().isCreated()) + .andReturn(); + } + + @Test + void testOverrideExistingTemplateWithoutForceShouldFail() throws Exception { + when(templateService.tryPersistOrOverwrite(any(Template.class), eq(true))).thenReturn(false); + + MvcResult postResult = mockMvc + .perform(post(UPLOAD_URL_FORCE) + .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE) + .content(TEMPLATE_REQUEST)) + .andExpect(status().isConflict()) + .andReturn(); + + assertThat(postResult.getResponse().getContentAsString()).isEqualTo(CANNOT_OVERRIDE_TEMPLATE_MSG); + } + + private List<Template> createTemplatesList() { + return Arrays.asList( + new Template("1", SAMPLE_TEMPLATE_BSON, 0L), + new Template("2", SAMPLE_TEMPLATE_BSON, 0L), + new Template("3", SAMPLE_TEMPLATE_BSON, 0L)); + } +} diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/util/DateUtilTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/util/DateUtilTest.java index 99b9af7ec..1591a59be 100644 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/util/DateUtilTest.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/util/DateUtilTest.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,4 +35,4 @@ class DateUtilTest { assertEquals(expectedResult, DateUtil.getTimestamp(new SimpleDateFormat("yyyy"))); } -}
\ No newline at end of file +} diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/util/ResponseBuilderTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/util/ResponseBuilderTest.java index 59e1e3b4f..0d62ee925 100644 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/util/ResponseBuilderTest.java +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/util/ResponseBuilderTest.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * PNF-REGISTRATION-HANDLER * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. + * Copyright (C) 2018 Nokia. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -public class ResponseBuilderTest { +class ResponseBuilderTest { private static final HttpStatus SAMPLE_STATUS = HttpStatus.OK; @@ -62,4 +62,4 @@ public class ResponseBuilderTest { } -}
\ No newline at end of file +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/IncrementProviderImplTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/IncrementProviderImplTest.java new file mode 100644 index 000000000..53f02da0e --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/IncrementProviderImplTest.java @@ -0,0 +1,78 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.onap.pnfsimulator.event.EventData; +import org.onap.pnfsimulator.event.EventDataRepository; + +public class IncrementProviderImplTest { + private IncrementProvider incrementProvider; + + @Mock + private EventDataRepository eventDataRepositoryMock; + + @BeforeEach + void setUp() { + eventDataRepositoryMock = mock(EventDataRepository.class); + incrementProvider = new IncrementProviderImpl(eventDataRepositoryMock); + } + + @Test + public void getAndIncrementTest() { + ArgumentCaptor<EventData> eventDataArgumentCaptor = ArgumentCaptor.forClass(EventData.class); + String eventId = "1"; + int initialIncrementValue = 0; + int expectedValue = initialIncrementValue + 1; + EventData eventData = EventData.builder().id(eventId).incrementValue(initialIncrementValue).build(); + Optional<EventData> optional = Optional.of(eventData); + + when(eventDataRepositoryMock.findById(eventId)).thenReturn(optional); + + int value = incrementProvider.getAndIncrement(eventId); + + verify(eventDataRepositoryMock).save(eventDataArgumentCaptor.capture()); + + assertThat(value).isEqualTo(expectedValue); + assertThat(eventDataArgumentCaptor.getValue().getIncrementValue()).isEqualTo(expectedValue); + + } + + @Test + public void shouldThrowOnNonExistingEvent() { + Optional<EventData> emptyOptional = Optional.empty(); + String nonExistingEventId = "THIS_DOES_NOT_EXIST"; + when(eventDataRepositoryMock.findById(nonExistingEventId)).thenReturn(emptyOptional); + + assertThrows(EventNotFoundException.class, + () -> incrementProvider.getAndIncrement(nonExistingEventId)); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidRandomIntegerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidRandomIntegerTest.java new file mode 100644 index 000000000..8198e95a9 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidRandomIntegerTest.java @@ -0,0 +1,67 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class KeywordsExtractorInvalidRandomIntegerTest { + + private final String keyword; + private KeywordsExtractor keywordsExtractor; + + private static final Collection INVALID_INTEGER_KEYWORDS = Arrays.asList(new Object[][]{ + {"#RandoInteger"}, + {"#Randominteger(23,11)"}, + {"#randomInteger(11,34)"}, + {"#Random_Integer(11,13)"}, + {"#RandomInteger(11)"}, + {"RandomInteger(11)"}, + {"RandomInteger"} + }); + + public KeywordsExtractorInvalidRandomIntegerTest(String keyword) { + this.keyword = keyword; + } + + @Before + public void setUp() { + this.keywordsExtractor = new KeywordsExtractor(); + } + + @Parameterized.Parameters + public static Collection data() { + return INVALID_INTEGER_KEYWORDS; + } + + @Test + public void checkValidRandomStringKeyword() { + assertEquals(keywordsExtractor.substituteStringKeyword(this.keyword, 1), this.keyword); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidRandomStringTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidRandomStringTest.java new file mode 100644 index 000000000..6834c0dc6 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidRandomStringTest.java @@ -0,0 +1,67 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class KeywordsExtractorInvalidRandomStringTest { + + private final String keyword; + private KeywordsExtractor keywordsExtractor; + + private static final Collection INVALID_STRING_KEYWORDS = Arrays.asList(new Object[][]{ + {"#RandoString"}, + {"#Randomstring(23)"}, + {"#randomString(11)"}, + {"#Random_String(11)"}, + {"#RandomString(11,10)"}, + {"RandomString(11)"}, + {"RandomString"} + }); + + public KeywordsExtractorInvalidRandomStringTest(String keyword) { + this.keyword = keyword; + } + + @Before + public void setUp() { + this.keywordsExtractor = new KeywordsExtractor(); + } + + @Parameterized.Parameters + public static Collection data() { + return INVALID_STRING_KEYWORDS; + } + + @Test + public void checkValidRandomStringKeyword() { + assertEquals(keywordsExtractor.substituteStringKeyword(this.keyword, 1).length(), this.keyword.length()); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidTimestampTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidTimestampTest.java new file mode 100644 index 000000000..eda40707b --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorInvalidTimestampTest.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class KeywordsExtractorInvalidTimestampTest { + + private final String keyword; + private KeywordsExtractor keywordsExtractor; + + private static final Collection INVALID_TIMESTAMP_KEYWORDS = Arrays.asList(new Object[][]{ + {"#Timesamp"}, + {"#Timestamp(10)"}, + {"#timestamp"}, + {"#Timestamp(11,13)"}, + {"Timestamp"} + }); + + public KeywordsExtractorInvalidTimestampTest(String keyword) { + this.keyword = keyword; + } + + @Before + public void setUp() { + this.keywordsExtractor = new KeywordsExtractor(); + } + + @Parameterized.Parameters + public static Collection data() { + return INVALID_TIMESTAMP_KEYWORDS; + } + + @Test + public void checkValidRandomStringKeyword() { + assertEquals(keywordsExtractor.substituteStringKeyword(this.keyword, 1), this.keyword); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomIntegerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomIntegerTest.java new file mode 100644 index 000000000..be79488b5 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomIntegerTest.java @@ -0,0 +1,66 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class KeywordsExtractorValidRandomIntegerTest { + + private final String keyword; + private final String shouldParseTo; + private KeywordsExtractor keywordsExtractor; + + private static final Collection VALID_INTEGER_KEYWORDS = Arrays.asList(new Object[][]{ + {"#RandomInteger(23,23)", "23"}, + {"#RandomInteger(6, 6)12", "612"}, + {"1#RandomInteger(11,11)", "111"}, + {"1#RandomInteger(11,11)2", "1112"} + }); + + public KeywordsExtractorValidRandomIntegerTest(String keyword, String shouldParseTo) { + this.keyword = keyword; + this.shouldParseTo = shouldParseTo; + } + + @Before + public void setUp() { + this.keywordsExtractor = new KeywordsExtractor(); + } + + @Parameterized.Parameters + public static Collection data() { + return VALID_INTEGER_KEYWORDS; + } + + @Test + public void checkValidRandomStringKeyword() { + assertEquals(keywordsExtractor.substituteStringKeyword(this.keyword, 1), this.shouldParseTo); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomPrimitiveIntegerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomPrimitiveIntegerTest.java new file mode 100644 index 000000000..fd72a5145 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomPrimitiveIntegerTest.java @@ -0,0 +1,66 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class KeywordsExtractorValidRandomPrimitiveIntegerTest { + + private final String keyword; + private final Integer shouldParseTo; + private KeywordsExtractor keywordsExtractor; + + private static final Collection VALID_INTEGER_KEYWORDS = Arrays.asList(new Object[][]{ + {"#RandomPrimitiveInteger(23,23)", 23}, + {"#RandomPrimitiveInteger(6, 6)12", 6}, + {"1#RandomPrimitiveInteger(11,11)", 11}, + {"1#RandomPrimitiveInteger(11,11)2", 11} + }); + + public KeywordsExtractorValidRandomPrimitiveIntegerTest(String keyword, Integer shouldParseTo) { + this.keyword = keyword; + this.shouldParseTo = shouldParseTo; + } + + @Before + public void setUp() { + this.keywordsExtractor = new KeywordsExtractor(); + } + + @Parameterized.Parameters + public static Collection data() { + return VALID_INTEGER_KEYWORDS; + } + + @Test + public void checkValidRandomStringKeyword() { + assertEquals(keywordsExtractor.substitutePrimitiveKeyword(this.keyword), this.shouldParseTo); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomStringTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomStringTest.java new file mode 100644 index 000000000..f0fdc0ff3 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidRandomStringTest.java @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.DEFAULT_STRING_LENGTH; + +import java.util.Arrays; +import java.util.Collection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class KeywordsExtractorValidRandomStringTest { + + private final String keyword; + private final int length; + private KeywordsExtractor keywordsExtractor; + + private static final Collection VALID_STRING_KEYWORDS = Arrays.asList(new Object[][]{ + {"#RandomString", DEFAULT_STRING_LENGTH}, + {"1#RandomString2", 1 + DEFAULT_STRING_LENGTH + 1}, + {"#RandomString(23)", 23}, + {"#RandomString(11)12", 11 + 2}, + {"1#RandomString(11)", 1 + 11}, + {"1#RandomString(11)2", 1 + 11 + 1} + }); + + public KeywordsExtractorValidRandomStringTest(String keyword, int length) { + this.keyword = keyword; + this.length = length; + } + + @Before + public void setUp() { + this.keywordsExtractor = new KeywordsExtractor(); + } + + @Parameterized.Parameters + public static Collection data() { + return VALID_STRING_KEYWORDS; + } + + @Test + public void checkValidRandomStringKeyword() { + assertEquals(keywordsExtractor.substituteStringKeyword(this.keyword, 1).length(), this.length); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidTimestampPrimitiveTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidTimestampPrimitiveTest.java new file mode 100644 index 000000000..7743e5558 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidTimestampPrimitiveTest.java @@ -0,0 +1,66 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.time.Instant; +import java.util.Arrays; +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(Parameterized.class) +public class KeywordsExtractorValidTimestampPrimitiveTest { + private final String keyword; + private KeywordsExtractor keywordsExtractor; + + private static final Collection VALID_TIMESTAMP_KEYWORDS = Arrays.asList(new Object[][]{ + {"#TimestampPrimitive"} + }); + + public KeywordsExtractorValidTimestampPrimitiveTest(String keyword) { + this.keyword = keyword; + } + + @Before + public void setUp() { + this.keywordsExtractor = new KeywordsExtractor(); + } + + @Parameterized.Parameters + public static Collection data() { + return VALID_TIMESTAMP_KEYWORDS; + } + + @Test + public void checkValidRandomStringKeyword() { + long currentTimestamp = Instant.now().getEpochSecond(); + Long timestamp = keywordsExtractor.substitutePrimitiveKeyword(this.keyword); + long afterExecution = Instant.now().getEpochSecond(); + + assertThat(timestamp).isBetween(currentTimestamp, afterExecution); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidTimestampTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidTimestampTest.java new file mode 100644 index 000000000..f5c12c311 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsExtractorValidTimestampTest.java @@ -0,0 +1,67 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.Collection; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(Parameterized.class) +public class KeywordsExtractorValidTimestampTest { + + private final String keyword; + private final int length; + private KeywordsExtractor keywordsExtractor; + + private static final Collection VALID_TIMESTAMP_KEYWORDS = Arrays.asList(new Object[][]{ + {"#Timestamp", 10}, + {"#Timestamp12", 10 + 2}, + {"1#Timestamp", 1 + 10}, + {"1#Timestamp2", 1 + 10 +1} + }); + + public KeywordsExtractorValidTimestampTest(String keyword, Integer length) { + this.keyword = keyword; + this.length = length; + } + + @Before + public void setUp() { + this.keywordsExtractor = new KeywordsExtractor(); + } + + @Parameterized.Parameters + public static Collection data() { + return VALID_TIMESTAMP_KEYWORDS; + } + + @Test + public void checkValidRandomStringKeyword() { + String substitution = keywordsExtractor.substituteStringKeyword(this.keyword, 1); + assertEquals(substitution.length(), this.length); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsHandlerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsHandlerTest.java new file mode 100644 index 000000000..e67d4a33b --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsHandlerTest.java @@ -0,0 +1,304 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.DEFAULT_STRING_LENGTH; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Queue; +import org.junit.jupiter.api.Test; + +class KeywordsHandlerTest { + + private static final String TEMPLATE_JSON = "{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"#RandomString\"\n" + + " },\n" + + " \"measurementsForVfScalingFields\": {\n" + + " \"measurementsForVfSclaingFieldsVersion\": 2.0,\n" + + " \"additionalMeasurements\": {\n" + + " \"name\": \"licenseUsage\",\n" + + " \"extraFields\": {\n" + + " \"name\": \"#RandomString(4)\",\n" + + " \"value\": \"1\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + private static final String TEMPLATE_JSON_WITH_MANY_KEYWORDS_INSIDE_SINGLE_VALUE = "{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain1\": \"#RandomString(1) #RandomString(2) #RandomString(3)\",\n" + + " \"domain2\": \"1 #RandomString(1) 2\"\n" + + " },\n" + + " \"measurementsForVfScalingFields\": {\n" + + " \"measurementsForVfSclaingFieldsVersion\": 2.0,\n" + + " \"additionalMeasurements\": {\n" + + " \"name\": \"licenseUsage\",\n" + + " \"extraFields\": {\n" + + " \"value\": \"1\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + private static final String TEMPLATE_JSON_WITH_ARRAY = "{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"#RandomString(1)\",\n" + + " \"version\": 2.0\n" + + " },\n" + + " \"measurementsForVfScalingFields\": {\n" + + " \"additionalMeasurements\": [\n" + + " {\n" + + " \"name\": \"licenseUsage\",\n" + + " \"arrayOfFields\": [\n" + + " {\n" + + " \"name\": \"G711AudioPort\",\n" + + " \"value\": \"1\"\n" + + " },\n" + + " {\n" + + " \"name\": [\"1\",\"2\"],\n" + + " \"value\": \"#RandomString(2)\"\n" + + " },\n" + + " {\n" + + " \"name\": \"G722AudioPort\",\n" + + " \"value\": \"1\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + + private static final String TEMPLATE_ONE_INCREMENT_JSON = "{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"#RandomString\"\n" + + " },\n" + + " \"measurementsForVfScalingFields\": {\n" + + " \"measurementsForVfSclaingFieldsVersion\": 2.0,\n" + + " \"additionalMeasurements\": {\n" + + " \"name\": \"licenseUsage\",\n" + + " \"extraFields\": {\n" + + " \"name\": \"#RandomString(4)\",\n" + + " \"value\": \"#Increment\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + private static final String TEMPLATE_WITH_SIMPLE_VALUE= "\"#RandomString(4)\""; + + private static final String TEMPLATE_WITH_ARRAY_OF_PRIMITIVES = "[ 1, \"#RandomString(5)\", 3]"; + + private static final String TEMPLATE_TWO_INCREMENT_JSON = "{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"#RandomString\"\n" + + " },\n" + + " \"measurementsForVfScalingFields\": {\n" + + " \"measurementsForVfSclaingFieldsVersion\": 2.0,\n" + + " \"additionalMeasurements\": {\n" + + " \"name\": \"licenseUsage\",\n" + + " \"extraFields\": {\n" + + " \"name\": \"#RandomString(4)\",\n" + + " \"value\": \"#Increment\",\n" + + " \"otherValue\": \"#Increment\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + private Gson gson = new Gson(); + + @Test + void shouldReplaceRandomStringKeyword() { + // given + JsonObject templateJson = gson.fromJson(TEMPLATE_JSON, JsonObject.class); + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), (id) -> 1); + + // when + JsonObject resultJson = keywordsHandler.substituteKeywords(templateJson, "").getAsJsonObject(); + + // then + String extraFields = resultJson + .get("event").getAsJsonObject() + .get("measurementsForVfScalingFields").getAsJsonObject() + .get("additionalMeasurements").getAsJsonObject() + .get("extraFields").getAsJsonObject() + .get("name").getAsString(); + String newDomain = resultJson + .get("event").getAsJsonObject() + .get("commonEventHeader").getAsJsonObject() + .get("domain").getAsString(); + + assertThat(extraFields.length()).isEqualTo(4); + assertThat(newDomain.length()).isEqualTo(DEFAULT_STRING_LENGTH); + } + + @Test + void shouldReplaceRandomStringKeywordsInsideSingleValue() { + // given + JsonObject templateJson = gson.fromJson(TEMPLATE_JSON_WITH_MANY_KEYWORDS_INSIDE_SINGLE_VALUE, JsonObject.class); + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), (id) -> 1); + + // when + JsonObject resultJson = keywordsHandler.substituteKeywords(templateJson, "").getAsJsonObject(); + + // then + String newDomain1 = resultJson + .get("event").getAsJsonObject() + .get("commonEventHeader").getAsJsonObject() + .get("domain1").getAsString(); + String newDomain2 = resultJson + .get("event").getAsJsonObject() + .get("commonEventHeader").getAsJsonObject() + .get("domain2").getAsString(); + + assertThat(newDomain1.length()).isEqualTo(1+1+2+1+3); + assertThat(newDomain2.length()).isEqualTo(1+1+1+1+1); + } + + @Test + void shouldReplaceRandomStringKeywordInTeplateAsArrayWithPrimitves() { + // given + JsonElement templateJson = gson.fromJson(TEMPLATE_WITH_ARRAY_OF_PRIMITIVES, JsonElement.class); + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), (id) -> 1); + + // when + JsonElement resultJson = keywordsHandler.substituteKeywords(templateJson, ""); + assertThat(resultJson.getAsJsonArray().get(1).getAsString().length()).isEqualTo(5); + } + + @Test + void shouldReplaceRandomStringKeywordInTeplateAsSimpleValue() { + // given + JsonElement templateJson = gson.fromJson(TEMPLATE_WITH_SIMPLE_VALUE, JsonElement.class); + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), (id) -> 1); + + // when + JsonElement resultJson = keywordsHandler.substituteKeywords(templateJson, ""); + + // then + assertThat(resultJson.getAsString().length()).isEqualTo(4); + } + + @Test + void shouldReplaceRandomStringKeywordInTeplateWithJsonArray() { + // given + JsonElement templateJson = gson.fromJson(TEMPLATE_JSON_WITH_ARRAY, JsonElement.class); + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), (id) -> 1); + + // when + JsonObject resultJson = keywordsHandler.substituteKeywords(templateJson, "").getAsJsonObject(); + + // then + String actualValue = resultJson + .get("event").getAsJsonObject() + .get("measurementsForVfScalingFields").getAsJsonObject() + .get("additionalMeasurements").getAsJsonArray() + .get(0).getAsJsonObject() + .get("arrayOfFields").getAsJsonArray() + .get(1).getAsJsonObject() + .get("value").getAsString(); + String otherActualValue = resultJson + .get("event").getAsJsonObject() + .get("commonEventHeader").getAsJsonObject() + .get("domain").getAsString(); + + assertThat(otherActualValue.length()).isEqualTo(1); + assertThat(actualValue.length()).isEqualTo(2); + } + + @Test + void shouldReplaceOneIncrementKeyword() { + // given + final Integer newIncrementedValue = 2; + JsonObject templateJson = gson.fromJson(TEMPLATE_ONE_INCREMENT_JSON, JsonObject.class); + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), (id) -> newIncrementedValue); + + // when + JsonObject resultJson = keywordsHandler.substituteKeywords(templateJson, "some random id").getAsJsonObject(); + + // then + String actualValue = resultJson + .get("event").getAsJsonObject() + .get("measurementsForVfScalingFields").getAsJsonObject() + .get("additionalMeasurements").getAsJsonObject() + .get("extraFields").getAsJsonObject() + .get("value").getAsString(); + + assertThat(actualValue).isEqualTo(newIncrementedValue.toString()); + } + + @Test + void shouldReplaceTwoIncrementKeyword() { + // given + final Integer firstIncrementValue = 2; + final Integer secondIncrementValue = 3; + JsonObject templateJson = gson.fromJson(TEMPLATE_TWO_INCREMENT_JSON, JsonObject.class); + KeywordsHandler keywordsHandler = new KeywordsHandler(new KeywordsExtractor(), new IncrementProvider() { + Queue<Integer> sequenceOfValues = new LinkedList<>( + Arrays.asList(firstIncrementValue, secondIncrementValue)); + + @Override + public int getAndIncrement(String id) { + return sequenceOfValues.poll(); + } + }); + + // when + JsonObject resultJson = keywordsHandler.substituteKeywords(templateJson, "some random id").getAsJsonObject(); + resultJson = keywordsHandler.substituteKeywords(templateJson, "some random id").getAsJsonObject(); + + // then + String actualValue = resultJson + .get("event").getAsJsonObject() + .get("measurementsForVfScalingFields").getAsJsonObject() + .get("additionalMeasurements").getAsJsonObject() + .get("extraFields").getAsJsonObject() + .get("value").getAsString(); + + String actualOtherValue = resultJson + .get("event").getAsJsonObject() + .get("measurementsForVfScalingFields").getAsJsonObject() + .get("additionalMeasurements").getAsJsonObject() + .get("extraFields").getAsJsonObject() + .get("otherValue").getAsString(); + + assertThat(actualValue).isEqualTo(secondIncrementValue.toString()); + assertThat(actualOtherValue).isEqualTo(secondIncrementValue.toString()); + + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsValueProviderTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsValueProviderTest.java new file mode 100644 index 000000000..73e4c31df --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/KeywordsValueProviderTest.java @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.onap.pnfsimulator.simulator.KeywordsValueProvider.DEFAULT_STRING_LENGTH; + +import java.util.Random; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; + +class KeywordsValueProviderTest { + + @RepeatedTest(10) + void randomLimitedStringTest() { + String supplierResult = KeywordsValueProvider.getRandomLimitedString().apply(); + assertEquals(supplierResult.length(), DEFAULT_STRING_LENGTH); + } + + @RepeatedTest(10) + void randomStringTest() { + int length = new Random().nextInt(15) + 1; + String supplierResult = KeywordsValueProvider.getRandomString().apply(length); + assertEquals(supplierResult.length(), length); + } + + @RepeatedTest(10) + void randomIntegerTest(){ + int min = new Random().nextInt(10) + 1; + int max = new Random().nextInt(1000) + 20; + String supplierResult = KeywordsValueProvider.getRandomInteger().apply(min, max); + assertTrue(Integer.parseInt(supplierResult)>=min); + assertTrue(Integer.parseInt(supplierResult)<=max); + } + + @Test + void randomIntegerContainsMaximalAndMinimalValuesTest(){ + int anyNumber = new Random().nextInt(10) + 1; + String supplierResult = KeywordsValueProvider.getRandomInteger().apply(anyNumber, anyNumber); + assertEquals(Integer.parseInt(supplierResult), anyNumber); + } + + @Test + void randomIntegerFromNegativeRangeTest(){ + String supplierResult = KeywordsValueProvider.getRandomInteger().apply(-20, -20); + assertEquals(Integer.parseInt(supplierResult), -20); + } + + @RepeatedTest(10) + void randomIntegerFromParametersWithDifferentOrdersTest(){ + String supplierResult = KeywordsValueProvider.getRandomInteger().apply(-20, -10); + assertTrue(Integer.parseInt(supplierResult)>=-20); + assertTrue(Integer.parseInt(supplierResult)<=-10); + } + + @RepeatedTest(10) + void epochSecondGeneratedInCorrectFormatTest(){ + String supplierResult = KeywordsValueProvider.getEpochSecond().apply(); + assertEquals(supplierResult.length(), 10); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java new file mode 100644 index 000000000..32dd532aa --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorServiceTest.java @@ -0,0 +1,226 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.onap.pnfsimulator.event.EventData; +import org.onap.pnfsimulator.event.EventDataService; +import org.onap.pnfsimulator.rest.model.FullEvent; +import org.onap.pnfsimulator.rest.model.SimulatorParams; +import org.onap.pnfsimulator.rest.model.SimulatorRequest; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; +import org.onap.pnfsimulator.simulator.scheduler.EventScheduler; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfig; +import org.onap.pnfsimulator.simulatorconfig.SimulatorConfigService; +import org.quartz.SchedulerException; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.internal.verification.VerificationModeFactory.times; + +class SimulatorServiceTest { + + private static final String VES_URL = "http://0.0.0.0:8080"; + private static final Gson GSON = new Gson(); + private static final JsonObject VALID_PATCH = GSON.fromJson("{\"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"sourceName\": \"SomeCustomSource\"}}}\n", JsonObject.class); + private static JsonObject VALID_FULL_EVENT = GSON.fromJson("{\"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"notification\",\n" + + " \"eventName\": \"vFirewallBroadcastPackets\"\n" + + " },\n" + + " \"notificationFields\": {\n" + + " \"arrayOfNamedHashMap\": [{\n" + + " \"name\": \"A20161221.1031-1041.bin.gz\",\n" + + " \"hashMap\": {\n" + + " \"fileformatType\": \"org.3GPP.32.435#measCollec\"}}]}}}", JsonObject.class); + private static JsonObject FULL_EVENT_WITH_KEYWORDS = GSON.fromJson("{\"event\":{ \n" + + " \"commonEventHeader\":{ \n" + + " \"domain\":\"notification\",\n" + + " \"eventName\":\"#RandomString(20)\",\n" + + " \"eventOrderNo\":\"#Increment\"}}}", JsonObject.class); + private static final String SOME_CUSTOM_SOURCE = "SomeCustomSource"; + private static final String CLOSED_LOOP_VNF ="ClosedLoopVNF"; + private static final String SAMPLE_ID = "sampleId"; + private static final EventData SAMPLE_EVENT = EventData.builder().id("1").build(); + private final ArgumentCaptor<JsonObject> bodyCaptor = ArgumentCaptor.forClass(JsonObject.class); + private final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class); + private final ArgumentCaptor<Integer> repeatCountCaptor = ArgumentCaptor + .forClass(Integer.class); + private final ArgumentCaptor<String> templateNameCaptor = ArgumentCaptor.forClass(String.class); + private final ArgumentCaptor<String> eventIdCaptor = ArgumentCaptor.forClass(String.class); + private final ArgumentCaptor<String> vesUrlCaptor = ArgumentCaptor.forClass(String.class); + private final ArgumentCaptor<String> eventContentCaptor = ArgumentCaptor.forClass(String.class); + private SimulatorService simulatorService; + private EventDataService eventDataService; + private EventScheduler eventScheduler; + private SimulatorConfigService simulatorConfigService; + private static TemplatePatcher templatePatcher = new TemplatePatcher(); + private static TemplateReader templateReader = new FilesystemTemplateReader( + "src/test/resources/org/onap/pnfsimulator/simulator/", GSON); + + @BeforeEach + void setUp() { + eventDataService = mock(EventDataService.class); + eventScheduler = mock(EventScheduler.class); + simulatorConfigService = mock(SimulatorConfigService.class); + + simulatorService = new SimulatorService(templatePatcher, templateReader, + eventScheduler, eventDataService, simulatorConfigService); + } + + @Test + void shouldTriggerEventWithGivenParams() throws IOException, SchedulerException { + String templateName = "validExampleMeasurementEvent.json"; + SimulatorParams simulatorParams = new SimulatorParams(VES_URL, 1, 1); + SimulatorRequest simulatorRequest = new SimulatorRequest(simulatorParams, + templateName, VALID_PATCH); + + doReturn(SAMPLE_EVENT).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); + + simulatorService.triggerEvent(simulatorRequest); + + assertEventHasExpectedStructure(VES_URL, templateName, SOME_CUSTOM_SOURCE); + } + + @Test + void shouldTriggerEventWithDefaultVesUrlWhenNotProvidedInRequest() throws IOException, SchedulerException { + String templateName = "validExampleMeasurementEvent.json"; + SimulatorRequest simulatorRequest = new SimulatorRequest( + new SimulatorParams("", 1, 1), + templateName, VALID_PATCH); + + URL inDbVesUrl = new URL("http://0.0.0.0:8080/eventListener/v6"); + doReturn(SAMPLE_EVENT).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); + when(simulatorConfigService.getConfiguration()).thenReturn(new SimulatorConfig(SAMPLE_ID, inDbVesUrl)); + + simulatorService.triggerEvent(simulatorRequest); + + assertEventHasExpectedStructure(inDbVesUrl.toString(), templateName, SOME_CUSTOM_SOURCE); + } + + @Test + void shouldThrowJsonSyntaxWhenInvalidJson() { + //given + JsonObject patch = GSON.fromJson("{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"sourceName\": \"" + SOME_CUSTOM_SOURCE + "\"\n" + + " }\n" + + " }\n" + + "}\n", JsonObject.class); + EventData eventData = EventData.builder().id("1").build(); + + SimulatorParams simulatorParams = new SimulatorParams(VES_URL, 1, 1); + SimulatorRequest simulatorRequest = new SimulatorRequest(simulatorParams, + "invalidJsonStructureEvent.json", patch); + doReturn(eventData).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); + + //when + assertThrows(JsonSyntaxException.class, + () -> simulatorService.triggerEvent(simulatorRequest)); + } + + @Test + void shouldHandleNonExistingPatchSection() throws IOException, SchedulerException { + String templateName = "validExampleMeasurementEvent.json"; + JsonObject nullPatch = null; + SimulatorRequest simulatorRequest = new SimulatorRequest( + new SimulatorParams("", 1, 1), + templateName, nullPatch); + + URL inDbVesUrl = new URL("http://0.0.0.0:8080/eventListener/v6"); + doReturn(SAMPLE_EVENT).when(eventDataService).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); + doReturn(new SimulatorConfig(SAMPLE_ID, inDbVesUrl)).when(simulatorConfigService).getConfiguration(); + + simulatorService.triggerEvent(simulatorRequest); + + assertEventHasExpectedStructure(inDbVesUrl.toString(), templateName, CLOSED_LOOP_VNF); + } + + @Test + void shouldSuccessfullySendOneTimeEventWithVesUrlWhenPassed() throws MalformedURLException { + SimulatorService spiedTestedService = spy(new SimulatorService(templatePatcher,templateReader, eventScheduler, eventDataService, simulatorConfigService)); + + HttpClientAdapter adapterMock = mock(HttpClientAdapter.class); + doNothing().when(adapterMock).send(eventContentCaptor.capture()); + doReturn(adapterMock).when(spiedTestedService).createHttpClientAdapter(any(String.class)); + FullEvent event = new FullEvent(VES_URL, VALID_FULL_EVENT); + + spiedTestedService.triggerOneTimeEvent(event); + + assertThat(eventContentCaptor.getValue()).isEqualTo(VALID_FULL_EVENT.toString()); + verify(eventDataService, times(1)).persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), any(JsonObject.class)); + verify(adapterMock, times(1)).send(VALID_FULL_EVENT.toString()); + } + + @Test + void shouldSubstituteKeywordsAndSuccessfullySendOneTimeEvent() throws MalformedURLException { + SimulatorService spiedTestedService = spy(new SimulatorService(templatePatcher,templateReader, eventScheduler, eventDataService, simulatorConfigService)); + + HttpClientAdapter adapterMock = mock(HttpClientAdapter.class); + doNothing().when(adapterMock).send(eventContentCaptor.capture()); + doReturn(adapterMock).when(spiedTestedService).createHttpClientAdapter(any(String.class)); + FullEvent event = new FullEvent(VES_URL, FULL_EVENT_WITH_KEYWORDS); + + spiedTestedService.triggerOneTimeEvent(event); + + JsonObject sentContent = GSON.fromJson(eventContentCaptor.getValue(), JsonElement.class).getAsJsonObject(); + assertThat(sentContent.getAsJsonObject("event").getAsJsonObject("commonEventHeader").get("eventOrderNo").getAsString()).isEqualTo("1"); + assertThat(sentContent.getAsJsonObject("event").getAsJsonObject("commonEventHeader").get("eventName").getAsString()).hasSize(20); + } + + + private void assertEventHasExpectedStructure(String expectedVesUrl, String templateName, String sourceNameString) throws SchedulerException, MalformedURLException { + verify(eventScheduler, times(1)).scheduleEvent(vesUrlCaptor.capture(), intervalCaptor.capture(), + repeatCountCaptor.capture(), templateNameCaptor.capture(), eventIdCaptor.capture(), bodyCaptor.capture()); + assertThat(vesUrlCaptor.getValue()).isEqualTo(expectedVesUrl); + assertThat(intervalCaptor.getValue()).isEqualTo(1); + assertThat(repeatCountCaptor.getValue()).isEqualTo(1); + assertThat(templateNameCaptor.getValue()).isEqualTo(templateName); + String actualSourceName = GSON.fromJson(bodyCaptor.getValue(), JsonObject.class) + .get("event").getAsJsonObject() + .get("commonEventHeader").getAsJsonObject() + .get("sourceName").getAsString(); + assertThat(actualSourceName).isEqualTo(sourceNameString); + verify(eventDataService) + .persistEventData(any(JsonObject.class), any(JsonObject.class), any(JsonObject.class), + any(JsonObject.class)); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplatePatcherTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplatePatcherTest.java new file mode 100644 index 000000000..52e0d6ae6 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplatePatcherTest.java @@ -0,0 +1,164 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.assertj.core.api.AssertionsForInterfaceTypes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class TemplatePatcherTest { + + private static final String TEMPLATE_JSON = "{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"measurementsForVfScaling\"\n" + + " },\n" + + " \"measurementsForVfScalingFields\": {\n" + + " \"measurementsForVfSclaingFieldsVersion\": 2.0,\n" + + " \"additionalMeasurements\": {\n" + + " \"name\": \"licenseUsage\",\n" + + " \"extraFields\": {\n" + + " \"name\": \"G711AudioPort\",\n" + + " \"value\": \"1\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + private TemplatePatcher templatePatcher; + private Gson gson = new Gson(); + private JsonObject templateJson; + + @BeforeEach + void setUp() { + templatePatcher = new TemplatePatcher(); + templateJson = gson.fromJson(TEMPLATE_JSON, JsonObject.class); + } + + @Test + void shouldReplaceJsonElementsInTemplate() { + //given + String patchJsonString = "{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"newDomain\"\n" + + " }\n" + + " }\n" + + "}"; + JsonObject patchJson = gson.fromJson(patchJsonString, JsonObject.class); + + //when + JsonObject requestJson = templatePatcher.mergeTemplateWithPatch(templateJson, patchJson); + + //then + String newDomain = requestJson + .get("event").getAsJsonObject() + .get("commonEventHeader").getAsJsonObject() + .get("domain").getAsString(); + assertThat(newDomain).isEqualTo("newDomain"); + } + + @Test + void shouldAddWholeJsonObjectToTemplateWhenItFinished() { + //given + String patchJsonString = + "{\n" + + " \"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": {\n" + + " \"extraFields\": {\n" + + " \"name\": \"G711AudioPort\",\n" + + " \"value\": \"1\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + JsonObject patchJson = gson.fromJson(patchJsonString, JsonObject.class); + + //when + JsonObject requestJson = templatePatcher.mergeTemplateWithPatch(templateJson, patchJson); + + //then + JsonElement newDomain = requestJson + .get("event").getAsJsonObject() + .get("commonEventHeader").getAsJsonObject() + .get("domain"); + assertThat(newDomain.isJsonObject()).isTrue(); + JsonObject newDomainJO = newDomain.getAsJsonObject(); + AssertionsForInterfaceTypes.assertThat(newDomainJO.keySet()).containsExactly("extraFields"); + JsonObject newDomainExtraFields = newDomainJO.get("extraFields").getAsJsonObject(); + AssertionsForInterfaceTypes.assertThat(newDomainExtraFields.keySet()).containsExactly("name", "value"); + } + + @Test + void shouldReplaceJsonObjectWithJsonElementFromPatch() { + //given + String patchJsonString = "{ \"event\": \"test\" }"; + JsonObject patchJson = gson.fromJson(patchJsonString, JsonObject.class); + + //when + JsonObject requestJson = templatePatcher.mergeTemplateWithPatch(templateJson, patchJson); + + //then + assertThat(requestJson.get("event").isJsonObject()).isFalse(); + assertThat(requestJson.get("event").getAsString()).isEqualTo("test"); + } + + @Test + void shouldAddNewKeyIfPatchHasItAndTempleteDoesnt() { + //given + String patchJsonString = "{ \"newTestKey\": { \"newTestKeyChild\":\"newTestValue\" }}"; + JsonObject patchJson = gson.fromJson(patchJsonString, JsonObject.class); + + //when + JsonObject requestJson = templatePatcher.mergeTemplateWithPatch(templateJson, patchJson); + + //then + assertThat(requestJson.get("event").isJsonObject()).isTrue(); + assertThat(requestJson.get("newTestKey").isJsonObject()).isTrue(); + JsonObject newTestKey = requestJson.get("newTestKey").getAsJsonObject(); + AssertionsForInterfaceTypes.assertThat(newTestKey.keySet()).containsExactly("newTestKeyChild"); + assertThat(newTestKey.get("newTestKeyChild").getAsString()).isEqualTo("newTestValue"); + + } + + + @Test + void shouldNotChangeInputTemplateParam() { + //given + String patchJsonString = "{ \"newTestKey\": { \"newTestKeyChild\":\"newTestValue\" }}"; + JsonObject patchJson = gson.fromJson(patchJsonString, JsonObject.class); + + //when + templatePatcher.mergeTemplateWithPatch(templateJson, patchJson); + + //then + assertThat(templateJson).isEqualTo(gson.fromJson(TEMPLATE_JSON, JsonObject.class)); + + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplateReaderTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplateReaderTest.java new file mode 100644 index 000000000..f029fce75 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/TemplateReaderTest.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.test.context.TestPropertySource; + +import java.io.IOException; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +@TestPropertySource +class TemplateReaderTest { + + private FilesystemTemplateReader templateReader = new FilesystemTemplateReader("src/test/resources/org/onap/pnfsimulator/simulator/", new Gson()); + + @Test + void testShouldReadJsonFromFile() throws IOException { + JsonObject readJson = templateReader.readTemplate("validExampleMeasurementEvent.json"); + assertThat(readJson.keySet()).containsOnly("event"); + assertThat(readJson.get("event").getAsJsonObject().keySet()).containsExactlyInAnyOrder("commonEventHeader", "measurementsForVfScalingFields"); + } + + @Test + void testShouldRaiseExceptionWhenInvalidJsonIsRead() { + Assertions.assertThrows(JsonSyntaxException.class, () -> templateReader.readTemplate("invalidJsonStructureEvent.json")); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java new file mode 100644 index 000000000..41bd7b1e6 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/HttpClientAdapterImplTest.java @@ -0,0 +1,97 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator.client; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.MalformedURLException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +class HttpClientAdapterImplTest { + + private static final String HTTPS_URL = "https://0.0.0.0:8443/"; + private static final String HTTP_URL = "http://0.0.0.0:8000/"; + + private HttpClient httpClient; + private HttpResponse httpResponse; + + @BeforeEach + void setup() { + httpClient = mock(HttpClient.class); + httpResponse = mock(HttpResponse.class); + } + + @Test + void sendShouldSuccessfullySendRequestGivenValidUrl() throws IOException { + assertAdapterSentRequest("http://valid-url:8080"); + } + + @Test + void sendShouldSuccessfullySendRequestGivenValidUrlUsingHTTPS() throws IOException { + assertAdapterSentRequest("https://valid-url:8443"); + } + + @Test + void shouldThrowExceptionWhenMalformedVesUrlPassed(){ + assertThrows(MalformedURLException.class, () -> new HttpClientAdapterImpl("http://blablabla:VES-PORT")); + } + @Test + void shouldCreateAdapterWithClientNotSupportingSSLConnection() throws MalformedURLException { + HttpClientAdapter adapterWithHttps = new HttpClientAdapterImpl(HTTPS_URL); + try { + adapterWithHttps.send("sample"); + } catch (Exception actualException) { + assertThat(actualException).hasStackTraceContaining(SSLConnectionSocketFactory.class.toString()); + } + } + + @Test + void shouldCreateAdapterWithClientSupportingPlainConnectionOnly() throws MalformedURLException { + HttpClientAdapter adapterWithHttps = new HttpClientAdapterImpl(HTTP_URL); + try { + adapterWithHttps.send("sample"); + } catch (Exception actualException) { + assertThat(actualException).hasStackTraceContaining(PlainConnectionSocketFactory.class.toString()); + } + } + + private void assertAdapterSentRequest(String targetUrl) throws IOException { + HttpClientAdapter adapter = new HttpClientAdapterImpl(httpClient, targetUrl); + doReturn(httpResponse).when(httpClient).execute(any()); + + adapter.send("test-msg"); + + verify(httpClient).execute(any()); + verify(httpResponse).getStatusLine(); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevelTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevelTest.java new file mode 100644 index 000000000..ff41c441d --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/client/utils/ssl/SslSupportLevelTest.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator.client.utils.ssl; + +import org.junit.jupiter.api.Test; + +import java.net.MalformedURLException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class SslSupportLevelTest { + + private static final String HTTPS_URL = "https://127.0.0.1:8443/"; + private static final String HTTP_URL = "http://127.0.0.1:8080/"; + + @Test + void testShouldReturnAlwaysTrustSupportLevelForHttpsUrl() throws MalformedURLException { + SslSupportLevel actualSupportLevel = SslSupportLevel.getSupportLevelBasedOnProtocol(HTTPS_URL); + assertEquals(actualSupportLevel, SslSupportLevel.ALWAYS_TRUST); + } + + @Test + void testShouldReturnNoneSupportLevelForHttpUrl() throws MalformedURLException { + SslSupportLevel actualSupportLevel = SslSupportLevel.getSupportLevelBasedOnProtocol(HTTP_URL); + assertEquals(actualSupportLevel, SslSupportLevel.NONE); + } + + @Test + void testShouldRaiseExceptionWhenInvalidUrlPassed(){ + assertThrows(MalformedURLException.class, () -> SslSupportLevel.getSupportLevelBasedOnProtocol("http://bla:VES-PORT/")); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventJobTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventJobTest.java new file mode 100644 index 000000000..25ed84c43 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventJobTest.java @@ -0,0 +1,90 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator.scheduler; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.BODY; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.CLIENT_ADAPTER; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.EVENT_ID; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.KEYWORDS_HANDLER; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.TEMPLATE_NAME; +import static org.onap.pnfsimulator.simulator.scheduler.EventJob.VES_URL; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.onap.pnfsimulator.simulator.KeywordsExtractor; +import org.onap.pnfsimulator.simulator.KeywordsHandler; +import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobKey; + +class EventJobTest { + + @Test + void shouldSendEventWhenExecuteCalled() { + //given + EventJob eventJob = new EventJob(); + String templateName = "template name"; + String vesUrl = "http://someurl:80/"; + String eventId = "1"; + JsonParser parser = new JsonParser(); + JsonObject body = parser.parse("{\"a\": \"A\"}").getAsJsonObject(); + HttpClientAdapter clientAdapter = mock(HttpClientAdapter.class); + JobExecutionContext jobExecutionContext = + createMockJobExecutionContext(templateName, eventId, vesUrl, body, clientAdapter); + + ArgumentCaptor<String> vesUrlCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor<String> bodyCaptor = ArgumentCaptor.forClass(String.class); + + //when + eventJob.execute(jobExecutionContext); + + //then + verify(clientAdapter).send(bodyCaptor.capture()); + assertThat(bodyCaptor.getValue()).isEqualTo(body.toString()); + } + + private JobExecutionContext createMockJobExecutionContext(String templateName, String eventId, String vesURL, + JsonObject body, HttpClientAdapter clientAdapter) { + + JobDataMap jobDataMap = new JobDataMap(); + jobDataMap.put(TEMPLATE_NAME, templateName); + jobDataMap.put(KEYWORDS_HANDLER, new KeywordsHandler(new KeywordsExtractor(), (id) -> 1)); + jobDataMap.put(EVENT_ID, eventId); + jobDataMap.put(VES_URL, vesURL); + jobDataMap.put(BODY, body); + jobDataMap.put(CLIENT_ADAPTER, clientAdapter); + + JobExecutionContext jobExecutionContext = mock(JobExecutionContext.class); + JobDetail jobDetail = mock(JobDetail.class); + when(jobExecutionContext.getJobDetail()).thenReturn(jobDetail); + when(jobDetail.getJobDataMap()).thenReturn(jobDataMap); + when(jobDetail.getKey()).thenReturn(new JobKey("jobId", "group")); + return jobExecutionContext; + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventSchedulerTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventSchedulerTest.java new file mode 100644 index 000000000..9d0f7d84f --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/scheduler/EventSchedulerTest.java @@ -0,0 +1,143 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulator.scheduler; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.gson.JsonObject; + +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobKey; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.SimpleTrigger; + +class EventSchedulerTest { + + @InjectMocks + EventScheduler eventScheduler; + + @Mock + Scheduler quartzScheduler; + + @BeforeEach + void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + void shouldTriggerEventWithGivenConfiguration() throws SchedulerException, MalformedURLException { + //given + ArgumentCaptor<JobDetail> jobDetailCaptor = ArgumentCaptor.forClass(JobDetail.class); + ArgumentCaptor<SimpleTrigger> triggerCaptor = ArgumentCaptor.forClass(SimpleTrigger.class); + + String vesUrl = "http://some:80/"; + int repeatInterval = 1; + int repeatCount = 4; + String testName = "testName"; + String eventId = "1"; + JsonObject body = new JsonObject(); + + //when + eventScheduler.scheduleEvent(vesUrl, repeatInterval, repeatCount, testName, eventId, body); + + //then + verify(quartzScheduler).scheduleJob(jobDetailCaptor.capture(), triggerCaptor.capture()); + JobDataMap actualJobDataMap = jobDetailCaptor.getValue().getJobDataMap(); + assertThat(actualJobDataMap.get(EventJob.BODY)).isEqualTo(body); + assertThat(actualJobDataMap.get(EventJob.TEMPLATE_NAME)).isEqualTo(testName); + assertThat(actualJobDataMap.get(EventJob.VES_URL)).isEqualTo(vesUrl); + + SimpleTrigger actualTrigger = triggerCaptor.getValue(); + // repeat count adds 1 to given value + assertThat(actualTrigger.getRepeatCount()).isEqualTo(repeatCount - 1); + + //getRepeatInterval returns interval in ms + assertThat(actualTrigger.getRepeatInterval()).isEqualTo(repeatInterval * 1000); + } + + @Test + void shouldCancelAllEvents() throws SchedulerException { + //given + List<JobKey> jobsKeys = Arrays.asList(new JobKey("jobName1"), new JobKey("jobName2"), + new JobKey("jobName3"), new JobKey("jobName4")); + List<JobExecutionContext> jobExecutionContexts = createExecutionContextWithKeys(jobsKeys); + when(quartzScheduler.getCurrentlyExecutingJobs()).thenReturn(jobExecutionContexts); + when(quartzScheduler.deleteJobs(jobsKeys)).thenReturn(true); + + //when + boolean isCancelled = eventScheduler.cancelAllEvents(); + + //then + assertThat(isCancelled).isTrue(); + } + + @Test + void shouldCancelSingleEvent() throws SchedulerException { + //given + JobKey jobToRemove = new JobKey("jobName3"); + List<JobKey> jobsKeys = Arrays.asList(new JobKey("jobName1"), new JobKey("jobName2"), + jobToRemove, new JobKey("jobName4")); + List<JobExecutionContext> jobExecutionContexts = createExecutionContextWithKeys(jobsKeys); + + when(quartzScheduler.getCurrentlyExecutingJobs()).thenReturn(jobExecutionContexts); + when(quartzScheduler.deleteJob(jobToRemove)).thenReturn(true); + + //when + boolean isCancelled = eventScheduler.cancelEvent("jobName3"); + + //then + assertThat(isCancelled).isTrue(); + } + + private List<JobExecutionContext> createExecutionContextWithKeys(List<JobKey> jobsKeys) { + List<JobExecutionContext> contexts = new ArrayList<>(); + for (JobKey key : jobsKeys) { + contexts.add(createExecutionContextFromKey(key)); + } + return contexts; + } + + private JobExecutionContext createExecutionContextFromKey(JobKey key) { + JobExecutionContext context = mock(JobExecutionContext.class); + JobDetail jobDetail = mock(JobDetail.class); + when(context.getJobDetail()).thenReturn(jobDetail); + when(jobDetail.getKey()).thenReturn(key); + return context; + } + + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigServiceTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigServiceTest.java new file mode 100644 index 000000000..4ed097289 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulatorconfig/SimulatorConfigServiceTest.java @@ -0,0 +1,104 @@ +/* + * ============LICENSE_START======================================================= + * PNF-REGISTRATION-HANDLER + * ================================================================================ + * Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.simulatorconfig; + +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.assertj.core.api.Java6Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +class SimulatorConfigServiceTest { + + private static final String SAMPLE_ID = "sampleId"; + private static final String SAMPLE_NEW_VES_URL = "http://localhost:8090/eventListener/v7"; + @Mock + private SimulatorConfigRepository repository; + + @InjectMocks + private SimulatorConfigService service; + + @BeforeEach + void resetMocks() { + initMocks(this); + } + + @Test + void testShouldReturnConfiguration() throws MalformedURLException { + List<SimulatorConfig> expectedConfig = getExpectedConfig(); + when(repository.findAll()).thenReturn(expectedConfig); + + SimulatorConfig configs = service.getConfiguration(); + + assertThat(configs).isNotNull(); + } + + @Test + void testShouldRaiseExceptionWhenNoConfigurationPresent() { + when(repository.findAll()).thenReturn(Lists.emptyList()); + + assertThatThrownBy(() -> service.getConfiguration()) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("No configuration found in db"); + } + + @Test + void testShouldUpdateConfigurationWithVesUrl() throws MalformedURLException { + URL updatedUrl = new URL("http://localhost:8090/listener/v8"); + SimulatorConfig configWithUpdates = new SimulatorConfig("sampleId", updatedUrl); + List<SimulatorConfig> expectedConfig = getExpectedConfig(); + + when(repository.findAll()).thenReturn(expectedConfig); + when(repository.save(any(SimulatorConfig.class))).thenReturn(configWithUpdates); + + SimulatorConfig updatedConfig = service.updateConfiguration(configWithUpdates); + + assertThat(updatedConfig).isEqualToComparingFieldByField(configWithUpdates); + } + + @Test + void testShouldRaiseExceptionWhenNoConfigInDbPresentOnUpdate() throws MalformedURLException { + when(repository.findAll()).thenReturn(Lists.emptyList()); + + SimulatorConfig configWithUpdates = new SimulatorConfig(SAMPLE_ID, new URL(SAMPLE_NEW_VES_URL)); + + assertThatThrownBy(() -> service.updateConfiguration(configWithUpdates)) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("No configuration found in db"); + } + + private List<SimulatorConfig> getExpectedConfig() throws MalformedURLException { + URL sampleVesUrl = new URL("http://localhost:8080/eventListener/v7"); + SimulatorConfig config = new SimulatorConfig(SAMPLE_ID, sampleVesUrl); + return Lists.newArrayList(config); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/TemplateServiceTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/TemplateServiceTest.java new file mode 100644 index 000000000..074696094 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/TemplateServiceTest.java @@ -0,0 +1,152 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.assertj.core.util.Lists; +import org.bson.Document; +import org.junit.Assert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock;; +import org.onap.pnfsimulator.template.search.viewmodel.FlatTemplateContent; +import org.onap.pnfsimulator.template.search.TemplateSearchHelper; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; + +import java.time.Instant; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyObject; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +class TemplateServiceTest { + private static final Gson GSON = new Gson(); + private static final Template SAMPLE_TEMPLATE = new Template("sample name", new Document(), Instant.now().getNano()); + private static final List<Template> SAMPLE_TEMPLATE_LIST = Collections.singletonList(SAMPLE_TEMPLATE); + + @Mock + private TemplateRepository templateRepositoryMock; + + @Mock + private MongoTemplate mongoTemplate; + + @InjectMocks + private TemplateService service; + + @BeforeEach + void setUp() { + initMocks(this); + TemplateSearchHelper searchHelper = new TemplateSearchHelper(mongoTemplate); + service = new TemplateService(templateRepositoryMock, searchHelper); + } + + @Test + void testShouldReturnAllTemplates() { + when(templateRepositoryMock.findAll()).thenReturn(SAMPLE_TEMPLATE_LIST); + + List<Template> actual = service.getAll(); + assertThat(actual).containsExactly(SAMPLE_TEMPLATE_LIST.get(0)); + } + + + @Test + void testShouldGetTemplateBySpecifiedName() { + when(templateRepositoryMock.findById("sample name")).thenReturn(Optional.of(SAMPLE_TEMPLATE)); + + Optional<Template> actualTemplate = service.get("sample name"); + assertThat(actualTemplate).isPresent(); + assertThat(actualTemplate.get()).isEqualTo(SAMPLE_TEMPLATE); + } + + @Test + void testShouldSaveTemplate() { + service.persist(SAMPLE_TEMPLATE); + + verify(templateRepositoryMock, times(1)).save(SAMPLE_TEMPLATE); + } + + @Test + void testShouldDeleteTemplateByName() { + service.delete("sample name"); + + verify(templateRepositoryMock, times(1)).deleteById("sample name"); + } + + + @Test + void testShouldReturnTemplatesAccordingToGivenSearchCriteria() { + doReturn(Lists.emptyList()).when(mongoTemplate).find(any(Query.class), anyObject(), any(String.class)); + + List<String> idsByContentCriteria = service.getIdsByContentCriteria(GSON.fromJson("{\"domain\": \"notification.json\"}", JsonObject.class)); + + assertThat(idsByContentCriteria).isEmpty(); + } + + @Test + void shouldReturnNamesForGivenComposedSearchCriteria(){ + JsonObject composedCriteriaObject = GSON.fromJson("{\"eventName\": \"pnfRegistration_Nokia_5gDu\", \"sequence\": 1}", JsonObject.class); + List<FlatTemplateContent> arr = Lists.newArrayList(new FlatTemplateContent("sampleId", null)); + + doReturn(arr).when(mongoTemplate).find(any(Query.class), anyObject(), any(String.class)); + + List<String> idsByContentCriteria = service.getIdsByContentCriteria(composedCriteriaObject); + assertThat(idsByContentCriteria).containsOnly("sampleId"); + } + + @Test + void shouldReturnFalseWhenOverwritingWithoutForce() { + String id = "someTemplate"; + Template template = new Template(id, new Document(), Instant.now().getNano()); + when(templateRepositoryMock.existsById(id)).thenReturn(true); + boolean actual = service.tryPersistOrOverwrite(template, false); + Assert.assertFalse(actual); + } + + @Test + void shouldReturnTrueWhenOverwritingWithForce() { + String id = "someTemplate"; + Template template = new Template(id, new Document(), Instant.now().getNano()); + when(templateRepositoryMock.existsById(id)).thenReturn(true); + boolean actual = service.tryPersistOrOverwrite(template, true); + Assert.assertTrue(actual); + } + + @Test + void shouldReturnTrueWhenSavingNonExistingTemplate() { + String id = "someTemplate"; + Template template = new Template(id, new Document(), Instant.now().getNano()); + when(templateRepositoryMock.existsById(id)).thenReturn(false); + boolean actual = service.tryPersistOrOverwrite(template, false); + Assert.assertTrue(actual); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/JsonUtilsTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/JsonUtilsTest.java new file mode 100644 index 000000000..fa0bed182 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/JsonUtilsTest.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.bson.Document; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +class JsonUtilsTest { + + private static final Gson GSON_HELPER = new Gson(); + private JsonUtils utils; + + @BeforeEach + void setUp() { + utils = new JsonUtils(); + } + + private static final String NOTIFICATION_JSON = "{\n\"event\": {\n" + + " \"commonEventHeader\": {\n" + + " \"domain\": \"notification\",\n" + + " \"eventName\": \"vFirewallBroadcastPackets\"\n" + + " },\n" + + " \"notificationFields\": {\n" + + " \"changeIdentifier\": \"PM_MEAS_FILES\",\n" + + " \"arrayOfNamedHashMap\": [{\n" + + " \"name\": \"A20161221.1031-1041.bin.gz\",\n" + + " \"hashMap\": {\n" + + " \"fileformatType\": \"org.3GPP.32.435#measCollec\",\n" + + " \"fileFormatVersion\": \"V10\"\n"+ + " }\n" + + " }, {\n" + + " \"name\": \"A20161222.1042-1102.bin.gz\",\n" + + " \"hashMap\": {\n" + + " \"fileFormatType\": \"org.3GPP.32.435#measCollec\",\n" + + " \"fileFormatVersion\": \"1.0.0\"\n" + + " }\n" + + " }],\n" + + " \"notificationFieldsVersion\": \"2.0\"\n}\n\n}}"; + private static final String EXPECTED_FLATTENED_NOTIFICATION = "{" + + " \":event:commonEventHeader:domain\" : \"notification\"," + + " \":event:commonEventHeader:eventName\" : \"vFirewallBroadcastPackets\"," + + " \":event:notificationFields:changeIdentifier\" : \"PM_MEAS_FILES\"," + + " \":event:notificationFields:arrayOfNamedHashMap[0]:name\" : \"A20161221.1031-1041.bin.gz\"," + + " \":event:notificationFields:arrayOfNamedHashMap[0]:hashMap:fileformatType\" : \"org.3GPP.32.435#measCollec\"," + + " \":event:notificationFields:arrayOfNamedHashMap[0]:hashMap:fileFormatVersion\" : \"V10\"," + + " \":event:notificationFields:arrayOfNamedHashMap[1]:name\" : \"A20161222.1042-1102.bin.gz\"," + + " \":event:notificationFields:arrayOfNamedHashMap[1]:hashMap:fileFormatType\" : \"org.3GPP.32.435#measCollec\"," + + " \":event:notificationFields:arrayOfNamedHashMap[1]:hashMap:fileFormatVersion\" : \"1.0.0\"," + + " \":event:notificationFields:notificationFieldsVersion\" : \"2.0\" }"; + + @Test + void shouldFlattenNestedJsonAndSeparateKeysWithDoubleHash(){ + JsonObject templateJson = GSON_HELPER.fromJson(NOTIFICATION_JSON, JsonObject.class); + + JsonObject result = utils.flatten(templateJson); + + assertThat(result).isEqualTo(GSON_HELPER.fromJson(EXPECTED_FLATTENED_NOTIFICATION, JsonObject.class)); + } + + @Test + void shouldWorkOnEmptyJsonObject(){ + JsonObject result = utils.flatten(new JsonObject()); + + assertThat(result.toString()).isEqualTo("{}"); + } + + @Test + void shouldFlattenObjectWithArrayValue(){ + String expectedFlattenedObjectWithArray = "{" + + " \":sample[0]\": 1," + + " \":sample[1]\": 2," + + " \":sample[2]\": 3}"; + JsonObject jsonWithPrimitivesArray = GSON_HELPER.fromJson("{\"sample\": [1, 2, 3]}", JsonObject.class); + + JsonObject result = utils.flatten(jsonWithPrimitivesArray); + + assertThat(result).isEqualTo(GSON_HELPER.fromJson(expectedFlattenedObjectWithArray, JsonObject.class)); + } + + @Test + void shouldFlattenObjectWithEmptyArrayValue(){ + String expectedFlattenedObjectWithEmptyArray = "{\":sample\": []}"; + JsonObject jsonWithEmptyArrayValue = GSON_HELPER.fromJson("{\"sample\": []}", JsonObject.class); + + JsonObject result = utils.flatten(jsonWithEmptyArrayValue); + + assertThat(result).isEqualTo(GSON_HELPER.fromJson(expectedFlattenedObjectWithEmptyArray, JsonObject.class)); + } + + @Test + void shouldFlattenNestedObjectWithEmptyObjectValue(){ + String expectedFlattenedNestedObjectWithEmptyObject = "{\":sample:key\": {}}"; + JsonObject nestedJsonWithEmptyObject = GSON_HELPER.fromJson("{\"sample\": {\"key\":{}}}", JsonObject.class); + + JsonObject result = utils.flatten(nestedJsonWithEmptyObject); + + assertThat(result).isEqualTo(GSON_HELPER.fromJson(expectedFlattenedNestedObjectWithEmptyObject, JsonObject.class)); + } + + @Test + void shouldFlattenObjectWithDifferentDataTypes(){ + String jsonWithDifferentDataTypes = "{ \"topLevelKey\": {\"sampleInt\": 1, \"sampleBool\": false, \"sampleDouble\": 10.0, \"sampleString\": \"str\"}}"; + String expectedResult = "{\":topLevelKey:sampleInt\": 1," + + " \":topLevelKey:sampleBool\": \"false\"," + + " \":topLevelKey:sampleDouble\": 10.0," + + " \":topLevelKey:sampleString\": \"str\"}"; + JsonObject templateJson = GSON_HELPER.fromJson(jsonWithDifferentDataTypes, JsonObject.class); + + JsonObject result = utils.flatten(templateJson); + + assertThat(result).isEqualTo(GSON_HELPER.fromJson(expectedResult, JsonObject.class)); + } + + @Test + void shouldHandleNullValues(){ + String jsonWithNullValue = "{ \"topLevelKey\": {\"sampleNull\": null, \"sampleString\": \"str\"}}"; + String expectedResult = "{\":topLevelKey:sampleNull\": null," + + " \":topLevelKey:sampleString\": \"str\"}"; + JsonObject templateJson = GSON_HELPER.fromJson(jsonWithNullValue, JsonObject.class); + + JsonObject result = utils.flatten(templateJson); + + assertThat(result).isEqualTo(GSON_HELPER.fromJson(expectedResult, JsonObject.class)); + } + + @Test + void shouldFlattenBsonDocument(){ + Document documentInput = Document.parse(NOTIFICATION_JSON); + + Document result = utils.flatten(documentInput); + + assertThat(result.toJson()).isEqualTo(EXPECTED_FLATTENED_NOTIFICATION); + } + + @Test + void shouldNotChangeEmptyBsonDocument(){ + Document input = Document.parse("{}"); + + Document result = utils.flatten(input); + + assertThat(result.toJson()).isEqualTo("{ }"); + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/TemplateSearchHelperTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/TemplateSearchHelperTest.java new file mode 100644 index 000000000..aeef8706a --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/TemplateSearchHelperTest.java @@ -0,0 +1,160 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.mongodb.BasicDBList; +import org.assertj.core.util.Lists; +import org.bson.Document; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.onap.pnfsimulator.template.search.viewmodel.FlatTemplateContent; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.BasicQuery; +import org.springframework.data.mongodb.core.query.Query; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyObject; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + + +class TemplateSearchHelperTest { + + private static final Gson GSON = new Gson(); + private static final String FLATTENED_TEMPLATES_VIEW = "flatTemplatesView"; + + @Mock + private MongoTemplate mongoTemplate; + + @InjectMocks + private TemplateSearchHelper helper; + + private static final ArgumentCaptor<Query> QUERY_CAPTOR = ArgumentCaptor.forClass(Query.class); + private static final ArgumentCaptor<String> COLLECTION_NAME_CAPTOR = ArgumentCaptor.forClass(String.class); + private static final ArgumentCaptor<Class<FlatTemplateContent>> CLASS_TYPE_CAPTOR = ArgumentCaptor.forClass((Class) FlatTemplateContent.class); + + + @BeforeEach + void setUp() { + initMocks(this); + } + + @Test + void shouldReturnNamesForGivenComposedSearchCriteria(){ + String expectedComposedQueryString = "{\"$and\":[{\"keyValues\":{\"$elemMatch\":{\"k\":{\"$regex\":\":eventName(?:(\\\\[[\\\\d]+\\\\]))?$\",\"$options\":\"iu\"},\"v\":{\"$regex\":\"^\\\\QpnfRegistration_Nokia_5gDu\\\\E$\",\"$options\":\"iu\"}}}},{\"keyValues\":{\"$elemMatch\":{\"k\":{\"$regex\":\":sequence(?:(\\\\[[\\\\d]+\\\\]))?$\",\"$options\":\"iu\"},\"v\":1.0}}}]}"; + Query expectedQuery = new BasicQuery(expectedComposedQueryString); + + String composedCriteriaInputJson = "{\"eventName\": \"pnfRegistration_Nokia_5gDu\", \"sequence\": 1}"; + JsonObject composedCriteriaObject = GSON.fromJson(composedCriteriaInputJson, JsonObject.class); + + when(mongoTemplate.find(any(Query.class), anyObject(), any(String.class))).thenReturn(Lists.newArrayList(new FlatTemplateContent("sampleId1", null), new FlatTemplateContent("sampleId2", null))); + + List<String> idsOfDocumentMatchingCriteria = helper.getIdsOfDocumentMatchingCriteria(composedCriteriaObject); + + assertThat(idsOfDocumentMatchingCriteria).containsOnly("sampleId1", "sampleId2"); + verify(mongoTemplate, times(1)).find(QUERY_CAPTOR.capture(), CLASS_TYPE_CAPTOR.capture(), COLLECTION_NAME_CAPTOR.capture()); + assertThat(QUERY_CAPTOR.getValue().toString()).isEqualTo(expectedQuery.toString()); + assertThat(COLLECTION_NAME_CAPTOR.getValue()).isEqualTo(FLATTENED_TEMPLATES_VIEW); + assertThat(CLASS_TYPE_CAPTOR.getValue()).isEqualTo(FlatTemplateContent.class); + } + + @Test + void shouldReturnTemplatesAccordingToGivenSearchCriteria() { + Query expectedQueryStructure = new BasicQuery("{\"$and\":[{\"keyValues\": { \"$elemMatch\" : { \"k\" : { \"$regex\" : \":domain(?:(\\\\[[\\\\d]+\\\\]))?$\", \"$options\" : \"iu\" }, \"v\" : { \"$regex\" : \"^\\\\Qnotification\\\\E$\", \"$options\" : \"iu\" }}}}]}"); + + helper.getIdsOfDocumentMatchingCriteria(GSON.fromJson("{\"domain\": \"notification\"}", JsonObject.class)); + + + verify(mongoTemplate, times(1)).find(QUERY_CAPTOR.capture(), CLASS_TYPE_CAPTOR.capture(), COLLECTION_NAME_CAPTOR.capture()); + + assertThat(QUERY_CAPTOR.getValue().toString()).isEqualTo(expectedQueryStructure.toString()); + assertThat(COLLECTION_NAME_CAPTOR.getValue()).isEqualTo(FLATTENED_TEMPLATES_VIEW); + assertThat(CLASS_TYPE_CAPTOR.getValue()).isEqualTo(FlatTemplateContent.class); + } + + @Test + void shouldGetQueryForEmptyJson(){ + JsonObject jsonObject = GSON.fromJson("{}", JsonObject.class); + + String expectedComposedQueryString = "{}"; + Query expectedQuery = new BasicQuery(expectedComposedQueryString); + + helper.getIdsOfDocumentMatchingCriteria(jsonObject); + + verify(mongoTemplate, times(1)).find(QUERY_CAPTOR.capture(), CLASS_TYPE_CAPTOR.capture(), COLLECTION_NAME_CAPTOR.capture()); + Query queryBasedOnCriteria = QUERY_CAPTOR.getValue(); + + assertThat(QUERY_CAPTOR.getValue().toString()).isEqualTo(expectedQuery.toString()); + assertThat(COLLECTION_NAME_CAPTOR.getValue()).isEqualTo(FLATTENED_TEMPLATES_VIEW); + assertThat(CLASS_TYPE_CAPTOR.getValue()).isEqualTo(FlatTemplateContent.class); + } + + + @Test + void shouldGetQueryWithAllTypeValues(){ + JsonObject jsonObject = GSON.fromJson("{\"stringKey\": \"stringValue\", \"numberKey\": 16.00, \"boolKey\": false}", JsonObject.class); + + helper.getIdsOfDocumentMatchingCriteria(jsonObject); + + verify(mongoTemplate, times(1)).find(QUERY_CAPTOR.capture(), CLASS_TYPE_CAPTOR.capture(), COLLECTION_NAME_CAPTOR.capture()); + Query queryBasedOnCriteria = QUERY_CAPTOR.getValue(); + + assertThat(queryBasedOnCriteria.getQueryObject().get("$and")).isInstanceOf(List.class); + List<Document> conditionDocuments = new ArrayList<>((List<Document>) queryBasedOnCriteria.getQueryObject().get("$and")); + List<Document> conditions = conditionDocuments.stream().map(el -> (Document) el.get("keyValues")).map(el -> (Document) el.get("$elemMatch")).collect(Collectors.toList()); + + assertThat(conditionDocuments).hasSize(3); + assertJsonPreparedKeyHasCorrectStructure(conditions.get(0), "stringKey"); + assertThat(conditions.get(0).get("v").toString()).isEqualTo(TemplateSearchHelper.getCaseInsensitive("^\\QstringValue\\E$").toString()); + + assertJsonPreparedKeyHasCorrectStructure(conditions.get(1), "numberKey"); + assertThat(conditions.get(1).get("v")).isEqualTo(16.0); + + assertJsonPreparedKeyHasCorrectStructure(conditions.get(2), "boolKey"); + assertThat(conditions.get(2).get("v")).isEqualTo("false"); + } + + @Test + void shouldThrowExceptionWhenNullIsPresentAsCriteriaValue(){ + JsonObject jsonObject = GSON.fromJson("{\"stringKey\": \"stringValue\", \"nullKey\": null}", JsonObject.class); + + assertThrows(IllegalJsonValueException.class, () -> helper.getIdsOfDocumentMatchingCriteria(jsonObject)); + } + + private void assertJsonPreparedKeyHasCorrectStructure(Document actual, String expectedPattern){ + assertThat(actual.get("k").toString()).isEqualTo(Pattern.compile(String.format(":%s(?:(\\[[\\d]+\\]))?$", expectedPattern)).toString()); + + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilderTest.java b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilderTest.java new file mode 100644 index 000000000..31bcf1cb2 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/java/org/onap/pnfsimulator/template/search/handler/PrimitiveValueCriteriaBuilderTest.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * Simulator + * ================================================================================ + * Copyright (C) 2019 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.pnfsimulator.template.search.handler; + +import com.google.gson.JsonPrimitive; +import org.junit.jupiter.api.Test; +import org.springframework.data.mongodb.core.query.Criteria; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +class PrimitiveValueCriteriaBuilderTest { + + private PrimitiveValueCriteriaBuilder builder = new PrimitiveValueCriteriaBuilder(); + + @Test + void testShouldAddRegexLikeCriteriaForStringType(){ + Criteria criteria = builder.applyValueCriteriaBasedOnPrimitiveType(Criteria.where("k").is("10").and("v"), new JsonPrimitive("sample")); + + assertThat(criteria.getCriteriaObject().toJson()).isEqualTo("{ \"k\" : \"10\", \"v\" : { \"$regex\" : \"^\\\\Qsample\\\\E$\", \"$options\" : \"iu\" } }"); + } + + @Test + void testShouldAddRegexLikeAndEscapeStringWithMetaChars(){ + Criteria criteria = builder.applyValueCriteriaBasedOnPrimitiveType(Criteria.where("k").is("10").and("v"), new JsonPrimitive("[1,2,3,4,5]")); + + assertThat(criteria.getCriteriaObject().toJson()).isEqualTo("{ \"k\" : \"10\", \"v\" : { \"$regex\" : \"^\\\\Q[1,2,3,4,5]\\\\E$\", \"$options\" : \"iu\" } }"); + } + + @Test + void testShouldAddRegexLikeCriteriaForIntType(){ + Criteria criteria = builder.applyValueCriteriaBasedOnPrimitiveType(Criteria.where("k").is("10").and("v"), new JsonPrimitive(1)); + + assertThat(criteria.getCriteriaObject().toJson()).isEqualTo("{ \"k\" : \"10\", \"v\" : 1.0 }"); + } + + @Test + void testShouldAddRegexLikeCriteriaForLongType(){ + Criteria criteria = builder.applyValueCriteriaBasedOnPrimitiveType(Criteria.where("k").is("10").and("v"), new JsonPrimitive(Long.MAX_VALUE)); + + assertThat(criteria.getCriteriaObject().toJson()).isEqualTo("{ \"k\" : \"10\", \"v\" : 9.223372036854776E18 }"); + } + + @Test + void testShouldAddRegexLikeCriteriaForDoubleType(){ + Criteria criteria = builder.applyValueCriteriaBasedOnPrimitiveType(Criteria.where("k").is("10").and("v"), new JsonPrimitive(2.5)); + + assertThat(criteria.getCriteriaObject().toJson()).isEqualTo("{ \"k\" : \"10\", \"v\" : 2.5 }"); + } + + @Test + void testShouldAddRegexLikeCriteriaForBooleanType(){ + Criteria criteria = builder.applyValueCriteriaBasedOnPrimitiveType(Criteria.where("k").is("10").and("v"), new JsonPrimitive(true)); + + assertThat(criteria.getCriteriaObject().toJson()).isEqualTo("{ \"k\" : \"10\", \"v\" : \"true\" }"); + } + +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/application.properties b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/application.properties new file mode 100644 index 000000000..fe10b41ce --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/application.properties @@ -0,0 +1 @@ +templates.dir=src/test/resources/org/onap/pnfsimulator/simulator
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/logback-test.xml b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/logback-test.xml index d7966fe60..ad4f0c85e 100644 --- a/test/mocks/pnfsimulator/src/test/resources/logback-test.xml +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/logback-test.xml @@ -1,4 +1,24 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> + <Configuration complete="true" compact="true"> <Property name="outputFilename" value="pnfsimulator_output"/> diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/filesystem/test1.json b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/filesystem/test1.json new file mode 100644 index 000000000..6ef87c52c --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/filesystem/test1.json @@ -0,0 +1,8 @@ +{ + "field1": "value1", + "field2": 2, + "nested": { + "key1": [1, 2, 3], + "key2": "sampleValue2" + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/invalidJsonStructureEvent.json b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/invalidJsonStructureEvent.json new file mode 100644 index 000000000..89d5e89d3 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/invalidJsonStructureEvent.json @@ -0,0 +1 @@ +{"sampleKey1": [{"sampleKey2": "1"}, {"sampleKey2": "2"}]
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/validExampleMeasurementEvent.json b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/validExampleMeasurementEvent.json new file mode 100644 index 000000000..989d6ead5 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/validExampleMeasurementEvent.json @@ -0,0 +1,89 @@ +{ + "event": { + "commonEventHeader": { + "domain": "measurementsForVfScaling", + "eventName": "vFirewallBroadcastPackets", + "eventId": "4cfc-91cf-31a46", + "nfType": "mrfx", + "priority": "Normal", + "reportingEntityName": "myVNF", + "sequence": 1, + "sourceName": "ClosedLoopVNF", + "startEpochMicrosec": 1531616794, + "lastEpochMicrosec": 1531719042, + "version": 2.0 + }, + "measurementsForVfScalingFields": { + "measurementsForVfSclaingFieldsVersion": 2.0, + "measurementsForVfScalingVersion": 2.0, + "measurementInterval": 180, + "concurrentSessions": 2, + "cpuUsageArray": [ + { + "cpuIdentifier": "INTEL_CORE_I7_1", + "percentUsage": 50 + }, + { + "cpuIdentifier": "INTEL_CORE_I7_2", + "percentUsage": 70 + } + ], + "memoryUsageArray": [ + { + "vmIdentifier": "vmIdentifier", + "memoryFree": 50, + "memoryUsed": 10 + } + ], + "vNicUsageArray": [ + { + "receivedTotalPacketsDelta": 30 + } + ], + "numberOfMediaPortsInUse": 100, + "additionalMeasurements": [ + { + "name": "licenseUsage", + "arrayOfFields": [ + { + "name": "G711AudioPort", + "value": "1" + }, + { + "name": "G729AudioPort", + "value": "1" + }, + { + "name": "G722AudioPort", + "value": "1" + }, + { + "name": "AMRAudioPort", + "value": "4" + }, + { + "name": "AMRWBAudioPort", + "value": "5" + }, + { + "name": "OpusAudioPort", + "value": "6" + }, + { + "name": "H263VideoPort", + "value": "7" + }, + { + "name": "H264NonHCVideoPort", + "value": "8" + }, + { + "name": "H264HCVideoPort", + "value": "9" + } + ] + } + ] + } + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/templates/measurement.json b/test/mocks/pnfsimulator/pnfsimulator/templates/measurement.json new file mode 100644 index 000000000..182003ded --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/templates/measurement.json @@ -0,0 +1,45 @@ +{ + "event": { + "commonEventHeader": { + "domain": "measurementsForVfScaling", + "eventName": "vFirewallBroadcastPackets", + "eventId": "eventID123121312323", + "nfType": "mrfx", + "priority": "Normal", + "reportingEntityName": "vnf", + "sequence": 1, + "sourceName": "sample-vnf-#RandomInteger(1,10)", + "startEpochMicrosec": "#TimestampPrimitive", + "lastEpochMicrosec": "#TimestampPrimitive", + "version": 1.0 + }, + "measurementsForVfScalingFields": { + "measurementsForVfScalingFieldsVersion": 2.0, + "measurementsForVfScalingVersion": 2.0, + "measurementInterval": 180, + "concurrentSessions": 2, + "requestRate": "#RandomPrimitiveInteger(50,100)", + "meanRequestLatency": "#RandomPrimitiveInteger(1,1000)", + "cpuUsageArray": [ + { + "cpuIdentifier": "INTEL_CORE_I7_1", + "percentUsage": "#RandomPrimitiveInteger(1,100)" + }, + { + "cpuIdentifier": "INTEL_CORE_I7_2", + "percentUsage": "#RandomPrimitiveInteger(1,100)" + } + ], + "memoryUsageArray": [ + { + "vmIdentifier": "vmIdentifier", + "memoryFree": 50, + "memoryUsed": 10 + } + ], + "numberOfMediaPortsInUse": 100, + "additionalMeasurements": [ + ] + } + } +} diff --git a/test/mocks/pnfsimulator/pnfsimulator/templates/notification.json b/test/mocks/pnfsimulator/pnfsimulator/templates/notification.json new file mode 100644 index 000000000..5657a5052 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/templates/notification.json @@ -0,0 +1,40 @@ +{ + "event": { + "commonEventHeader": { + "domain": "notification", + "eventName": "vFirewallBroadcastPackets", + "eventId": "4cfc-91cf-31a46", + "priority": "Normal", + "reportingEntityName": "myVNF", + "sequence": 1, + "sourceName": "ClosedLoopVNF", + "startEpochMicrosec": 1531616794, + "lastEpochMicrosec": 1531719042, + "vesEventListenerVersion": "7.0.1", + "version": "4.0.1" + }, + "notificationFields": { + "changeIdentifier": "PM_MEAS_FILES", + "changeType": "FileReady", + "arrayOfNamedHashMap": [{ + "name": "A20161221.1031-1041.bin.gz", + "hashMap": { + "fileformatType": "org.3GPP.32.435#measCollec", + "fileFormatVersion": "V10", + "location": "ftpes://192.169.0.1:22/ftp/rop/A20161224.1030-1045.bin.gz", + "compression": "gzip" + } + }, { + "name": "A20161222.1042-1102.bin.gz", + "hashMap": { + "fileFormatType": "org.3GPP.32.435#measCollec", + "fileFormatVersion": "V10", + "location": "ftpes://192.168.0.102:22/ftp/rop/A20161224.1045-1100.bin.gz", + "compression": "gzip" + } + }], + "notificationFieldsVersion": "2.0" + } + + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pnfsimulator/templates/registration.json b/test/mocks/pnfsimulator/pnfsimulator/templates/registration.json new file mode 100644 index 000000000..5a3261fa5 --- /dev/null +++ b/test/mocks/pnfsimulator/pnfsimulator/templates/registration.json @@ -0,0 +1,33 @@ +{ + "event": { + "commonEventHeader": { + "eventId": "registration_39239592", + "eventType": "pnfRegistration", + "reportingEntityName": "NOK6061ZW3", + "domain": "pnfRegistration", + "nfcNamingCode": "oam", + "sequence": 0, + "sourceId": "val13", + "internalHeaderFields": {}, + "priority": "Normal", + "sourceName": "NOK6061ZW3", + "eventName": "pnfRegistration_Nokia_5gDu", + "version": "4.0.1", + "nfNamingCode": "gNB", + "startEpochMicrosec": 1539239592379, + "vesEventListenerVersion": "7.0.1", + "lastEpochMicrosec": 1539239592379 + }, + "pnfRegistrationFields": { + "pnfRegistrationFieldsVersion":"2.0", + "serialNumber": "6061ZW3", + "vendorName": "Nokia", + "oamV4IpAddress": "val3", + "oamV6IpAddress": "val4", + "unitFamily": "BBU", + "modelNumber": "val6", + "softwareVersion": "val7", + "unitType": "val8" + } + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/pom.xml b/test/mocks/pnfsimulator/pom.xml index 254cc8e0b..adc2bd582 100644 --- a/test/mocks/pnfsimulator/pom.xml +++ b/test/mocks/pnfsimulator/pom.xml @@ -1,339 +1,76 @@ <?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + Simulator + ================================================================================ + Copyright (C) 2019 Nokia. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at -<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> + http://www.apache.org/licenses/LICENSE-2.0 - <parent> - <groupId>org.onap.oparent</groupId> - <artifactId>oparent</artifactId> - <version>1.2.1</version> - </parent> + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= + --> - <groupId>org.onap.pnfsimulator</groupId> - <artifactId>pnf-simulator</artifactId> - <version>4.0.0-SNAPSHOT</version> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <packaging>pom</packaging> - <name>pnf-simulator</name> + <parent> + <groupId>org.onap.oparent</groupId> + <artifactId>oparent</artifactId> + <version>2.0.0</version> + </parent> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <maven.compiler.source>1.8</maven.compiler.source> - <maven.compiler.target>1.8</maven.compiler.target> - <maven.build.timestamp.format>yyyyMMdd'T'HHmmss</maven.build.timestamp.format> + <groupId>org.onap.simulator</groupId> + <artifactId>simulator-parent</artifactId> + <version>5.0.0-SNAPSHOT</version> + <modules> + <module>pnfsimulator</module> + <module>netconfsimulator</module> + </modules> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> - <simulator.main.class>org.onap.pnfsimulator.Main</simulator.main.class> - <docker.image.tag>latest</docker.image.tag> - <junit.jupiter.version>5.1.0</junit.jupiter.version> - <junit.vintage.version>5.1.0</junit.vintage.version> - <docker.image.name>onap/${project.artifactId}</docker.image.name> + <profiles> + <profile> + <id>tests</id> + <activation> + <activeByDefault>false</activeByDefault> + </activation> + <modules> + <module>pnfsimulator/integration</module> + </modules> + </profile> + </profiles> - <dependency.directory.name>libs</dependency.directory.name> - <dependency.directory.location>${project.build.directory}/${dependency.directory.name} - </dependency.directory.location> - - <onap.nexus.dockerregistry.daily>nexus3.onap.org:10003</onap.nexus.dockerregistry.daily> - </properties> - - <dependencies> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter</artifactId> - <version>2.0.2.RELEASE</version> - <exclusions> - <exclusion> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-logging</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> - <version>2.0.2.RELEASE</version> - </dependency> - <dependency> - <groupId>ch.qos.logback</groupId> - <artifactId>logback-classic</artifactId> - <version>1.2.3</version> - </dependency> - <dependency> - <groupId>ch.qos.logback</groupId> - <artifactId>logback-core</artifactId> - <version>1.2.3</version> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - <version>1.7.25</version> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>2.6</version> - </dependency> - <dependency> - <groupId>org.json</groupId> - <artifactId>json</artifactId> - <version>20180130</version> - </dependency> - <dependency> - <groupId>org.everit.json</groupId> - <artifactId>org.everit.json.schema</artifactId> - <version>1.3.0</version> - </dependency> - <dependency> - <groupId>com.github.fge</groupId> - <artifactId>json-schema-validator</artifactId> - <version>2.2.6</version> - </dependency> - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - <version>2.8.2</version> - </dependency> - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - <version>4.5.5</version> - </dependency> - <dependency> - <groupId>com.google.guava</groupId> - <artifactId>guava</artifactId> - <version>21.0</version> - </dependency> - <dependency> - <groupId>commons-cli</groupId> - <artifactId>commons-cli</artifactId> - <version>1.4</version> - </dependency> - <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - <version>3.7</version> - </dependency> - <dependency> - <groupId>org.onosproject</groupId> - <artifactId>jnc</artifactId> - <version>1.0</version> - </dependency> - - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-engine</artifactId> - <version>5.1.1</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-migrationsupport</artifactId> - <version>${junit.jupiter.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.9.1</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.apache.sshd</groupId> - <artifactId>sshd-core</artifactId> - <version>0.9.0</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>2.18.3</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-test</artifactId> - <version>5.0.4.RELEASE</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-test</artifactId> - <version>2.0.1.RELEASE</version> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-assembly-plugin</artifactId> - <configuration> - <descriptor>src/assembly/resources.xml</descriptor> - <finalName>${project.artifactId}-${project.version}</finalName> - </configuration> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.7.0</version> - <configuration> - <source>${maven.compiler.source}</source> - <target>${maven.compiler.target}</target> - <showWarnings>true</showWarnings> - <showDeprecation>true</showDeprecation> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <version>3.0.2</version> - <configuration> - <archive> - <manifestEntries> - <Main-Class>${simulator.main.class}</Main-Class> - <Build-Time>${maven.build.timestamp}</Build-Time> - </manifestEntries> - </archive> - </configuration> - </plugin> - <plugin> - <groupId>pl.project13.maven</groupId> - <artifactId>git-commit-id-plugin</artifactId> - <version>2.2.4</version> - <executions> - <execution> - <id>get-commit-info</id> - <goals> - <goal>revision</goal> - </goals> - </execution> - </executions> - <configuration> - <dotGitDirectory>${project.basedir}/.git</dotGitDirectory> - <generateGitPropertiesFile>true</generateGitPropertiesFile> - <includeOnlyProperties>git.commit.id.abbrev</includeOnlyProperties> - </configuration> - </plugin> - <plugin> - <artifactId>maven-surefire-plugin</artifactId> - <version>2.19</version> - <dependencies> - <dependency> - <groupId>org.junit.platform</groupId> - <artifactId>junit-platform-surefire-provider</artifactId> - <version>1.1.1</version> - </dependency> - </dependencies> - <configuration> - <detail>true</detail> - <printSummary>true</printSummary> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-dependency-plugin</artifactId> - <configuration> - <outputDirectory>${dependency.directory.location}</outputDirectory> - <includeScope>runtime</includeScope> - <silent>true</silent> - </configuration> - <executions> - <execution> - <id>copy-external-dependencies</id> - <phase>package</phase> - <goals> - <goal>copy-dependencies</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>com.spotify</groupId> - <artifactId>docker-maven-plugin</artifactId> - <version>1.0.0</version> - <configuration> - <registryUrl>${onap.nexus.dockerregistry.daily}</registryUrl> - <imageName>${onap.nexus.dockerregistry.daily}/${docker.image.name}</imageName> - <forceTags>true</forceTags> - <imageTags> - <tag>${project.version}</tag> - <tag>${project.version}-${maven.build.timestamp}</tag> - </imageTags> - <baseImage>openjdk:8-jre-alpine</baseImage> - <cmd>java -cp ${dependency.directory.name}/*:${project.build.finalName}.jar ${simulator.main.class}</cmd> - <resources> - <resource> - <targetPath>${dependency.directory.name}</targetPath> - <directory>${dependency.directory.location}</directory> - </resource> - <resource> - <targetPath>/</targetPath> - <directory>${project.build.directory}</directory> - <include>${project.build.finalName}.jar</include> - </resource> - </resources> - <forceTags>true</forceTags> - </configuration> - </plugin> - <plugin> - <groupId>org.jacoco</groupId> - <artifactId>jacoco-maven-plugin</artifactId> - <version>0.8.1</version> - <configuration> - <excludes> - <exclude>org/onap/pnfsimulator/Main.class</exclude> - </excludes> - </configuration> - <executions> - <execution> - <id>default-prepare-agent</id> - <goals> - <goal>prepare-agent</goal> - </goals> - </execution> - <execution> - <id>report</id> - <phase>prepare-package</phase> - <goals> - <goal>report</goal> - </goals> - </execution> - <execution> - <id>check</id> - <goals> - <goal>check</goal> - </goals> - <configuration> - <rules> - <rule> - <element>CLASS</element> - <limits> - <limit> - <value>COVEREDRATIO</value> - <minimum>0.70</minimum> - </limit> - <limit> - <counter>BRANCH</counter> - <value>COVEREDRATIO</value> - <minimum>0.75</minimum> - </limit> - </limits> - </rule> - </rules> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> + <build> + <plugins> + <plugin> + <artifactId>maven-checkstyle-plugin</artifactId> + <version>2.17</version> + <configuration> + <suppressionsLocation>checkstyle-suppressions.xml</suppressionsLocation> + <suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression> + </configuration> + </plugin> + <plugin> + <groupId>com.spotify</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>1.1.1</version> + </plugin> + </plugins> + </build> </project> diff --git a/test/mocks/pnfsimulator/sftp/sftp-file.txt b/test/mocks/pnfsimulator/sftp/sftp-file.txt deleted file mode 100644 index 43f671212..000000000 --- a/test/mocks/pnfsimulator/sftp/sftp-file.txt +++ /dev/null @@ -1,2 +0,0 @@ -We are SFTP specialists. -Do you prefer chocolate or vanilia?
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/simulator-cli/.gitignore b/test/mocks/pnfsimulator/simulator-cli/.gitignore new file mode 100644 index 000000000..96a29d6e2 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/.gitignore @@ -0,0 +1,7 @@ +**/*.iml +**/.idea +**/target +**/__pycache__ +build/** +dist/** +pnf_simulator_cli.egg-info/**
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/simulator-cli/README.md b/test/mocks/pnfsimulator/simulator-cli/README.md new file mode 100644 index 000000000..5dc6f76b9 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/README.md @@ -0,0 +1,304 @@ +## PNF/NETCONF SIMULATOR CLI + +### Overview +Anytime you want to see a basic usage of a tool, you can run fully descriptive help using command: +``` +./{tool_name}.py -h # --help argument is also acceptable +``` + +#### PNF Simulator CLI +PNF Simulator CLI provides command line interface to remotely interact with running PNF Simulator. + +Using the PNF Simulator CLI user is able to trigger events, retrieve simulator's configuration and change default VES url stored +inside simulator. + +#### Netconf Simulator CLI +Dedicated tool to help with management of the Netconf Server is also available. + +Using the Netconf Simulator CLI user is able to retrieve simulator's cm history stored inside simulator as well as open the live session to actively listen for new configuration changes. + +### Requirements and installation +Requirements +* Python > 3.5 + +Installation: +* Go to directory containing setup.py and invoke `python setup.py install` +* Go to cli directory +* Add executable privilege to pnf_simulator.py and netconf_simulator.py (for example `chmod +x <path_to_pnf_simulator.py>`) + +### Pnf simulator +#### Usage +* [send](#send-action) +* [configure](#configure-action) +* [get-config](#get-config-action) +* [template](#template-action) +* [filter](#filter-templates-action) + + +#### Help +Invoke `pnf_simulator.py [send|configure|get-config] -h` to display help. + +##### Send Action +Send action allows user to trigger sending events from Simulator to VES Collector. + +*sending repeating events backed by template persisted in db +`usage: pnf_simulator.py send template [-h] --address ADDRESS --name NAME + [--patch PATCH] [--repeats REPEATS] + [--interval INTERVAL] + [--ves-server-url VES_SERVER_URL] [--verbose] +` + +Parameters +` --address ADDRESS` `IP address of simulator` +` --name NAME` `Name of template file which should be used as a base for event. + Cannot be used simultaneously with parameter: event.` +` --patch PATCH` `Json which should be merged into template to override parameters. + Acceptable format: valid json wrapped using single quotes (example:'{"abc":1}'). + Cannot be used simultaneously with parameter: event.` +` --repeats REPEATS` `Number of events to be send` +` --interval INTERVAL` `Interval between two consecutive events (in seconds)` +` --ves-server-url VES_SERVER_URL` `Well-formed URL which will override current VES endpoint stored in simulator's DB` +` --verbose` `Displays additional logs` + + +*sending event only once by passing path to file with complete event +`usage: pnf_simulator.py send event [-h] --address ADDRESS --filepath FILEPATH + [--ves-server-url VES_SERVER_URL] [--verbose] +` +Parameters +` --address ADDRESS` `IP address of simulator` +` --filepath FILEPATH` `Path to file with full, legitimate event that is to be send directly to VES only once. + This event is not associated with template and will not be persisted in db. + Cannot be used simultaneously with parameters: template and patch.` +` --ves-server-url VES_SERVER_URL` `Well-formed URL which will override current VES endpoint stored in simulator's DB` +` --verbose` `Displays additional logs` + +example content of file with complete event: +``` +{ + "commonEventHeader": { + "eventId": "#Timestamp", + "sourceName": "#Increment", + "version": 3.0 + } +} +``` + +##### Configure Action +Configure action allows user to change Simulator's configuration (VES Server URL) +`usage: pnf_simulator.py configure [-h] --address ADDRESS --ves-server-url + VES_SERVER_URL [--verbose] +` + +Parameters + +` --address ADDRESS` `IP address of simulator` +` --ves-server-url VES_SERVER_URL` `Well-formed URL which should be set as a default VES Server URL in simulator` +` --verbose` `Displays additional logs` + +##### Get Config Action +Get Config action allows user to retrieve actual Simulator's configuration +`usage: pnf_simulator.py get-config [-h] --address ADDRESS [--verbose] ` + +Parameters + +`--address ADDRESS` `IP address of simulator` +`--verbose` `Displays additional logs` + +##### Template Action +Template action allows user to: +* retrieve a single template by name +* list all available templates. +* upload template to PNF Simulator (can overwrite existing template) + +`usage: pnf_simulator.py template [-h] + (--list | --get-content NAME | --upload FILENAME) + [--override] --address ADDRESS [--verbose]` + +Parameters + +`--get-content NAME` `Gets the template by name` +`--list` `List all templates` +`--upload FILENAME [--override]` `Uploads the template given as FILENAME file. Optionally overrides any exisitng templates with matching filename` +`--address ADDRESS` `IP address of simulator` +`--verbose` `Displays additional logs` + +#### Filter Templates Action +Filter template action allows to search through templates in order to find names of those that satisfy given criteria. +Criteria are passed in JSON format, as key-values pairs. Relation between pairs with criteria is AND (all conditions must be satisfied by template to have it returned). +No searching for null values is supported. +Search expression must be valid JSON, thus no duplicate keys are allowed - user could specify the same parameter multiple times, but only last occurrence will be applied to query. + + +`usage: pnf_simulator.py filter [-h] + --criteria CRITERIA --address ADDRESS [--verbose]` + +Parameters +`--criteria CRITERIA` `Json with criteria as key-value pairs, where values can be one of following data types: string, integer, double, boolean. + Acceptable format: valid json wrapped using single quotes (example:'{"searchedInt":1}'). + Cannot be used simultaneously with parameter: event.` +`--address ADDRESS` `IP address of simulator` +`--verbose` `Displays additional logs` + + +### Netconf simulator +#### Usage +* [load-model](#load-model-action) +* [delete-model](#delete-model-action) +* [get-config](#get-config-action) +* [edit-config](#edit-config-action) +* [tailf](#tailf-action) +* [less](#less-action) +* [cm-history](#cm-history-action) + +#### Help +Invoke `netconf_simulator.py [tailf|less|cm-history] -h` to display help. + + +#### Load-model action +Loads to netconf server new YANG model that corresponds with schema passed as yang-model parameter, +assigns name specified in module-name and initializes model with startup configuration passed in config file. +`usage: netconf_simulator.py load-module [-h] --address ADDRESS ---module-name MODULE_NAME --yang-model YANG_MODEL_FILEPATH --config <XML_CONFIG_FILEPATH> [--verbose]` + +example YANG schema (file content for YANG_MODEL) +``` +Response status: 200 +module pnf-simulator { + namespace "http://nokia.com/pnf-simulator"; + prefix config; + container config { + config true; + leaf itemValue1 {type uint32;} + leaf itemValue2 {type uint32;} + leaf itemValue3 {type uint32;} + leaf-list allow-user { + type string; + ordered-by user; + description "A sample list of user names."; + } + } +} +``` + +example startup configuration (file content of XML_CONFIG) +``` +<config xmlns="http://nokia.com/pnf-simulator"> + <itemValue1>100</itemValue1> + <itemValue2>200</itemValue2> + <itemValue3>300</itemValue3> +</config> +``` + + +example output (without verbose flag): +``` +Response status: 200 +Successfully started +``` + +#### Delete-model action +Deletes a YANG model loaded in the netconf server. + +`usage: netconf_simulator.py delete-model [-h] --address ADDRESS --model-name + MODEL_NAME [--verbose]` + +Example output (without verbose flag): +``` +Response status: 200 +Successfully deleted +``` + +#### Get-config Action +Returns active running configurations. +By default it returns all running configurations. To retrieve one specific configuration (represented by _/'module_name':'container'_ ) user needs to pass module-name and container. +Example: +` +netconf_simulator.py get-config --address localhost --module-name pnf-simulator --container config +` + + +`usage: netconf_simulator.py get-config [-h] --address ADDRESS [--verbose] [--module-name MODULE-NAME] [--container CONTAINER]` + +example output (without verbose flag): +``` +Response status: 200 +<config xmlns="http://nokia.com/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>2781</itemValue1> + <itemValue2>3782</itemValue2> + <itemValue3>3333</itemValue3> +</config> +``` + +#### Edit-config Action +Modifies existing configuration (e.g. change parameter values, modify or remove parameter from model). +To edit configuration, netconf compliant XML file should be prepared and used as one of edit-config parameters. +`usage: netconf_simulator.py edit-config [-h] --address ADDRESS --config <XML_CONFIG_FILEPATH> [--verbose]` + +example - parameter values modification +file content: +``` +<config xmlns="http://nokia.com/pnf-simulator"> + <itemValue1>1</itemValue1> + <itemValue2>2</itemValue2> + <itemValue3>3</itemValue3> +</config> +``` + +example output (without verbose flag): +``` +Response status: 202 +<config xmlns="http://nokia.com/pnf-simulator" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> + <itemValue1>1</itemValue1> + <itemValue2>2</itemValue2> + <itemValue3>3</itemValue3> +</config> +``` + +##### Less Action +Less action allows user to watch historical configuration changes. +Size of the configuration changes list is limited to the 100 last cm events by default, but can be incresed/decresead using a 'limit' attribute. +`usage: netconf_simulator.py less [-h] --address ADDRESS [--limit LIMIT] [--verbose]` + +Output from the command can be easily piped into other tools like native less, more, etc. e.g.: +`netconf_simulator.py less --address 127.0.0.1 | less` + +Last known configuration is last printed to the output, so order of the printed configuration events complies with time when the configuration was stored inside the simulator. + +Parameters: + +`--address ADDRESS` - `IP address of simulator` + +`--limit LIMIT` - ` Number of configurations to print at output` + +`--verbose` - ` Displays additional logs` + +Single message is represented as a pair of timestamp in epoch format and suitable configuration entry. + +##### Tailf Action +Tailf action allows user to actively listen for new uploaded configuration changes. +Size of the historical configuration changes list is limited to the 10 last cm events. +`usage: netconf_simulator.py tailf [-h] --address ADDRESS [--verbose]` + +The listener can be easily terminated at anytime using `CTRL+C` shortcut. + +Parameters: + +`--address ADDRESS` - `IP address of simulator` + +`--verbose` - ` Displays additional logs` + +Single message is represented as a pair of timestamp in epoch format and suitable configuration entry. + +##### Cm-history Action +Cm-history action allows user to view list of all uploaded configuration changes. +`usage: netconf_simulator.py cm-history [-h] --address ADDRESS [--verbose]` + +Last known configuration is last printed to the output, so order of the printed configuration events complies with time when the configuration was stored inside the simulator. + +Parameters: + +`--address ADDRESS` - `IP address of simulator` + +`--verbose` - ` Displays additional logs` + +Single message is represented as a pair of timestamp in epoch format and suitable configuration entry. diff --git a/test/mocks/pnfsimulator/simulator-cli/cli/__init__.py b/test/mocks/pnfsimulator/simulator-cli/cli/__init__.py new file mode 100644 index 000000000..aa8b4f995 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/cli/__init__.py @@ -0,0 +1,19 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### diff --git a/test/mocks/pnfsimulator/simulator-cli/cli/client/__init__.py b/test/mocks/pnfsimulator/simulator-cli/cli/client/__init__.py new file mode 100644 index 000000000..aa8b4f995 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/cli/client/__init__.py @@ -0,0 +1,19 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### diff --git a/test/mocks/pnfsimulator/simulator-cli/cli/client/tailf_client.py b/test/mocks/pnfsimulator/simulator-cli/cli/client/tailf_client.py new file mode 100644 index 000000000..d1cb60d97 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/cli/client/tailf_client.py @@ -0,0 +1,59 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +import logging + +import websockets +import asyncio +import signal +import sys + + +class TailfClient(object): + + def __init__(self, url: str, verbose: bool = False) -> None: + self._url = url + self._is_running = False + self._connection = None + self.logger = logging.getLogger() + self.logger.setLevel(logging.DEBUG if verbose else logging.INFO) + signal.signal(signal.SIGINT, self._handle_keyboard_interrupt) + + def tailf_messages(self): + self._is_running = True + self.logger.debug("Attempting to connect to websocket server on %s", self._url) + asyncio.get_event_loop().run_until_complete( + self._tailf_messages() + ) + + async def _tailf_messages(self): + try: + async with websockets.connect(self._url) as connection: + self.logger.debug("Connection with %s established", self._url) + self._connection = connection + while self._is_running: + print(await self._connection.recv(), "\n") + except ConnectionRefusedError: + self.logger.error("Cannot establish connection with %s", self._url) + + def _handle_keyboard_interrupt(self, sig, frame): + self.logger.warning("CTR-C pressed, interrupting.") + self._is_running = False + sys.exit(0) diff --git a/test/mocks/pnfsimulator/simulator-cli/cli/data/logging.ini b/test/mocks/pnfsimulator/simulator-cli/cli/data/logging.ini new file mode 100644 index 000000000..8b2b40285 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/cli/data/logging.ini @@ -0,0 +1,20 @@ +[loggers] +keys=root + +[handlers] +keys=consoleHandler + +[formatters] +keys=simpleFormatter + +[logger_root] +level=DEBUG +handlers=consoleHandler + +[handler_consoleHandler] +class=StreamHandler +formatter=simpleFormatter +args=(sys.stdout,) + +[formatter_simpleFormatter] +format=%(message)s diff --git a/test/mocks/pnfsimulator/simulator-cli/cli/netconf_simulator.py b/test/mocks/pnfsimulator/simulator-cli/cli/netconf_simulator.py new file mode 100755 index 000000000..a3b3bf1de --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/cli/netconf_simulator.py @@ -0,0 +1,278 @@ +#!/usr/bin/env python3 +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +import argparse +import logging +import logging.config +import requests +import os +import sys +from requests import Response + +from cli.client.tailf_client import TailfClient + +TAILF_FUNC_ENDPOINT = "ws://{}:9000/netconf" +LESS_FUNC_ENDPOINT = "/store/less" +CM_HISTORY_ENDPOINT = "/store/cm-history" +GET_CONFIG_ENDPOINT = "/netconf/get" +MODEL_ENDPOINT = "/netconf/model/{}" +EDIT_CONFIG_ENDPOINT = "/netconf/edit-config" +logging.basicConfig() + +DEFAULT_EXTERNAL_SIM_PORT = 8080 +DEFAULT_INTERNAL_SIM_PORT = 9000 + + +class NetconfSimulatorClient(object): + def __init__(self, ip: str, protocol: str = 'http', port: int = DEFAULT_EXTERNAL_SIM_PORT, verbose: bool = False) -> None: + self._ip = ip + self._protocol = protocol + self._port = port + self._configure_logger(verbose) + self._verbose=verbose + + def tailf_like_func(self) -> None: + url = TAILF_FUNC_ENDPOINT.format(self._ip) + client = TailfClient(url, self._verbose) + client.tailf_messages() + + def get_cm_history(self) -> None: + self.logger.info("Attempting to retrieve all netconf configuration changes") + simulator_address = "{}://{}:{}{}".format(self._protocol, self._ip, self._port, CM_HISTORY_ENDPOINT) + self.logger.debug("Simulator address: %s", simulator_address) + try: + response = requests.get(simulator_address) + self._log_json_response(response) + except requests.ConnectionError: + self.logger.error("Failed to establish connection with {}".format(simulator_address)) + + def less_like_func(self, limit: int) -> None: + self.logger.info("Attempting to run less on CM change") + simulator_address = "{}://{}:{}{}".format(self._protocol, self._ip, self._port, LESS_FUNC_ENDPOINT) + parameters = {"offset": limit} if limit else None + self.logger.debug("Simulator address: %s", simulator_address) + try: + response = requests.get(url = simulator_address, params = parameters) + self._log_json_response(response) + except requests.ConnectionError: + self.logger.error("Failed to establish connection with {}".format(simulator_address)) + + def get_config(self, module_name: str=None, container:str=None)-> None: + self.logger.info("Attempting to run get-config") + simulator_address = self._create_get_endpoint(module_name, container) + self.logger.debug("Simulator address: %s", simulator_address) + try: + response = requests.get(simulator_address) + self._log_string_response(response) + except requests.ConnectionError: + self.logger.error("Failed to establish connection with {}".format(simulator_address)) + + def load_yang_model(self, module_name: str, yang_model_path: str, config_path: str) -> None: + self.logger.info( + "Attempting to load new yang model with its initial configuration") + simulator_address = "{}://{}:{}{}".format(self._protocol, self._ip, self._port, MODEL_ENDPOINT.format(module_name)) + files = {"yangModel": open(yang_model_path, "rb"), + "initialConfig": open(config_path, "rb")} + self.logger.debug("Simulator address: %s", simulator_address) + + try: + response = requests.post(simulator_address, files=files) + self._log_string_response(response) + except requests.ConnectionError: + self.logger.error("Failed to establish connection with {}".format(simulator_address)) + + def delete_yang_model(self, model_name: str) -> None: + self.logger.info( + "Attempting to delete a yang model") + simulator_address = "{}://{}:{}{}".format(self._protocol, self._ip, self._port, MODEL_ENDPOINT.format(model_name)) + self.logger.debug("Simulator address: %s", simulator_address) + + try: + response = requests.delete(simulator_address) + self._log_string_response(response) + except requests.ConnectionError: + self.logger.error("Failed to establish connection with {}".format(simulator_address)) + + def edit_config(self, new_config_path: str): + self.logger.info("Attempting to apply new configuration") + simulator_address = "{}://{}:{}{}".format(self._protocol, self._ip, self._port, EDIT_CONFIG_ENDPOINT) + files = {"editConfigXml": open(new_config_path,"rb")} + self.logger.debug("Simulator address: %s", simulator_address) + + try: + response = requests.post(simulator_address, files=files) + self._log_string_response(response) + except requests.ConnectionError: + self.logger.error("Failed to establish connection with {}".format(simulator_address)) + + def _log_json_response(self, response: Response) ->None: + self.logger.info("Response status: %d", response.status_code) + self.logger.info(" ----- HEAD -----") + for message in response.json(): + self.logger.info("{}: {}".format(str(message['timestamp']), message['configuration'])) + self.logger.info(" ----- END ------") + self.logger.debug(response.headers) + + def _configure_logger(self, verbose): + logging_conf = os.path.join(sys.prefix, 'logging.ini') + if os.path.exists(logging_conf): + logging.config.fileConfig(logging_conf) + else: + print("Couldn't find logging.ini, using default logger config") + self.logger = logging.getLogger() + self.logger.setLevel(logging.DEBUG if verbose else logging.INFO) + + def _log_string_response(self, response: Response)->None: + self.logger.info("Response status: %d", response.status_code) + self.logger.info(response.text) + self.logger.debug(response.headers) + + def _create_get_endpoint(self, module_name: str, container: str): + endpoint = "{}://{}:{}{}".format(self._protocol, self._ip, self._port, + GET_CONFIG_ENDPOINT) + if module_name and container: + endpoint = endpoint + "/{}/{}".format(module_name, container) + elif (not module_name and container) or (module_name and not container): + raise AttributeError( + "Both module_name and container must be present or absent") + return endpoint + +def create_argument_parser(): + parser = argparse.ArgumentParser(description="Netconf Simulator Command Line Interface. ") + subparsers = parser.add_subparsers(title="Available actions") + tailf_parser = subparsers.add_parser("tailf", + description="Method which allows user to view N last lines of configuration changes") + + __configure_tailf_like_parser(tailf_parser) + less_parser = subparsers.add_parser("less", description="Method which allows user to traverse configuration changes") + __configure_less_like_parser(less_parser) + cm_history_parser = subparsers.add_parser("cm-history", + description="Method which allows user to view all configuration changes") + __configure_cm_history_parser(cm_history_parser) + + load_model_parser = subparsers.add_parser("load-model") + __configure_load_model_parser(load_model_parser) + + delete_model_parser = subparsers.add_parser("delete-model") + __configure_delete_model_parser(delete_model_parser) + + get_config_parser = subparsers.add_parser("get-config") + __configure_get_config_parser(get_config_parser) + edit_config_parser = subparsers.add_parser("edit-config") + __configure_edit_config_parser(edit_config_parser) + return parser + + +def run_tailf(args): + client = NetconfSimulatorClient(args.address, verbose=args.verbose) + client.tailf_like_func() + + +def run_get_cm_history(args): + client = NetconfSimulatorClient(args.address, verbose=args.verbose, port=DEFAULT_INTERNAL_SIM_PORT) + client.get_cm_history() + + +def run_less(args): + client = NetconfSimulatorClient(args.address, verbose=args.verbose, port=DEFAULT_INTERNAL_SIM_PORT) + client.less_like_func(args.limit) + + +def run_load_model(args): + client = NetconfSimulatorClient(args.address, verbose=args.verbose, + port=DEFAULT_INTERNAL_SIM_PORT) + client.load_yang_model(args.module_name, args.yang_model, args.config) + + +def run_delete_model(args): + client = NetconfSimulatorClient(args.address, verbose=args.verbose, + port=DEFAULT_INTERNAL_SIM_PORT) + client.delete_yang_model(args.model_name) + + +def run_get_config(args): + client = NetconfSimulatorClient(args.address, verbose=args.verbose, port=DEFAULT_INTERNAL_SIM_PORT) + client.get_config(args.module_name, args.container) + + +def run_edit_config(args): + client = NetconfSimulatorClient(args.address, verbose=args.verbose, port=DEFAULT_INTERNAL_SIM_PORT) + client.edit_config(args.config) + + +def __configure_tailf_like_parser(tailf_func_parser): + tailf_func_parser.add_argument("--address", required=True, help="IP address of simulator") + tailf_func_parser.add_argument("--verbose", action='store_true', + help="Displays additional logs") + tailf_func_parser.set_defaults(func=run_tailf) + + +def __configure_less_like_parser(less_func_parser): + less_func_parser.add_argument("--address", required=True, help="IP address of simulator") + less_func_parser.add_argument("--limit", help="Limit of configurations to retrieve") + less_func_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + less_func_parser.set_defaults(func=run_less) + + +def __configure_cm_history_parser(cm_history_parser): + cm_history_parser.add_argument("--address", required=True, help="IP address of simulator") + cm_history_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + cm_history_parser.set_defaults(func=run_get_cm_history) + + +def __configure_load_model_parser(load_model_parser): + load_model_parser.add_argument("--address", required=True, help="IP address of simulator") + load_model_parser.add_argument("--module-name", required=True, help="Module name corresponding to yang-model") + load_model_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + load_model_parser.add_argument("--yang-model", required=True, help="Path to file with yang model") + load_model_parser.add_argument("--config", required=True, help="Path to file with initial xml config") + load_model_parser.set_defaults(func=run_load_model) + + +def __configure_delete_model_parser(delete_model_parser): + delete_model_parser.add_argument("--address", required=True, help="IP address of simulator") + delete_model_parser.add_argument("--model-name", required=True, help="YANG model name to delete") + delete_model_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + delete_model_parser.set_defaults(func=run_delete_model) + + +def __configure_get_config_parser(get_config_parser): + get_config_parser.add_argument("--address", required=True, help="IP address of simulator") + get_config_parser.add_argument("--verbose", action='store_true',help="Displays additional logs") + get_config_parser.add_argument("--module-name", help="Module name corresponding to yang-model", default=None) + get_config_parser.add_argument("--container", help="Container name corresponding to module name", default=None) + get_config_parser.set_defaults(func=run_get_config) + + +def __configure_edit_config_parser(edit_config_parser): + edit_config_parser.add_argument("--address", required=True, help="IP address of simulator") + edit_config_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + edit_config_parser.add_argument("--config", required=True, help="Path to file with xml config to apply") + edit_config_parser.set_defaults(func=run_edit_config) + + +if __name__ == "__main__": + argument_parser = create_argument_parser() + result = argument_parser.parse_args() + if hasattr(result, 'func'): + result.func(result) + else: + argument_parser.parse_args(['-h']) diff --git a/test/mocks/pnfsimulator/simulator-cli/cli/pnf_simulator.py b/test/mocks/pnfsimulator/simulator-cli/cli/pnf_simulator.py new file mode 100755 index 000000000..9176fd8e0 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/cli/pnf_simulator.py @@ -0,0 +1,374 @@ +#!/usr/bin/env python3 +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### +import argparse +import http.client +import json +import logging +import ntpath +from typing import Dict + +SEND_PERIODIC_EVENT_ENDPOINT = "/simulator/start" +SEND_ONE_TIME_EVENT_ENDPOINT = "/simulator/event" +CONFIG_ENDPOINT = "/simulator/config" +LIST_TEMPLATES_ENDPOINT = "/template/list" +GET_TEMPLATE_BY_NAME_ENDPOINT = "/template/get" +UPLOAD_TEMPLATE_NOFORCE = "/template/upload" +UPLOAD_TEMPLATE_FORCE = "/template/upload?override=true" +FILTER_TEMPLATES_ENDPOINT = "/template/search" + +logging.basicConfig() + + +class Messages(object): + OVERRIDE_VALID_ONLY_WITH_UPLOAD = "--override is valid only with --upload parameter" + + +class SimulatorParams(object): + def __init__(self, repeats: int = 1, interval: int = 1, ves_server_url: str = None) -> None: + self.repeats_count = repeats + self.repeats_interval = interval + self.ves_server_url = ves_server_url + + def to_json(self) -> Dict: + to_return = {"repeatCount": self.repeats_count, + "repeatInterval": self.repeats_interval} + if self.ves_server_url: + to_return["vesServerUrl"] = self.ves_server_url + return to_return + + def __repr__(self) -> str: + return str(self.to_json()) + + +class PersistedEventRequest(object): + def __init__(self, simulator_params: SimulatorParams, template: str, patch: Dict = None) -> None: + self.params = simulator_params + self.template = template + self.patch = patch or {} + + def to_json(self) -> Dict: + return {"simulatorParams": self.params, "templateName": self.template, + "patch": self.patch} + + def __repr__(self) -> str: + return str(self.to_json()) + + +class FullEventRequest(object): + def __init__(self, event_body: Dict, ves_server_url: str = None) -> None: + self.event_body = event_body + self.ves_server_url = ves_server_url or "" + + def to_json(self) -> Dict: + return {"vesServerUrl": self.ves_server_url, "event": self.event_body} + + def __repr__(self) -> str: + return str(self.to_json()) + + +class TemplateUploadRequest(object): + def __init__(self, template_name: str, template_body: Dict) -> None: + self.template_name = template_name + self.template_body = template_body + + def to_json(self) -> Dict: + return {"name": self.template_name, "template": self.template_body} + + def __repr__(self) -> str: + return str(self.to_json()) + + +class SimulatorClient(object): + def __init__(self, ip: str, port: int = 5000, verbose: bool = False) -> None: + self._ip = ip + self._port = port + self.logger = logging.getLogger() + self.logger.setLevel(logging.DEBUG if verbose else logging.INFO) + + def send_event(self, request: PersistedEventRequest) -> None: + connection = http.client.HTTPConnection(self._ip, self._port) + self.logger.info("Attempting to send event") + self.logger.debug("Simulator address: ip %s, port %s, endpoint %s", self._ip, self._port, SEND_PERIODIC_EVENT_ENDPOINT) + self.logger.debug("REQUEST %s", request) + + connection.request("POST", SEND_PERIODIC_EVENT_ENDPOINT, body=json.dumps(request, cls=RequestSerializer), + headers={"Content-Type": "application/json"}) + + response = connection.getresponse() + + self._log_response(response) + connection.close() + + def send_one_time_event(self, request: FullEventRequest) -> None: + connection = http.client.HTTPConnection(self._ip, self._port) + self.logger.info("Attempting to send one time event") + self.logger.debug("Simulator address: ip %s, port %s, endpoint %s", self._ip, self._port, SEND_ONE_TIME_EVENT_ENDPOINT) + self.logger.debug("REQUEST %s", request.to_json()) + + connection.request("POST", SEND_ONE_TIME_EVENT_ENDPOINT, body=json.dumps(request.to_json()), + headers={"Content-Type": "application/json"}) + + response = connection.getresponse() + + self._log_response(response) + connection.close() + + def get_configuration(self) -> None: + connection = http.client.HTTPConnection(self._ip, self._port) + self.logger.info("Attempting to retrieve Simulator configuration") + self.logger.debug("Simulator address: ip %s, port %s, endpoint %s", self._ip, self._port, CONFIG_ENDPOINT) + connection.request("GET", CONFIG_ENDPOINT) + response = connection.getresponse() + + self._log_response(response) + connection.close() + + def edit_configuration(self, ves_server_url: str) -> None: + connection = http.client.HTTPConnection(self._ip, self._port) + self.logger.info("Attempting to update Simulator configuration") + self.logger.debug("Simulator address: ip %s, port %s, endpoint %s", self._ip, self._port, CONFIG_ENDPOINT) + request = {"vesServerUrl": ves_server_url} + self.logger.debug("REQUEST %s", request) + connection.request("PUT", CONFIG_ENDPOINT, body=json.dumps(request), + headers={"Content-Type": "application/json"}) + + response = connection.getresponse() + + self._log_response(response) + connection.close() + + def _log_response(self, response: http.client.HTTPResponse): + self.logger.info("Response status: %s ", response.status) + self.logger.info(response.read().decode()) + self.logger.debug(response.headers) + + def list_templates(self): + connection = http.client.HTTPConnection(self._ip, self._port) + self.logger.info("Attempting to retrieve all templates") + self.logger.debug("Simulator address: ip %s, port %s, endpoint %s", self._ip, self._port, LIST_TEMPLATES_ENDPOINT) + connection.request("GET", LIST_TEMPLATES_ENDPOINT) + response = connection.getresponse() + + self._log_response(response) + connection.close() + + def get_template_by_name(self, name): + connection = http.client.HTTPConnection(self._ip, self._port) + endpoint = GET_TEMPLATE_BY_NAME_ENDPOINT + "/" + name + self.logger.info("Attempting to retrieve template by name: '%s'", name) + self.logger.debug("Simulator address: ip %s, port %s, endpoint %s", self._ip, self._port, endpoint) + connection.request("GET", endpoint) + response = connection.getresponse() + + self._log_response(response) + connection.close() + + def upload_template(self, template_request, force): + connection = http.client.HTTPConnection(self._ip, self._port) + endpoint = UPLOAD_TEMPLATE_FORCE if force else UPLOAD_TEMPLATE_NOFORCE + self.logger.info("Attempting to upload template: '%s'", template_request) + self.logger.debug("Simulator address: ip %s, port %s, endpoint %s", self._ip, self._port, endpoint) + connection.request("POST", endpoint, + body=json.dumps(template_request.to_json()), + headers={"Content-Type": "application/json"}) + response = connection.getresponse() + + self._log_response(response) + connection.close() + + def search_for_templates(self, filter_criteria: str): + connection = http.client.HTTPConnection(self._ip, self._port) + self.logger.debug("Simulator address: ip %s, port %s, endpoint %s", self._ip, self._port, FILTER_TEMPLATES_ENDPOINT) + filter_request = {"searchExpr": json.loads(filter_criteria)} + self.logger.debug("Filter criteria: %s", str(filter_criteria)) + connection.request("POST", FILTER_TEMPLATES_ENDPOINT, + body=json.dumps(filter_request), + headers={"Content-Type": "application/json"}) + response = connection.getresponse() + + self._log_response(response) + connection.close() + + +class RequestSerializer(json.JSONEncoder): + def default(self, o): + return o.to_json() if (isinstance(o, SimulatorParams) or isinstance(o, PersistedEventRequest)) else o + + + +def create_argument_parser(): + parser = argparse.ArgumentParser(description="PNF Simulator Command Line Interface. ") + subparsers = parser.add_subparsers(title="Available actions") + send_parser = subparsers.add_parser("send", + description="Method which allows user to trigger simulator to start sending " + "events. Available options: [template, event]") + + send_subparsers = send_parser.add_subparsers() + one_time_send_event_parser = send_subparsers.add_parser("event", description="Option for direct, one-time event sending to VES. This option does not require having corresponging template.") + __configure_one_time_send_parser(one_time_send_event_parser) + persisted_send_event_parser = send_subparsers.add_parser("template") + __configure_persisted_send_parser(persisted_send_event_parser) + + configure_parser = subparsers.add_parser("configure", description="Method which allows user to set new default " + "value for VES Endpoint") + __configure_config_parser(configure_parser) + + get_config_parser = subparsers.add_parser("get-config", + description="Method which allows user to view simulator configuration") + __configure_get_config_parser(get_config_parser) + + template_config_parser = subparsers.add_parser("template", description="Template management operations") + __configure_template_parser(template_config_parser) + + template_filter_parser = subparsers.add_parser("filter", description="Method for searching through templates to find those satisfying given criteria") + __configure_template_filter_parser(template_filter_parser) + + return parser + + +def _perform_send_action(args): + if (not args.interval and args.repeats) or (args.interval and not args.repeats): + raise Exception("Either both repeats and interval must be present or missing") + + client = SimulatorClient(args.address, verbose=args.verbose) + client.send_event(_create_scheduled_event_request(args)) + + +def _perform_one_time_send_action(args): + client = SimulatorClient(args.address, verbose=args.verbose) + client.send_one_time_event(_create_one_time_event_request(args.filepath, args.ves_server_url)) + + +def get_configuration(args): + client = SimulatorClient(args.address, verbose=args.verbose) + client.get_configuration() + + +def edit_configuration(args): + client = SimulatorClient(args.address, verbose=args.verbose) + client.edit_configuration(args.ves_server_url) + + +def perform_template_action(args): + client = SimulatorClient(args.address, verbose=args.verbose) + if args.list: + client.list_templates() + elif args.get_content: + client.get_template_by_name(args.get_content) + elif args.upload: + client.upload_template(_create_upload_template_request(args.upload), args.override) + elif args.force: + raise Exception(Messages.OVERRIDE_VALID_ONLY_WITH_UPLOAD) + + +def list_all_templates(args): + client = SimulatorClient(args.address, verbose=args.verbose) + client.list_templates() + + +def filter_templates(args): + client = SimulatorClient(args.address, verbose=args.verbose) + client.search_for_templates(args.criteria) + + +def _create_upload_template_request(template_filename): + with open(template_filename) as json_template: + template_body = json.load(json_template) + return TemplateUploadRequest(path_leaf(template_filename), template_body) + + +def _create_scheduled_event_request(args): + simulator_params = SimulatorParams(args.repeats, args.interval, args.ves_server_url) + return PersistedEventRequest(simulator_params, args.name, json.loads(args.patch) if args.patch else {}) + + +def _create_one_time_event_request(event_filename, ves_server_url): + with open(event_filename) as json_event: + event_body = json.load(json_event) + return FullEventRequest(event_body, ves_server_url) + + +def __configure_persisted_send_parser(send_parser): + send_parser.add_argument("--address", required=True, help="IP address of simulator") + send_parser.add_argument("--name", required=True, help="Name of template file which should be used as a base for event") + send_parser.add_argument("--patch", help="Json which should be merged into template to override parameters") + send_parser.add_argument("--repeats", help="Number of events to be send", type=int) + send_parser.add_argument("--interval", help="Interval between two consecutive events (in seconds)", type=int) + send_parser.add_argument("--ves_server_url", + help="Well-formed URL which will override current VES endpoint stored in simulator's DB") + send_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + send_parser.set_defaults(func=_perform_send_action) + + +def __configure_one_time_send_parser(send_parser): + send_parser.add_argument("--address", required=True, help="IP address of simulator") + send_parser.add_argument("--filepath", required=True, help="Name of file with complete event for direct sending.") + send_parser.add_argument("--ves_server_url", + help="Well-formed URL which will override current VES endpoint stored in simulator's DB") + send_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + send_parser.set_defaults(func=_perform_one_time_send_action) + + +def __configure_config_parser(config_parser): + config_parser.add_argument("--address", required=True, help="IP address of simulator") + config_parser.add_argument("--ves-server-url", required=True, + help="Well-formed URL which should be set as a default VES Server URL in simulator") + config_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + config_parser.set_defaults(func=edit_configuration) + + +def __configure_get_config_parser(get_config_parser): + get_config_parser.add_argument("--address", required=True, help="IP address of simulator") + get_config_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + get_config_parser.set_defaults(func=get_configuration) + + +def __configure_template_parser(template_config_parser): + group = template_config_parser.add_mutually_exclusive_group(required=True) + group.add_argument("--list", action='store_true', help="List all templates") + group.add_argument("--get-content", help="Gets the template by name") + group.add_argument("--upload", help="Uploads the template given in parameter file.") + + template_config_parser.add_argument("--override", action='store_true', help="Overwrites the template in case it exists.") + template_config_parser.add_argument("--address", required=True, help="IP address of simulator") + template_config_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + template_config_parser.set_defaults(func=perform_template_action) + + +def __configure_template_filter_parser(template_filter_parser): + template_filter_parser.add_argument("--criteria", required=True, help="Json string with key-value search criteria") + template_filter_parser.add_argument("--address", required=True, help="IP address of simulator") + template_filter_parser.add_argument("--verbose", action='store_true', help="Displays additional logs") + template_filter_parser.set_defaults(func=filter_templates) + + +def path_leaf(path): + head, tail = ntpath.split(path) + return tail or ntpath.basename(head) + + +if __name__ == "__main__": + argument_parser = create_argument_parser() + result = argument_parser.parse_args() + if hasattr(result, 'func'): + result.func(result) + else: + argument_parser.parse_args(['-h']) diff --git a/test/mocks/pnfsimulator/simulator-cli/requirements.txt b/test/mocks/pnfsimulator/simulator-cli/requirements.txt new file mode 100644 index 000000000..4f962defb --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/requirements.txt @@ -0,0 +1,23 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### +requests==2.20.1 +websockets==7.0 +asynctest +mock diff --git a/test/mocks/pnfsimulator/simulator-cli/setup.py b/test/mocks/pnfsimulator/simulator-cli/setup.py new file mode 100644 index 000000000..26578a047 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/setup.py @@ -0,0 +1,34 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### + +import setuptools + +setuptools.setup( + name="pnf_simulator_cli", + version="5.0.0", + description="Command line interface which allows to communicate with PNF SIMULATOR", + packages=setuptools.find_packages(), + data_files=['cli/data/logging.ini'], + classifiers=["Programming Language :: Python :: 3"], + install_requires=[ + 'requests==2.20.1', + 'websockets==7.0' + ] +) diff --git a/test/mocks/pnfsimulator/simulator-cli/tests/__init__.py b/test/mocks/pnfsimulator/simulator-cli/tests/__init__.py new file mode 100644 index 000000000..aa8b4f995 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/tests/__init__.py @@ -0,0 +1,19 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### diff --git a/test/mocks/pnfsimulator/simulator-cli/tests/resources/notification.json b/test/mocks/pnfsimulator/simulator-cli/tests/resources/notification.json new file mode 100644 index 000000000..bdba8ae59 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/tests/resources/notification.json @@ -0,0 +1,15 @@ +{ + "commonEventHeader": { + "domain": "notification", + "eventName": "#RandomString(20)", + "version": "4.0.1" + }, + "notificationFields": { + "arrayOfNamedHashMap": [{ + "name": "A20161221.1031-1041.bin.gz", + "hashMap": { + "fileformatType": "org.3GPP.32.435#measCollec" + } + }] + } +}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/simulator-cli/tests/test_netconf_simulator.py b/test/mocks/pnfsimulator/simulator-cli/tests/test_netconf_simulator.py new file mode 100644 index 000000000..46ce84623 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/tests/test_netconf_simulator.py @@ -0,0 +1,165 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### +import logging +import unittest +import os +from mock import patch + +from cli.netconf_simulator import create_argument_parser, NetconfSimulatorClient + + +class TestArgumentParser(unittest.TestCase): + + def test_should_properly_parse_edit_config_with_all_params(self): + parser = create_argument_parser() + args = parser.parse_args( + ['edit-config', '--address', '127.0.0.1', '--config', 'sample_path', + "--verbose"] + ) + + self.assertEqual(args.address, '127.0.0.1') + self.assertEqual(args.config, 'sample_path') + self.assertTrue(args.verbose) + + def test_should_properly_parse_load_yang_model(self): + parser = create_argument_parser() + + args = parser.parse_args( + ['load-model', '--address', '127.0.0.1', '--module-name', + 'sample_name', '--yang-model', 'sample_model', '--config', + 'sample_config', + "--verbose"] + ) + + self.assertEqual(args.address, '127.0.0.1') + self.assertEqual(args.config, 'sample_config') + self.assertEqual(args.yang_model, 'sample_model') + self.assertEqual(args.module_name, 'sample_name') + self.assertTrue(args.verbose) + + def test_should_properly_parse_delete_yang_model(self): + parser = create_argument_parser() + + args = parser.parse_args( + ['delete-model', '--address', '127.0.0.1', '--model-name', + 'sample_name', "--verbose"] + ) + + self.assertEqual(args.address, '127.0.0.1') + self.assertEqual(args.model_name, 'sample_name') + self.assertTrue(args.verbose) + + def test_should_properly_parse_get_config(self): + parser = create_argument_parser() + args = parser.parse_args( + ['get-config', '--address', '127.0.0.1', '--verbose'] + ) + + self.assertEqual(args.address, '127.0.0.1') + self.assertTrue(args.verbose) + + +class TestNetconfSimulatorClient(unittest.TestCase): + + @classmethod + def setUpClass(cls): + with open("example", "w+") as f: + f.write("sampleContent") + + @classmethod + def tearDownClass(cls): + os.remove("example") + + @patch('cli.netconf_simulator.requests') + @patch('cli.netconf_simulator.NetconfSimulatorClient._configure_logger') + def test_should_properly_get_config(self, logger, requests): + client = NetconfSimulatorClient('localhost') + client.logger = logging.getLogger() + + client.get_config() + + requests.get.assert_called_with('http://localhost:8080/netconf/get') + + @patch('cli.netconf_simulator.requests') + @patch('cli.netconf_simulator.NetconfSimulatorClient._configure_logger') + def test_should_properly_get_config_for_given_module(self, logger, requests): + client = NetconfSimulatorClient('localhost') + client.logger = logging.getLogger() + + client.get_config("module", "container") + + requests.get.assert_called_with('http://localhost:8080/netconf/get/module/container') + + @patch('cli.netconf_simulator.NetconfSimulatorClient._configure_logger') + def test_should_raise_exception_when_module_is_present_and_container_is_absent(self, logger): + client = NetconfSimulatorClient('localhost') + client.logger = logging.getLogger() + + with self.assertRaises(AttributeError) as context: + client.get_config(module_name="test") + + @patch('cli.netconf_simulator.NetconfSimulatorClient._configure_logger') + def test_should_raise_exception_when_module_is_absent_and_container_is_present(self, logger): + client = NetconfSimulatorClient('localhost') + client.logger = logging.getLogger() + + with self.assertRaises(AttributeError) as context: + client.get_config(container="test") + + @patch('cli.netconf_simulator.requests') + @patch('cli.netconf_simulator.NetconfSimulatorClient._configure_logger') + def test_should_properly_load_yang_model(self, logger, requests): + client = NetconfSimulatorClient('localhost') + client.logger = logging.getLogger() + + client.load_yang_model('sample_module_name', 'example', 'example') + + requests.post.assert_called() + + @patch('cli.netconf_simulator.requests') + @patch('cli.netconf_simulator.NetconfSimulatorClient._configure_logger') + def test_should_properly_delete_yang_model(self, logger, requests): + client = NetconfSimulatorClient('localhost') + client.logger = logging.getLogger() + + client.delete_yang_model('sample_model_name') + + requests.delete.assert_called() + + @patch('cli.netconf_simulator.requests') + @patch('cli.netconf_simulator.NetconfSimulatorClient._configure_logger') + def test_should_properly_edit_config(self, logger, requests): + client = NetconfSimulatorClient('localhost') + client.logger = logging.getLogger() + + client.edit_config('example') + + requests.post.assert_called() + + @patch('cli.netconf_simulator.requests') + @patch('cli.netconf_simulator.NetconfSimulatorClient._configure_logger') + def test_should_properly_run_less_like_mode(self, logger, requests): + client = NetconfSimulatorClient('localhost') + client.logger = logging.getLogger() + + client.less_like_func(100) + + requests.get.assert_called_with( + params={"offset": 100}, url="http://localhost:8080/store/less") diff --git a/test/mocks/pnfsimulator/simulator-cli/tests/test_pnf_simulator.py b/test/mocks/pnfsimulator/simulator-cli/tests/test_pnf_simulator.py new file mode 100644 index 000000000..50f220038 --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/tests/test_pnf_simulator.py @@ -0,0 +1,270 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### +import json +import os +import unittest +from http.client import HTTPResponse, HTTPConnection +from unittest import mock +from unittest.mock import patch, Mock + +from cli.pnf_simulator import SimulatorClient, FullEventRequest, Messages +from cli.pnf_simulator import create_argument_parser, SimulatorParams, PersistedEventRequest + + +class TestArgumentParser(unittest.TestCase): + + def test_should_properly_parse_send_template_action_with_all_params(self): + parser = create_argument_parser() + + result = parser.parse_args( + ['send', 'template', '--address', '127.0.0.1', "--name", 'sample_template', '--patch', '"{}"', '--repeats', '2', + "--interval", '5', '--verbose', '--ves_server_url', 'sample_url']) + + self.assertEqual(result.address, '127.0.0.1') + self.assertEqual(result.name, "sample_template") + self.assertEqual(result.patch, "\"{}\"") + self.assertEqual(result.repeats, 2) + self.assertEqual(result.interval, 5) + self.assertEqual(result.ves_server_url, 'sample_url') + self.assertTrue(result.verbose) + + def test_should_properly_parse_send_event_action_with_all_params(self): + parser = create_argument_parser() + + result = parser.parse_args( + ['send', 'event', '--address', '127.0.0.1', "--filepath", 'sample_filepath.json', '--verbose', '--ves_server_url', 'sample_url']) + + self.assertEqual(result.address, '127.0.0.1') + self.assertEqual(result.filepath, "sample_filepath.json") + self.assertEqual(result.ves_server_url, 'sample_url') + self.assertTrue(result.verbose) + + def test_should_properly_parse_configure_action_with_all_params(self): + parser = create_argument_parser() + result = parser.parse_args( + ['configure', '--address', '127.0.0.1', "--verbose", '--ves-server-url', 'sample_url'] + ) + + self.assertEqual(result.address, '127.0.0.1') + self.assertTrue(result.verbose) + self.assertEqual(result.ves_server_url, 'sample_url') + + def test_should_properly_parse_get_config_action_with_all_params(self): + parser = create_argument_parser() + result = parser.parse_args( + ['get-config', '--address', '127.0.0.1', '--verbose'] + ) + + self.assertEqual(result.address, '127.0.0.1') + self.assertTrue(result.verbose) + + def test_should_not_parse_arguments_when_mandatory_params_are_missing_for_template(self): + parser = create_argument_parser() + + with self.assertRaises(SystemExit) as context: + parser.parse_args(['send', 'template']) + self.assertTrue('the following arguments are required: --address, --name' in context.exception) + + def test_should_not_parse_arguments_when_mandatory_params_are_missing_for_event(self): + parser = create_argument_parser() + + with self.assertRaises(SystemExit) as context: + parser.parse_args(['send', 'event']) + self.assertTrue('the following arguments are required: --address, --filepath' in context.exception) + + def test_should_not_parse_arguments_when_mandatory_template_params_are_missing(self): + parser = create_argument_parser() + + with self.assertRaises(SystemExit) as context: + parser.parse_args(['template']) + self.assertTrue('one of the arguments --list --get-content is required' in context.exception) + + def test_should_not_parse_template_action_with_all_params(self): + parser = create_argument_parser() + with self.assertRaises(SystemExit) as context: + parser.parse_args( + ['template', '--address', '127.0.0.1', "--list", '--get-content', 'sample'] + ) + self.assertTrue('argument --get-content: not allowed with argument --list' in context.exception) + + def test_should_properly_parse_template_action_with_list_param(self): + parser = create_argument_parser() + result = parser.parse_args( + ['template', '--address', '127.0.0.1', "--list"] + ) + + self.assertTrue(result.list) + self.assertEqual(result.address, '127.0.0.1') + self.assertFalse(result.verbose) + + def test_should_properly_parse_template_action_with_get_content_param(self): + parser = create_argument_parser() + result = parser.parse_args( + ['template', '--address', '127.0.0.1', "--get-content", "sample"] + ) + + self.assertTrue(result.get_content) + self.assertEqual(result.address, '127.0.0.1') + self.assertFalse(result.verbose) + + def test_should_not_parse_template_action_with_empty_get_content_param(self): + parser = create_argument_parser() + with self.assertRaises(SystemExit) as context: + parser.parse_args( + ['template', '--address', '127.0.0.1', "--list", '--get-content'] + ) + self.assertTrue('argument --get-content: expected one argument' in context.exception) + + def test_should_not_parse_template_action_when_only_override_is_given(self): + parser = create_argument_parser() + with self.assertRaises(SystemExit) as context: + parser.parse_args( + ['template', '--address', '127.0.0.1', "--override"] + ) + self.assertTrue(Messages.OVERRIDE_VALID_ONLY_WITH_UPLOAD in context.exception) + + def test_should_parse_template_action_with_upload(self): + parser = create_argument_parser() + result = parser.parse_args( + ['template', '--address', '127.0.0.1', "--upload", "resources/notification.json"] + ) + + self.assertFalse(result.override) + self.assertEqual(result.upload, 'resources/notification.json') + + def test_should_parse_template_action_with_upload_and_override(self): + parser = create_argument_parser() + result = parser.parse_args( + ['template', '--address', '127.0.0.1', "--upload", "resources/notification.json", "--override"] + ) + + self.assertTrue(result.override) + self.assertEqual(result.upload, 'resources/notification.json') + + + def test_should_properly_parse_filter_templates_action_with_all_params(self): + parser = create_argument_parser() + + result = parser.parse_args( + ['filter', '--address', '127.0.0.1', '--criteria', '"{}"', '--verbose']) + + self.assertEqual(result.address, '127.0.0.1') + self.assertEqual(result.criteria, "\"{}\"") + self.assertTrue(result.verbose) + +class TestSimulatorClient(unittest.TestCase): + + @patch('cli.pnf_simulator.http.client.HTTPConnection') + def test_should_properly_send_event(self, http_connection): + request = self._create_request() + mocked_connection = Mock(HTTPConnection) + http_connection.return_value = mocked_connection + mocked_response = Mock(HTTPResponse) + mocked_connection.getresponse.return_value = mocked_response + mocked_response.status = '200' + mocked_response.headers = {} + + client = SimulatorClient('localhost') + client.send_event(request) + + mocked_connection.close.assert_called_with() + mocked_connection.request.assert_called_with('POST', '/simulator/start', + body=mock.ANY, + headers={'Content-Type': 'application/json'}) + + @patch('cli.pnf_simulator.http.client.HTTPConnection') + def test_should_properly_send_one_time_event(self, http_connection): + event_abs_filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)),"resources/notification.json") + request = self._create_one_time_request(event_abs_filepath) + mocked_connection = Mock(HTTPConnection) + http_connection.return_value = mocked_connection + mocked_response = Mock(HTTPResponse) + mocked_connection.getresponse.return_value = mocked_response + mocked_response.status = '202' + mocked_response.headers = {} + + client = SimulatorClient('localhost') + client.send_one_time_event(request) + + mocked_connection.close.assert_called_with() + mocked_connection.request.assert_called_with('POST', '/simulator/event', + body=mock.ANY, + headers={'Content-Type': 'application/json'}) + + @patch('cli.pnf_simulator.http.client.HTTPConnection') + def test_should_properly_update_configuration(self, http_connection): + mocked_connection = Mock(HTTPConnection) + http_connection.return_value = mocked_connection + mocked_response = Mock(HTTPResponse) + mocked_connection.getresponse.return_value = mocked_response + mocked_response.status = '200' + mocked_response.headers = {} + + client = SimulatorClient('localhost') + client.edit_configuration("sample_url") + + mocked_connection.close.assert_called_with() + mocked_connection.request.assert_called_with('PUT', '/simulator/config', + body=json.dumps({"vesServerUrl": "sample_url"}), + headers={'Content-Type': 'application/json'}) + + @patch('cli.pnf_simulator.http.client.HTTPConnection') + def test_should_properly_retrieve_configuration(self, http_connection): + mocked_connection = Mock(HTTPConnection) + http_connection.return_value = mocked_connection + mocked_response = Mock(HTTPResponse) + mocked_connection.getresponse.return_value = mocked_response + mocked_response.status = '200' + mocked_response.headers = {} + + client = SimulatorClient('localhost') + client.get_configuration() + mocked_connection.close.assert_called_with() + mocked_connection.request.assert_called_with('GET', '/simulator/config') + + + @patch('cli.pnf_simulator.http.client.HTTPConnection') + def test_should_properly_trigger_filter_template_action(self, http_connection): + request = '{"sampleSearchString": "sampleSearchValue"}' + mocked_connection = Mock(HTTPConnection) + http_connection.return_value = mocked_connection + mocked_response = Mock(HTTPResponse) + mocked_connection.getresponse.return_value = mocked_response + mocked_response.status = '200' + mocked_response.headers = {} + + client = SimulatorClient('localhost') + client.search_for_templates(request) + + mocked_connection.close.assert_called_with() + mocked_connection.request.assert_called_with('POST', '/template/search', + body=json.dumps({"searchExpr": {"sampleSearchString": "sampleSearchValue"}}), + headers={'Content-Type': 'application/json'}) + + + @classmethod + def _create_request(cls): + return PersistedEventRequest(SimulatorParams(), 'sample_template') + + @classmethod + def _create_one_time_request(cls, event_filepath): + with open(event_filepath) as json_event: + event_body = json.load(json_event) + return FullEventRequest(event_body, 'sample_url') diff --git a/test/mocks/pnfsimulator/simulator-cli/tests/test_tailf_client.py b/test/mocks/pnfsimulator/simulator-cli/tests/test_tailf_client.py new file mode 100644 index 000000000..da8bd624e --- /dev/null +++ b/test/mocks/pnfsimulator/simulator-cli/tests/test_tailf_client.py @@ -0,0 +1,47 @@ +### +# ============LICENSE_START======================================================= +# Simulator +# ================================================================================ +# Copyright (C) 2019 Nokia. All rights reserved. +# ================================================================================ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============LICENSE_END========================================================= +### +import unittest +import asynctest + +from cli.client.tailf_client import TailfClient + + +class TestTailfClient(unittest.TestCase): + + def __init__(self, methodName='runTest'): + super().__init__(methodName) + self._client = TailfClient('ws://localhost:9999') + + @asynctest.mock.patch('cli.client.tailf_client.websockets') + def test_should_connect_to_server_and_receive_message(self, websockets_mock): + recv_mock = asynctest.CoroutineMock(side_effect=self.interrupt) + aenter_mock = asynctest.MagicMock() + connection_mock = asynctest.MagicMock() + websockets_mock.connect.return_value = aenter_mock + aenter_mock.__aenter__.return_value = connection_mock + connection_mock.recv = recv_mock + + self._client.tailf_messages() + + recv_mock.assert_awaited_once() + + def interrupt(self): + self._client._is_running = False + return 'test' diff --git a/test/mocks/pnfsimulator/simulator.sh b/test/mocks/pnfsimulator/simulator.sh deleted file mode 100755 index 6b61e6b87..000000000 --- a/test/mocks/pnfsimulator/simulator.sh +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -COMPOSE_FILE_NAME=docker-compose.yml -NETOPEER_CONTAINER_NAME=netopeer -SIMULATOR_CONTAINER_NAME=pnf-simulator -SIMULATOR_PORT=5000 -SIMULATOR_START_URL=http://localhost:$SIMULATOR_PORT/simulator/start -SIMULATOR_STOP_URL=http://localhost:$SIMULATOR_PORT/simulator/stop -SIMULATOR_STATUS_URL=http://localhost:$SIMULATOR_PORT/simulator/status -RUNNING_COMPOSE_CONFIG=$COMPOSE_FILE_NAME - -function main(){ - - COMMAND=${1:-"help"} - - case $COMMAND in - "build") - build_image;; - "start") - start $COMPOSE_FILE_NAME;; - "start-dev") - start_netconf_server $COMPOSE_FILE_NAME;; - "stop") - stop;; - "run-simulator") - run_simulator;; - "stop-simulator") - stop_simulator;; - "status") - get_status;; - "clear-logs") - clear_logs;; - *) - print_help;; - esac -} - -function build_image(){ - if [ -f pom.xml ]; then - mvn clean package docker:build - else - echo "pom.xml file not found" - exit 1 - fi -} - -function set_vsftpd_file_owner() { - sudo chown root ./ftpes/vsftpd/configuration/vsftpd_ssl.conf -} - -function start_netconf_server() { - set_vsftpd_file_owner - docker-compose -f $1 up -d $NETOPEER_CONTAINER_NAME - echo - echo "NETCONF server container's logs:" - docker exec $NETOPEER_CONTAINER_NAME /bin/bash -c "sysrepoctl --install --yang=/netconf/\$NETCONF_MODEL.yang --owner=netconf:nogroup --permissions=777" - docker exec $NETOPEER_CONTAINER_NAME /bin/bash -c "sysrepocfg --import=/netconf/\$NETCONF_MODEL.data.xml --datastore=startup --format=xml --level=3 \$NETCONF_MODEL" - docker exec -d $NETOPEER_CONTAINER_NAME /bin/bash -c "/opt/dev/sysrepo/build/examples/application_example \$NETCONF_MODEL" - echo -} - -function start(){ - - if [[ $(running_containers) ]]; then - echo "Simulator containers are already up" - else - echo "Starting simulator containers using netconf model specified in config/netconf.env" - set_vsftpd_file_owner - archive_logs - start_netconf_server $1 - docker-compose -f $1 up -d $SIMULATOR_CONTAINER_NAME - RUNNING_COMPOSE_CONFIG=$1 - fi -} - -function running_containers(){ - docker-compose -f $COMPOSE_FILE_NAME ps -q -} - -function stop(){ - - if [[ $(running_containers) ]]; then - docker-compose -f $RUNNING_COMPOSE_CONFIG down - else - echo "Simulator containers are already down" - fi -} - -function run_simulator(){ -cat << EndOfMessage -Simulator response: -$(curl -s -X POST -H "Content-Type: application/json" -H "X-ONAP-RequestID: 123" -H "X-InvocationID: 456" -d @config/config.json $SIMULATOR_START_URL) -EndOfMessage -} - -function stop_simulator(){ -cat << EndOfMessage -Simulator response: -$(curl -s -X POST $SIMULATOR_STOP_URL) -EndOfMessage -} - -function get_status(){ - - if [[ $(running_containers) ]]; then - print_status - else - echo "Simulator containers are down" - fi -} - -function print_status(){ -cat << EndOfMessage -$(docker-compose -f $RUNNING_COMPOSE_CONFIG ps) - -Simulator response: -$(curl -s -X GET $SIMULATOR_STATUS_URL) -EndOfMessage -} - -function print_help(){ -cat << EndOfMessage -Available options: -build - locally builds simulator image from existing code -start - starts simulator and netopeer2 containers using remote simulator image and specified model name -start-dev - starts only netopeer2 container -run-simulator - starts sending PNF registration messages with parameters specified in config.json -stop-simulator - stop sending PNF registration messages -stop - stops both containers -status - prints simulator status -clear-logs - deletes log folder - -Starting simulation: - -- Setup environment with "./simulator.sh start". It will download required docker images from the internet and run them on docker machine -- To start the simulation use "./simulator.sh run-simulator", which will start sending PNF registration messages with parameters specified in config.json - -To stop simulation use "./simulator.sh stop-simulator" command. To check simulator's status use "./simulator.sh status". -If you want to change message parameters simply edit config.json, then start the simulation with "./simulator.sh run-simulator" again -Logs are written to logs/pnf-simulator.log. After each "start/start-dev" old log files are moved to the archive - -FOR DEVELOPERS -1. Build local simulator image using "./simulator.sh build" -2. Run containers with "./simulator.sh start-dev" - -If you change the source code you have to rebuild image with "./simulator.sh build" and run "./simulator.sh start/start-dev" again -EndOfMessage -} - -function archive_logs(){ - - if [ -d logs ]; then - echo "Moving log file to archive" - DIR_PATH=logs/archive/simulator[$(timestamp)] - mkdir -p $DIR_PATH - if [ -f logs/pnfsimulator.log ]; then - mv logs/pnfsimulator.log $DIR_PATH - fi - - if [ -f logs/*.xml ]; then - mv logs/*.xml $DIR_PATH - fi - - else - mkdir logs - fi -} - -function clear_logs(){ - - if [[ $(running_containers) ]]; then - echo "Cannot delete logs when simulator is running" - else - rm -rf logs - fi -} - -function timestamp(){ - date "+%Y-%m-%d_%T" -} - -main $@
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/assembly/resources.xml b/test/mocks/pnfsimulator/src/assembly/resources.xml deleted file mode 100644 index 470df7c46..000000000 --- a/test/mocks/pnfsimulator/src/assembly/resources.xml +++ /dev/null @@ -1,82 +0,0 @@ -<assembly> - <id>resources</id> - <formats> - <format>zip</format> - </formats> - - <fileSets> - <fileSet> - <includes> - <include>simulator.sh</include> - </includes> - <lineEnding>unix</lineEnding> - <fileMode>0755</fileMode> - </fileSet> - <fileSet> - <includes> - <include>docker-compose.yml</include> - </includes> - <lineEnding>unix</lineEnding> - <fileMode>0644</fileMode> - </fileSet> - <fileSet> - <directory>config</directory> - <outputDirectory>config</outputDirectory> - <includes> - <include>**/*</include> - </includes> - </fileSet> - <fileSet> - <directory>deployment</directory> - <outputDirectory>deployment</outputDirectory> - <includes> - <include>**/*</include> - </includes> - </fileSet> - <fileSet> - <directory>ftpes</directory> - <outputDirectory>ftpes</outputDirectory> - <includes> - <include>**/*</include> - </includes> - <fileMode>0644</fileMode> - - </fileSet> - <fileSet> - <directory>json_schema</directory> - <outputDirectory>json_schema</outputDirectory> - <includes> - <include>**/*</include> - </includes> - </fileSet> - <fileSet> - <directory>netconf</directory> - <outputDirectory>netconf</outputDirectory> - <includes> - <include>**/*</include> - </includes> - </fileSet> - <fileSet> - <directory>netopeer_tls_cfg</directory> - <outputDirectory>netopeer_tls_cfg</outputDirectory> - <includes> - <include>**/*</include> - </includes> - </fileSet> - <fileSet> - <directory>sftp</directory> - <outputDirectory>sftp</outputDirectory> - <includes> - <include>**/*</include> - </includes> - </fileSet> - <fileSet> - <directory>ssh</directory> - <outputDirectory>ssh</outputDirectory> - <includes> - <include>**/*</include> - </includes> - - </fileSet> - </fileSets> -</assembly>
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/JSONObjectFactory.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/JSONObjectFactory.java deleted file mode 100644 index 3ebf5674a..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/JSONObjectFactory.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.message; - -import static org.onap.pnfsimulator.message.MessageConstants.EVENT_ID; -import static org.onap.pnfsimulator.message.MessageConstants.INTERNAL_HEADER_FIELDS; -import static org.onap.pnfsimulator.message.MessageConstants.LAST_EPOCH_MICROSEC; -import static org.onap.pnfsimulator.message.MessageConstants.NOTIFICATION_FIELDS_VERSION; -import static org.onap.pnfsimulator.message.MessageConstants.NOTIFICATION_FIELDS_VERSION_VALUE; -import static org.onap.pnfsimulator.message.MessageConstants.PNF_LAST_SERVICE_DATE; -import static org.onap.pnfsimulator.message.MessageConstants.PNF_MANUFACTURE_DATE; -import static org.onap.pnfsimulator.message.MessageConstants.PNF_REGISTRATION_FIELDS_VERSION; -import static org.onap.pnfsimulator.message.MessageConstants.PNF_REGISTRATION_FIELDS_VERSION_VALUE; -import static org.onap.pnfsimulator.message.MessageConstants.PRIORITY; -import static org.onap.pnfsimulator.message.MessageConstants.PRIORITY_NORMAL; -import static org.onap.pnfsimulator.message.MessageConstants.SEQUENCE; -import static org.onap.pnfsimulator.message.MessageConstants.SEQUENCE_NUMBER; -import static org.onap.pnfsimulator.message.MessageConstants.START_EPOCH_MICROSEC; -import static org.onap.pnfsimulator.message.MessageConstants.VERSION; -import static org.onap.pnfsimulator.message.MessageConstants.VERSION_NUMBER; -import static org.onap.pnfsimulator.message.MessageConstants.VES_EVENT_LISTENER_VERSION; -import static org.onap.pnfsimulator.message.MessageConstants.VES_EVENT_LISTENER_VERSION_NUMBER; - -import org.json.JSONObject; - -final class JSONObjectFactory { - - static JSONObject generateConstantCommonEventHeader() { - JSONObject commonEventHeader = new JSONObject(); - long timestamp = System.currentTimeMillis(); - commonEventHeader.put(EVENT_ID, generateEventId()); - commonEventHeader.put(LAST_EPOCH_MICROSEC, timestamp); - commonEventHeader.put(PRIORITY, PRIORITY_NORMAL); - commonEventHeader.put(SEQUENCE, SEQUENCE_NUMBER); - commonEventHeader.put(START_EPOCH_MICROSEC, timestamp); - commonEventHeader.put(INTERNAL_HEADER_FIELDS, new JSONObject()); - commonEventHeader.put(VERSION, VERSION_NUMBER); - commonEventHeader.put(VES_EVENT_LISTENER_VERSION, VES_EVENT_LISTENER_VERSION_NUMBER); - return commonEventHeader; - } - - static JSONObject generatePnfRegistrationFields() { - JSONObject pnfRegistrationFields = new JSONObject(); - pnfRegistrationFields.put(PNF_REGISTRATION_FIELDS_VERSION, PNF_REGISTRATION_FIELDS_VERSION_VALUE); - pnfRegistrationFields.put(PNF_LAST_SERVICE_DATE, String.valueOf(System.currentTimeMillis())); - pnfRegistrationFields.put(PNF_MANUFACTURE_DATE, String.valueOf(System.currentTimeMillis())); - return pnfRegistrationFields; - } - - static JSONObject generateNotificationFields() { - JSONObject notificationFields = new JSONObject(); - notificationFields.put(NOTIFICATION_FIELDS_VERSION, NOTIFICATION_FIELDS_VERSION_VALUE); - return notificationFields; - } - - - static String generateEventId() { - String timeAsString = String.valueOf(System.currentTimeMillis()); - return String.format("registration_%s", - timeAsString.substring(timeAsString.length() - 11, timeAsString.length() - 3)); - } - - private JSONObjectFactory() { - - } - -} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageBuilder.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageBuilder.java deleted file mode 100644 index ef0b2fdd2..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageBuilder.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2019 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.message; - -import org.json.JSONObject; - -import static org.onap.pnfsimulator.message.MessageConstants.COMMON_EVENT_HEADER; -import static org.onap.pnfsimulator.message.MessageConstants.DOMAIN; -import static org.onap.pnfsimulator.message.MessageConstants.DOMAIN_NOTIFICATION; -import static org.onap.pnfsimulator.message.MessageConstants.DOMAIN_PNF_REGISTRATION; -import static org.onap.pnfsimulator.message.MessageConstants.EVENT; -import static org.onap.pnfsimulator.message.MessageConstants.EVENT_TYPE; -import static org.onap.pnfsimulator.message.MessageConstants.NOTIFICATION_FIELDS; -import static org.onap.pnfsimulator.message.MessageConstants.PNF_REGISTRATION_FIELDS; - -public final class MessageBuilder { - private JSONObject root; - private JSONObject event; - private JSONObject commonEventHeader; - - private MessageBuilder() { - } - - public static MessageBuilder withCommonEventHeaderParams(JSONObject commonEventHeaderParams) { - MessageBuilder builder = new MessageBuilder(); - builder.initializeBuilder(commonEventHeaderParams); - return builder; - } - - public MessageBuilder withNotificationParams(JSONObject notificationParams) { - JSONObject notificationFields = JSONObjectFactory.generateNotificationFields(); - merge(notificationParams, notificationFields); - commonEventHeader.put(DOMAIN, DOMAIN_NOTIFICATION); - event.put(NOTIFICATION_FIELDS, notificationFields); - return this; - } - - public MessageBuilder withPnfRegistrationParams(JSONObject pnfRegistrationParams) { - JSONObject pnfRegistrationFields = JSONObjectFactory.generatePnfRegistrationFields(); - merge(pnfRegistrationParams, pnfRegistrationFields); - commonEventHeader.put(DOMAIN, DOMAIN_PNF_REGISTRATION); - commonEventHeader.put(EVENT_TYPE, DOMAIN_PNF_REGISTRATION); - event.put(PNF_REGISTRATION_FIELDS, pnfRegistrationFields); - return this; - } - - public JSONObject build() { - return root; - } - - private void initializeBuilder(JSONObject commonEventHeaderParams) { - root = new JSONObject(); - event = new JSONObject(); - commonEventHeader = JSONObjectFactory.generateConstantCommonEventHeader(); - commonEventHeaderParams.toMap().forEach(commonEventHeader::put); - event.put(COMMON_EVENT_HEADER, commonEventHeader); - root.put(EVENT, event); - } - - private void merge(JSONObject source, JSONObject destination) { - source.toMap().forEach(destination::put); - } -} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageConstants.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageConstants.java deleted file mode 100644 index 95e8f69f3..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/message/MessageConstants.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.message; - -public final class MessageConstants { - - public static final String SIMULATOR_PARAMS = "simulatorParams"; - public static final String COMMON_EVENT_HEADER_PARAMS = "commonEventHeaderParams"; - public static final String PNF_REGISTRATION_PARAMS = "pnfRegistrationParams"; - public static final String NOTIFICATION_PARAMS = "notificationParams"; - - static final String COMMON_EVENT_HEADER = "commonEventHeader"; - static final String PNF_REGISTRATION_FIELDS = "pnfRegistrationFields"; - static final String NOTIFICATION_FIELDS = "notificationFields"; - static final String EVENT = "event"; - - //============================================================================================= - //Simulation parameters - public static final String VES_SERVER_URL = "vesServerUrl"; - public static final String TEST_DURATION = "testDuration"; - public static final String MESSAGE_INTERVAL = "messageInterval"; - - //============================================================================================= - //commonEventHeader - //parameters - static final String DOMAIN = "domain"; - static final String EVENT_ID = "eventId"; - static final String EVENT_TYPE = "eventType"; - static final String LAST_EPOCH_MICROSEC = "lastEpochMicrosec"; - static final String PRIORITY = "priority"; - static final String SEQUENCE = "sequence"; - static final String START_EPOCH_MICROSEC = "startEpochMicrosec"; - static final String INTERNAL_HEADER_FIELDS = "internalHeaderFields"; - static final String VERSION = "version"; - static final String VES_EVENT_LISTENER_VERSION = "vesEventListenerVersion"; - //constant values - static final int SEQUENCE_NUMBER = 0; - static final String VERSION_NUMBER = "4.0.1"; - static final String VES_EVENT_LISTENER_VERSION_NUMBER = "7.0.1"; - static final String PRIORITY_NORMAL = "Normal"; - - //============================================================================================= - //PNF registration - //parameters - static final String PNF_REGISTRATION_FIELDS_VERSION = "pnfRegistrationFieldsVersion"; - static final String PNF_LAST_SERVICE_DATE = "lastServiceDate"; - static final String PNF_MANUFACTURE_DATE = "manufactureDate"; - //constant values - static final String PNF_REGISTRATION_FIELDS_VERSION_VALUE = "2.0"; - static final String DOMAIN_PNF_REGISTRATION ="pnfRegistration"; - - //============================================================================================= - // Notifications - //parameters - static final String NOTIFICATION_FIELDS_VERSION = "notificationFieldsVersion"; - //constant values - static final String NOTIFICATION_FIELDS_VERSION_VALUE = "2.0"; - static final String DOMAIN_NOTIFICATION ="notification"; - - private MessageConstants() { - } - -} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfConfigurationCheckingTask.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfConfigurationCheckingTask.java deleted file mode 100644 index 2300d6492..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfConfigurationCheckingTask.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.netconfmonitor; - -import com.tailf.jnc.JNCException; -import java.io.IOException; -import java.util.TimerTask; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationCache; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationReader; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NetconfConfigurationCheckingTask extends TimerTask { - - private static final Logger LOGGER = LoggerFactory.getLogger(NetconfConfigurationCheckingTask.class); - - private final NetconfConfigurationReader reader; - private final NetconfConfigurationWriter writer; - private final NetconfConfigurationCache cache; - - public NetconfConfigurationCheckingTask(NetconfConfigurationReader reader, - NetconfConfigurationWriter writer, - NetconfConfigurationCache cache) { - this.reader = reader; - this.writer = writer; - this.cache = cache; - } - - @Override - public void run() { - try { - String currentConfiguration = reader.read(); - if (!currentConfiguration.equals(cache.getConfiguration())) { - LOGGER.info("Configuration has changed, new configuration:\n\n{}", currentConfiguration); - writer.writeToFile(currentConfiguration); - cache.update(currentConfiguration); - } - } catch (IOException | JNCException e) { - LOGGER.warn("Error during configuration reading: {}", e.getMessage()); - } - } -} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorService.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorService.java deleted file mode 100644 index 0e7ab257d..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorService.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.netconfmonitor; - -import com.tailf.jnc.JNCException; -import java.io.IOException; -import java.util.Timer; -import javax.annotation.PostConstruct; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationCache; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationReader; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class NetconfMonitorService { - private static final Logger LOGGER = LoggerFactory.getLogger(NetconfMonitorService.class); - private static final long timePeriod = 1000L; - private static final long startDelay = 0; - - private Timer timer; - private NetconfConfigurationReader reader; - private NetconfConfigurationWriter writer; - private NetconfConfigurationCache cache; - - @Autowired - public NetconfMonitorService(Timer timer, - NetconfConfigurationReader reader, - NetconfConfigurationWriter writer, - NetconfConfigurationCache cache) { - this.timer = timer; - this.reader = reader; - this.writer = writer; - this.cache = cache; - } - - @PostConstruct - public void start() { - setStartConfiguration(); - NetconfConfigurationCheckingTask task = new NetconfConfigurationCheckingTask(reader, writer, cache); - timer.scheduleAtFixedRate(task, startDelay, timePeriod); - } - - private void setStartConfiguration() { - try { - String configuration = reader.read(); - writer.writeToFile(configuration); - cache.update(configuration); - } catch (IOException | JNCException e) { - LOGGER.warn("Error during configuration reading: {}", e.getMessage()); - } - } -} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceConfiguration.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceConfiguration.java deleted file mode 100644 index b0965d42b..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceConfiguration.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.netconfmonitor; - -import com.tailf.jnc.JNCException; -import com.tailf.jnc.NetconfSession; -import com.tailf.jnc.SSHConnection; -import com.tailf.jnc.SSHSession; -import java.io.IOException; -import java.util.Map; -import java.util.Timer; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationCache; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationReader; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationWriter; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConnectionParams; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class NetconfMonitorServiceConfiguration { - - private static final Logger LOGGER = LoggerFactory.getLogger(NetconfMonitorServiceConfiguration.class); - private static final Map<String, String> enviroment = System.getenv(); - - private static final String LOG_PATH = "/var/log"; - - private static final String NETCONF_ADDRESS = "NETCONF_ADDRESS"; - private static final String NETCONF_PORT = "NETCONF_PORT"; - private static final String NETCONF_MODEL = "NETCONF_MODEL"; - private static final String NETCONF_MAIN_CONTAINER = "NETCONF_MAIN_CONTAINER"; - - private static final String DEFAULT_NETCONF_ADDRESS = "localhost"; - private static final int DEFAULT_NETCONF_PORT = 830; - private static final String DEFAULT_NETCONF_MODEL = "pnf-simulator"; - private static final String DEFAULT_NETCONF_MAIN_CONTAINER = "config"; - - private static final String DEFAULT_NETCONF_USER = "netconf"; - private static final String DEFAULT_NETCONF_PASSWORD = "netconf"; - - @Bean - public Timer timer() { - return new Timer("NetconfMonitorServiceTimer"); - } - - @Bean - public NetconfConfigurationCache configurationCache() { - return new NetconfConfigurationCache(); - } - - @Bean - public NetconfConfigurationReader configurationReader() throws IOException, JNCException { - NetconfConnectionParams params = resolveConnectionParams(); - LOGGER.info("Configuration params are : {}", params); - NetconfSession session = createNetconfSession(params); - return new NetconfConfigurationReader(session, buildModelPath()); - } - - NetconfSession createNetconfSession(NetconfConnectionParams params) throws IOException, JNCException { - SSHConnection sshConnection = new SSHConnection(params.address, params.port); - sshConnection.authenticateWithPassword(params.user, params.password); - return new NetconfSession( new SSHSession(sshConnection)); - } - - @Bean - public NetconfConfigurationWriter netconfConfigurationWriter() { - return new NetconfConfigurationWriter(LOG_PATH); - } - - private String buildModelPath() { - return String.format("/%s:%s", - enviroment.getOrDefault(NETCONF_MODEL, DEFAULT_NETCONF_MODEL), - enviroment.getOrDefault(NETCONF_MAIN_CONTAINER, DEFAULT_NETCONF_MAIN_CONTAINER)); - } - - NetconfConnectionParams resolveConnectionParams() { - return new NetconfConnectionParams( - enviroment.getOrDefault(NETCONF_ADDRESS, DEFAULT_NETCONF_ADDRESS), - resolveNetconfPort(), - DEFAULT_NETCONF_USER, - DEFAULT_NETCONF_PASSWORD); - } - - private int resolveNetconfPort() { - try { - return Integer.parseInt(enviroment.get(NETCONF_PORT)); - } catch (NumberFormatException e) { - LOGGER.warn("Invalid netconf port: {}. Default netconf port {} is set.", e.getMessage(), - DEFAULT_NETCONF_PORT); - return DEFAULT_NETCONF_PORT; - } - } -} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationWriter.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationWriter.java deleted file mode 100644 index 40030796f..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationWriter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.netconfmonitor.netconf; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import org.onap.pnfsimulator.rest.util.DateUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class NetconfConfigurationWriter { - - private static final Logger LOGGER = LoggerFactory.getLogger(NetconfConfigurationWriter.class); - private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss"); - private String pathToLog; - - public NetconfConfigurationWriter(String pathToLog) { - this.pathToLog = pathToLog; - } - - public void writeToFile(String configuration) { - String fileName = String.format("%s/config[%s].xml", pathToLog, DateUtil.getTimestamp(dateFormat)); - try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) { - writer.write(configuration); - LOGGER.info("Configuration wrote to file {}/{} ", pathToLog, fileName); - } catch (IOException e) { - LOGGER.warn("Failed to write configuration to file: {}", e.getMessage()); - } - } -} diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java deleted file mode 100644 index 6b9f02622..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/rest/SimulatorController.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018-2019 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.rest; - -import com.github.fge.jsonschema.core.exceptions.ProcessingException; -import org.json.JSONException; -import org.json.JSONObject; -import org.onap.pnfsimulator.rest.util.DateUtil; -import org.onap.pnfsimulator.rest.util.ResponseBuilder; -import org.onap.pnfsimulator.simulator.Simulator; -import org.onap.pnfsimulator.simulator.SimulatorFactory; -import org.onap.pnfsimulator.simulator.validation.JSONValidator; -import org.onap.pnfsimulator.simulator.validation.ValidationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.UUID; - -import static org.onap.pnfsimulator.logging.MDCVariables.INSTANCE_UUID; -import static org.onap.pnfsimulator.logging.MDCVariables.INVOCATION_ID; -import static org.onap.pnfsimulator.logging.MDCVariables.REQUEST_ID; -import static org.onap.pnfsimulator.logging.MDCVariables.RESPONSE_CODE; -import static org.onap.pnfsimulator.logging.MDCVariables.SERVICE_NAME; -import static org.onap.pnfsimulator.logging.MDCVariables.X_INVOCATION_ID; -import static org.onap.pnfsimulator.logging.MDCVariables.X_ONAP_REQUEST_ID; -import static org.onap.pnfsimulator.message.MessageConstants.COMMON_EVENT_HEADER_PARAMS; -import static org.onap.pnfsimulator.message.MessageConstants.NOTIFICATION_PARAMS; -import static org.onap.pnfsimulator.message.MessageConstants.PNF_REGISTRATION_PARAMS; -import static org.onap.pnfsimulator.message.MessageConstants.SIMULATOR_PARAMS; -import static org.onap.pnfsimulator.rest.util.ResponseBuilder.MESSAGE; -import static org.onap.pnfsimulator.rest.util.ResponseBuilder.REMAINING_TIME; -import static org.onap.pnfsimulator.rest.util.ResponseBuilder.SIMULATOR_STATUS; -import static org.onap.pnfsimulator.rest.util.ResponseBuilder.TIMESTAMP; -import static org.springframework.http.HttpStatus.BAD_REQUEST; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; -import static org.springframework.http.HttpStatus.OK; - -@RestController -@RequestMapping("/simulator") -public class SimulatorController { - - private static final Logger LOGGER = LoggerFactory.getLogger(Simulator.class); - private static final DateFormat RESPONSE_DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss,SSS"); - private final Marker ENTRY = MarkerFactory.getMarker("ENTRY"); - private Simulator simulator; - private JSONValidator validator; - private SimulatorFactory factory; - - @Autowired - public SimulatorController(JSONValidator validator, SimulatorFactory factory) { - this.validator = validator; - this.factory = factory; - } - - @PostMapping("start") - public ResponseEntity start(@RequestHeader HttpHeaders headers, @RequestBody String message) { - MDC.put(REQUEST_ID, headers.getFirst(X_ONAP_REQUEST_ID)); - MDC.put(INVOCATION_ID, headers.getFirst(X_INVOCATION_ID)); - MDC.put(INSTANCE_UUID, UUID.randomUUID().toString()); - MDC.put(SERVICE_NAME, "/simulator/start"); - LOGGER.info(ENTRY, "Simulator starting"); - - if (isSimulatorRunning()) { - MDC.put(RESPONSE_CODE, BAD_REQUEST.toString()); - return ResponseBuilder - .status(BAD_REQUEST) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(MESSAGE, "Cannot start simulator since it's already running") - .build(); - } - - try { - validator.validate(message, "json_schema/input_validator.json"); - JSONObject root = new JSONObject(message); - JSONObject simulatorParams = root.getJSONObject(SIMULATOR_PARAMS); - JSONObject commonEventHeaderParams = root.getJSONObject(COMMON_EVENT_HEADER_PARAMS); - simulator = createSimulator(root, simulatorParams, commonEventHeaderParams); - simulator.start(); - - MDC.put(RESPONSE_CODE, OK.toString()); - return ResponseBuilder - .status(OK) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(MESSAGE, "Simulator started") - .build(); - - } catch (JSONException e) { - MDC.put(RESPONSE_CODE, BAD_REQUEST.toString()); - LOGGER.warn("Cannot start simulator, invalid json format: {}", e.getMessage()); - LOGGER.debug("Received json has invalid format", e); - return ResponseBuilder - .status(BAD_REQUEST) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(MESSAGE, "Cannot start simulator, invalid json format") - .build(); - - } catch (ProcessingException | ValidationException | IOException e) { - MDC.put(RESPONSE_CODE, BAD_REQUEST.toString()); - LOGGER.warn("Json validation failed: {}", e.getMessage()); - return ResponseBuilder - .status(BAD_REQUEST) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(MESSAGE, "Cannot start simulator - Json format is not compatible with schema definitions") - .build(); - - } catch (Exception e) { - MDC.put(RESPONSE_CODE, INTERNAL_SERVER_ERROR.toString()); - LOGGER.error("Cannot start simulator - unexpected exception", e); - return ResponseBuilder - .status(INTERNAL_SERVER_ERROR) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(MESSAGE, "Unexpected exception: " + e.getMessage()) - .build(); - } finally { - MDC.clear(); - } - } - - private Simulator createSimulator(JSONObject root, JSONObject simulatorParams, JSONObject commonEventHeaderParams) - throws ProcessingException, IOException, ValidationException { - JSONObject pnfRegistrationFields = root.optJSONObject(PNF_REGISTRATION_PARAMS); - JSONObject notificationFields = root.optJSONObject(NOTIFICATION_PARAMS); - if (pnfRegistrationFields != null && notificationFields == null) { - return factory.createSimulatorWithPnfRegistration(simulatorParams, commonEventHeaderParams, pnfRegistrationFields); - } else if (pnfRegistrationFields == null && notificationFields != null) { - return factory.createSimulatorWithNotification(simulatorParams, commonEventHeaderParams, notificationFields); - } else { - throw new ValidationException("Exactly one of pnfRegistrationFields or notificationFields should be present"); - } - } - - @GetMapping("status") - public ResponseEntity status() { - if (isSimulatorRunning()) { - ResponseBuilder responseBuilder = ResponseBuilder - .status(OK) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(SIMULATOR_STATUS, "RUNNING"); - - return !simulator.isEndless() ? - responseBuilder - .put(REMAINING_TIME, simulator.getRemainingTime()) - .build() : - responseBuilder - .build(); - } else { - return ResponseBuilder - .status(OK) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(SIMULATOR_STATUS, "NOT RUNNING") - .build(); - } - } - - @PostMapping("stop") - public ResponseEntity stop() { - if (isSimulatorRunning()) { - simulator.interrupt(); - - return ResponseBuilder - .status(OK) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(MESSAGE, "Simulator successfully stopped") - .build(); - } else { - return ResponseBuilder - .status(BAD_REQUEST) - .put(TIMESTAMP, DateUtil.getTimestamp(RESPONSE_DATE_FORMAT)) - .put(MESSAGE, "Cannot stop simulator, because it's not running") - .build(); - } - } - - private boolean isSimulatorRunning() { - return simulator != null && simulator.isAlive(); - } -} - diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/Simulator.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/Simulator.java deleted file mode 100644 index 854311709..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/Simulator.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.simulator; - -import java.time.Duration; -import java.time.Instant; -import java.util.Map; -import org.json.JSONObject; -import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; -import org.onap.pnfsimulator.simulator.client.HttpClientAdapterImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; - -public class Simulator extends Thread { - - private static final Logger LOGGER = LoggerFactory.getLogger(Simulator.class); - private final Marker EXIT = MarkerFactory.getMarker("EXIT"); - private Map<String,String> contextMap = MDC.getCopyOfContextMap(); - private boolean isEndless; - private String vesUrl; - private HttpClientAdapter httpClient; - private JSONObject messageBody; - private Duration duration; - private Duration interval; - private Instant endTime; - - private Simulator() { - } - - public static Builder builder() { - return new Builder(); - } - - public void run() { - setMdcContextMap(contextMap); - LOGGER.info("Simulation started - duration: {}, interval: {}s", getDuration(), interval.getSeconds()); - endTime = Instant.now().plus(duration); - while (isEndless || runningTimeNotExceeded()) { - try { - LOGGER.debug("Message to be sent:\n" + getMessage()); - httpClient.send(messageBody.toString(), vesUrl); - Thread.sleep(interval.toMillis()); - } catch (InterruptedException e) { - LOGGER.info("Simulation interrupted"); - return; - } - } - LOGGER.info(EXIT, "Simulation finished"); - MDC.clear(); - } - - private void setMdcContextMap(Map<String,String> mdcContextMap) { - if(mdcContextMap != null) - MDC.setContextMap(mdcContextMap); - } - - private String getMessage() { - return messageBody.toString(4); - } - - private String getDuration() { - return isEndless() ? "infinity" : duration.getSeconds() + "s"; - } - - private boolean runningTimeNotExceeded() { - return Instant.now().isBefore(endTime); - } - - public boolean isEndless() { - return isEndless; - } - - public long getRemainingTime() { - return Duration.between(Instant.now(), endTime).getSeconds(); - } - - public static class Builder { - - private String vesUrl; - private HttpClientAdapter httpClient; - private JSONObject messageBody; - private Duration duration; - private Duration interval; - - private Builder() { - this.vesUrl = ""; - this.httpClient = new HttpClientAdapterImpl(); - this.messageBody = new JSONObject(); - this.duration = Duration.ZERO; - this.interval = Duration.ZERO; - } - - public Builder withVesUrl(String vesUrl) { - this.vesUrl = vesUrl; - return this; - } - - public Builder withCustomHttpClientAdapter(HttpClientAdapter httpClient) { - this.httpClient = httpClient; - return this; - } - - public Builder withMessageBody(JSONObject messageBody) { - this.messageBody = messageBody; - return this; - } - - public Builder withDuration(Duration duration) { - this.duration = duration; - return this; - } - - - public Builder withInterval(Duration interval) { - this.interval = interval; - return this; - } - - public Simulator build() { - Simulator simulator = new Simulator(); - simulator.vesUrl = this.vesUrl; - simulator.httpClient = this.httpClient; - simulator.messageBody = this.messageBody; - simulator.duration = this.duration; - simulator.interval = this.interval; - simulator.isEndless = duration.equals(Duration.ZERO); - return simulator; - } - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorFactory.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorFactory.java deleted file mode 100644 index 8e16ad2ce..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/SimulatorFactory.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018-2019 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.simulator; - -import com.github.fge.jsonschema.core.exceptions.ProcessingException; -import org.json.JSONObject; -import org.onap.pnfsimulator.message.MessageProvider; -import org.onap.pnfsimulator.simulator.validation.JSONValidator; -import org.onap.pnfsimulator.simulator.validation.ValidationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.io.IOException; -import java.time.Duration; - -import static java.lang.Integer.parseInt; -import static org.onap.pnfsimulator.message.MessageConstants.MESSAGE_INTERVAL; -import static org.onap.pnfsimulator.message.MessageConstants.TEST_DURATION; -import static org.onap.pnfsimulator.message.MessageConstants.VES_SERVER_URL; - -@Service -public class SimulatorFactory { - - private static final String DEFAULT_OUTPUT_SCHEMA_PATH = "json_schema/output_validator_ves_schema_30.0.1.json"; - - private MessageProvider messageProvider; - private JSONValidator validator; - - @Autowired - public SimulatorFactory(MessageProvider messageProvider, JSONValidator validator) { - this.messageProvider = messageProvider; - this.validator = validator; - } - - public Simulator createSimulatorWithNotification(JSONObject simulatorParams, JSONObject commonEventHeaderParams, - JSONObject notificationParams) - throws ProcessingException, IOException, ValidationException { - JSONObject messageBody = messageProvider - .createMessageWithNotification(commonEventHeaderParams, notificationParams); - return createSimulatorWithMessage(simulatorParams, messageBody); - } - - public Simulator createSimulatorWithPnfRegistration(JSONObject simulatorParams, JSONObject commonEventHeaderParams, - JSONObject pnfRegistrationParams) - throws ProcessingException, IOException, ValidationException { - JSONObject messageBody = messageProvider - .createMessageWithPnfRegistration(commonEventHeaderParams, pnfRegistrationParams); - return createSimulatorWithMessage(simulatorParams, messageBody); - } - - private Simulator createSimulatorWithMessage(JSONObject simulatorParams, JSONObject messageBody) - throws ValidationException, ProcessingException, IOException { - Duration duration = Duration.ofSeconds(parseInt(simulatorParams.getString(TEST_DURATION))); - Duration interval = Duration.ofSeconds(parseInt(simulatorParams.getString(MESSAGE_INTERVAL))); - String vesUrl = simulatorParams.getString(VES_SERVER_URL); - validator.validate(messageBody.toString(), DEFAULT_OUTPUT_SCHEMA_PATH); - - return Simulator.builder() - .withVesUrl(vesUrl) - .withDuration(duration) - .withInterval(interval) - .withMessageBody(messageBody) - .build(); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/JSONValidator.java b/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/JSONValidator.java deleted file mode 100644 index 89135f9b4..000000000 --- a/test/mocks/pnfsimulator/src/main/java/org/onap/pnfsimulator/simulator/validation/JSONValidator.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.simulator.validation; - -import com.fasterxml.jackson.databind.JsonNode; -import com.github.fge.jackson.JsonLoader; -import com.github.fge.jsonschema.core.exceptions.ProcessingException; -import com.github.fge.jsonschema.core.report.LogLevel; -import com.github.fge.jsonschema.core.report.ProcessingMessage; -import com.github.fge.jsonschema.core.report.ProcessingReport; -import com.github.fge.jsonschema.main.JsonSchema; -import com.github.fge.jsonschema.main.JsonSchemaFactory; -import com.google.gson.JsonParser; -import java.io.FileReader; -import java.io.IOException; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -public class JSONValidator { - - public void validate(String data, String jsonSchemaPath) - throws ValidationException, ProcessingException, IOException { - String jsonSchema = readJsonSchemaAsString(jsonSchemaPath); - JsonNode jsonData = JsonLoader.fromString(data); - ProcessingReport report = createJsonSchema(jsonSchema).validate(jsonData); - - if (!report.isSuccess()) { - throw new ValidationException(constructValidationErrors(report)); - } - } - - private String readJsonSchemaAsString(String schemaPath) throws IOException { - try (FileReader reader = new FileReader(schemaPath)) { - return new JsonParser().parse(reader).toString(); - } - } - - private JsonSchema createJsonSchema(String schema) throws ProcessingException, IOException { - return JsonSchemaFactory.byDefault().getJsonSchema(JsonLoader.fromString(schema)); - } - - private String constructValidationErrors(ProcessingReport report) { - return StreamSupport.stream(report.spliterator(), false) - .filter(entry -> entry.getLogLevel() == LogLevel.ERROR) - .map(ProcessingMessage::getMessage) - .collect(Collectors.joining("\n")); - } -} diff --git a/test/mocks/pnfsimulator/src/main/resources/application.properties b/test/mocks/pnfsimulator/src/main/resources/application.properties deleted file mode 100644 index 888dcec44..000000000 --- a/test/mocks/pnfsimulator/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -server.port=5000
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/JSONObjectFactoryTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/JSONObjectFactoryTest.java deleted file mode 100644 index 4331195c9..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/JSONObjectFactoryTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.message; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.onap.pnfsimulator.message.MessageConstants.*; - -import org.json.JSONObject; -import org.junit.jupiter.api.Test; - -public class JSONObjectFactoryTest { - - @Test - public void generateConstantCommonEventHeader_shouldCreateProperly(){ - JSONObject commonEventHeader = JSONObjectFactory.generateConstantCommonEventHeader(); - assertEquals(8,commonEventHeader.toMap().size()); - assertTrue(commonEventHeader.has(EVENT_ID)); - assertTrue(commonEventHeader.has(LAST_EPOCH_MICROSEC)); - assertTrue(commonEventHeader.has(PRIORITY)); - assertTrue(commonEventHeader.has(SEQUENCE)); - assertTrue(commonEventHeader.has(START_EPOCH_MICROSEC)); - assertTrue(commonEventHeader.has(INTERNAL_HEADER_FIELDS)); - assertTrue(commonEventHeader.has(VERSION)); - assertEquals(commonEventHeader.get(PRIORITY),PRIORITY_NORMAL); - assertEquals(commonEventHeader.get(SEQUENCE),SEQUENCE_NUMBER); - assertEquals(commonEventHeader.get(VERSION),VERSION_NUMBER); - assertEquals(commonEventHeader.get(VES_EVENT_LISTENER_VERSION),VES_EVENT_LISTENER_VERSION_NUMBER); - } - - @Test - public void generateConstantPnfRegistrationFields_shouldCreateProperly(){ - JSONObject pnfRegistrationFields = JSONObjectFactory.generatePnfRegistrationFields(); - assertEquals(3,pnfRegistrationFields.toMap().size()); - assertTrue(pnfRegistrationFields.has(PNF_REGISTRATION_FIELDS_VERSION)); - assertEquals(pnfRegistrationFields.get(PNF_REGISTRATION_FIELDS_VERSION), PNF_REGISTRATION_FIELDS_VERSION_VALUE); - assertTrue(pnfRegistrationFields.has(PNF_LAST_SERVICE_DATE)); - assertTrue(pnfRegistrationFields.has(PNF_MANUFACTURE_DATE)); - } - - @Test - public void generateEventId_shouldCreateProperly(){ - String eventId = JSONObjectFactory.generateEventId(); - assertTrue(eventId.startsWith("registration_")); - } - - @Test - public void generateNotificationFields_shouldCreateProperly(){ - JSONObject notificationFields = JSONObjectFactory.generateNotificationFields(); - assertEquals(1,notificationFields.keySet().size()); - assertEquals(NOTIFICATION_FIELDS_VERSION_VALUE,notificationFields.get(NOTIFICATION_FIELDS_VERSION)); - - } - -} diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/MessageProviderTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/MessageProviderTest.java deleted file mode 100644 index 4524b96c3..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/message/MessageProviderTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018-2019 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.message; - -import org.json.JSONObject; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.onap.pnfsimulator.simulator.ResourceReader; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.data.MapEntry.entry; -import static org.onap.pnfsimulator.message.MessageConstants.COMMON_EVENT_HEADER; -import static org.onap.pnfsimulator.message.MessageConstants.EVENT; -import static org.onap.pnfsimulator.message.MessageConstants.NOTIFICATION_FIELDS; -import static org.onap.pnfsimulator.message.MessageConstants.PNF_REGISTRATION_FIELDS; - -public class MessageProviderTest { - - private static String testParamsPnfRegistration; - - private static String testParamsNotification; - - private MessageProvider messageProvider = new MessageProvider(); - - @BeforeAll - public static void setup() { - ResourceReader reader = new ResourceReader("org/onap/pnfsimulator/message/MessageProviderTest/"); - testParamsPnfRegistration = reader.readResource("pnfRegistrationParams.json"); - testParamsNotification = reader.readResource("notificationParams.json"); - } - - @Test - public void createMessageWithPnfRegistration_should_create_constant_message_when_no_params_specified() { - JSONObject message = messageProvider.createMessageWithPnfRegistration(new JSONObject(), new JSONObject()); - JSONObject event = message.getJSONObject(EVENT); - - JSONObject commonEventHeader = event.getJSONObject(COMMON_EVENT_HEADER); - JSONObject pnfRegistrationFields = event.getJSONObject(PNF_REGISTRATION_FIELDS); - - JSONObject expectedCommonEventHeader = JSONObjectFactory.generateConstantCommonEventHeader(); - JSONObject expectedPnfRegistrationFields = JSONObjectFactory.generatePnfRegistrationFields(); - - assertThat(commonEventHeader.keySet()) - .containsAll(expectedCommonEventHeader.keySet()); - assertThat(pnfRegistrationFields.keySet()) - .containsAll(expectedPnfRegistrationFields.keySet()); - } - - @Test - public void createMessageWithNotification_should_create_constant_message_when_no_params_specified() { - JSONObject message = messageProvider.createMessageWithNotification(new JSONObject(), - new JSONObject()); - JSONObject event = message.getJSONObject(EVENT); - - JSONObject commonEventHeader = event.getJSONObject(COMMON_EVENT_HEADER); - JSONObject notificationFields = event.getJSONObject(NOTIFICATION_FIELDS); - - JSONObject expectedCommonEventHeader = JSONObjectFactory.generateConstantCommonEventHeader(); - JSONObject expectedNotificationFields = JSONObjectFactory.generateNotificationFields(); - - assertThat(commonEventHeader.keySet()) - .containsAll(expectedCommonEventHeader.keySet()); - - assertThat(notificationFields.keySet()) - .containsAll(expectedNotificationFields.keySet()); - } - - @Test - public void createMessageWithPnfRegistration_should_add_specified_params_to_valid_subobjects() { - JSONObject message = messageProvider - .createMessageWithPnfRegistration(new JSONObject(), new JSONObject(testParamsPnfRegistration)); - JSONObject event = message.getJSONObject(EVENT); - - JSONObject commonEventHeader = event.getJSONObject(COMMON_EVENT_HEADER); - - JSONObject pnfRegistrationFields = event.getJSONObject(PNF_REGISTRATION_FIELDS); - assertThat(pnfRegistrationFields.toMap()).contains( - entry("pnfKey1", "pnfVal1"), - entry("pnfKey2", "pnfVal2"), - entry("pnfKey3", "pnfVal3"), - entry("pnfKey4", "pnfVal4") - ); - } - - @Test - public void createMessageWithNotification_should_add_specified_params_to_valid_subobjects() { - JSONObject message = messageProvider - .createMessageWithNotification(new JSONObject(), - new JSONObject(testParamsNotification)); - JSONObject event = message.getJSONObject(EVENT); - - JSONObject notificationFields = event.getJSONObject(NOTIFICATION_FIELDS); - assertThat(notificationFields.toMap()).contains( - entry("notKey1", "notVal1"), - entry("notKey2", "notVal2"), - entry("notKey3", "notVal3"), - entry("notKey4", "notVal4") - ); - - } - -} diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfConfigurationCheckingTaskTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfConfigurationCheckingTaskTest.java deleted file mode 100644 index 99cae00df..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfConfigurationCheckingTaskTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.netconfmonitor; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.tailf.jnc.JNCException; -import java.io.IOException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationCache; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationReader; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationWriter; - -class NetconfConfigurationCheckingTaskTest { - - private NetconfConfigurationCheckingTask checkingTask; - - @Mock - private NetconfConfigurationReader reader; - @Mock - private NetconfConfigurationWriter writer; - @Mock - private NetconfConfigurationCache cache; - - @BeforeEach - void setup() { - MockitoAnnotations.initMocks(this); - checkingTask = new NetconfConfigurationCheckingTask(reader, writer, cache); - } - - @Test - void run_should_update_configuration_when_changed() throws IOException, JNCException { - String configuration = "newConfiguration"; - when(reader.read()).thenReturn(configuration); - when(cache.getConfiguration()).thenReturn("oldConfiguration"); - - checkingTask.run(); - - verify(reader).read(); - verify(cache).getConfiguration(); - verify(writer).writeToFile(configuration); - verify(cache).update(configuration); - } - - @Test - void run_should_not_update_configuration_when_same() throws IOException, JNCException { - String configuration = "configuration"; - when(reader.read()).thenReturn(configuration); - when(cache.getConfiguration()).thenReturn("configuration"); - - checkingTask.run(); - - verify(reader).read(); - verify(cache).getConfiguration(); - verify(writer, never()).writeToFile(configuration); - verify(cache, never()).update(configuration); - } - - @Test - void run_should_not_take_any_action_when_failed_to_read_configuration() throws IOException, JNCException { - when(reader.read()).thenThrow(new IOException()); - - checkingTask.run(); - - verify(reader).read(); - verify(cache, never()).getConfiguration(); - verify(writer, never()).writeToFile(any()); - verify(cache, never()).update(any()); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceConfigurationTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceConfigurationTest.java deleted file mode 100644 index 02b8423f1..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceConfigurationTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.netconfmonitor; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import com.tailf.jnc.JNCException; -import com.tailf.jnc.NetconfSession; -import java.io.IOException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; - -class NetconfMonitorServiceConfigurationTest { - - private NetconfMonitorServiceConfiguration configuration; - - @Mock - private NetconfSession netconfSession; - - @BeforeEach - void setup() { - netconfSession = mock(NetconfSession.class); - configuration = spy(new NetconfMonitorServiceConfiguration()); - } - - @Test - void readNetconfConfiguration() throws IOException, JNCException { - doReturn(netconfSession).when(configuration).createNetconfSession(any()); - - assertNotNull(configuration.configurationReader()); - verify(configuration).createNetconfSession(any()); - } - - @Test - void configurationCacheIsNotNull() { - assertNotNull(configuration.configurationCache()); - } - - @Test - void netconfConfigurationWriterIsNotNull() { - assertNotNull(configuration.netconfConfigurationWriter()); - } - - @Test - void timerIsNotNull() { - assertNotNull(configuration.timer()); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceTest.java deleted file mode 100644 index 4f5da3309..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/NetconfMonitorServiceTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.netconfmonitor; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyLong; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.tailf.jnc.JNCException; -import java.io.IOException; -import java.util.Timer; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationCache; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationReader; -import org.onap.pnfsimulator.netconfmonitor.netconf.NetconfConfigurationWriter; - -class NetconfMonitorServiceTest { - - private NetconfMonitorService service; - - @Mock - private Timer timer; - @Mock - private NetconfConfigurationReader reader; - @Mock - private NetconfConfigurationWriter writer; - @Mock - private NetconfConfigurationCache cache; - - @BeforeEach - void setup() { - MockitoAnnotations.initMocks(this); - service = new NetconfMonitorService(timer, reader, writer, cache); - } - - @Test - void startNetconfService() throws IOException, JNCException { - when(reader.read()).thenReturn("message"); - doNothing().when(writer).writeToFile(anyString()); - doNothing().when(cache).update(anyString()); - - service.start(); - - verify(cache, times(1)).update(anyString()); - verify(writer, times(1)).writeToFile(anyString()); - verify(timer, times(1)).scheduleAtFixedRate(any(), anyLong(), anyLong()); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationWriterTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationWriterTest.java deleted file mode 100644 index 2baee21b7..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/netconfmonitor/netconf/NetconfConfigurationWriterTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.netconfmonitor.netconf; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport; -import org.junit.rules.TemporaryFolder; - -@EnableRuleMigrationSupport -class NetconfConfigurationWriterTest { - - private static final String TEST_CONFIGURATION = "test-configuration"; - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Test - void writeToFile_should_write_sample_config_when_directory_exists() throws IOException { - File file = temporaryFolder.newFolder("temp"); - NetconfConfigurationWriter configurationWriter = new NetconfConfigurationWriter(file.getPath()); - - configurationWriter.writeToFile(TEST_CONFIGURATION); - - File[] files = file.listFiles(); - assertEquals(1, files.length); - - String content = FileUtils.readFileToString(files[0], "UTF-8"); - assertEquals(TEST_CONFIGURATION, content); - } - - @Test - void writeToFile_should_not_write_config_when_directory_doesnt_exist() { - String logFolderPath = "/not/existing/logs"; - NetconfConfigurationWriter configurationWriter = new NetconfConfigurationWriter(logFolderPath); - - configurationWriter.writeToFile(TEST_CONFIGURATION); - - assertFalse(Files.exists(Paths.get(logFolderPath))); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java deleted file mode 100644 index bed67e33e..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/rest/SimulatorControllerTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018-2019 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.rest; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.onap.pnfsimulator.simulator.ResourceReader; -import org.onap.pnfsimulator.simulator.Simulator; -import org.onap.pnfsimulator.simulator.SimulatorFactory; -import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; -import org.onap.pnfsimulator.simulator.validation.JSONValidator; -import org.onap.pnfsimulator.simulator.validation.ValidationException; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.time.Duration; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -class SimulatorControllerTest { - - private static final String START_URL = "/simulator/start"; - private static final String STOP_URL = "/simulator/stop"; - private static final String STATUS_URL = "/simulator/status"; - private static final String JSON_MSG_EXPRESSION = "$.message"; - private static final String JSON_STATUS_EXPRESSION = "$.simulatorStatus"; - private static String pnfRegistrationJson; - private static String incorrectJson; - - private MockMvc mockMvc; - - @InjectMocks - private SimulatorController controller; - - @Mock - private SimulatorFactory factory; - - @Mock - private JSONValidator validator; - - private Simulator simulator; - - @BeforeAll - static void beforeAll() { - ResourceReader reader = new ResourceReader("org/onap/pnfsimulator/rest/SimulatorControllerTest/"); - pnfRegistrationJson = reader.readResource("pnfRegistration.json"); - incorrectJson = reader.readResource("incorrectJson.json"); - } - - @BeforeEach - void setup() { - MockitoAnnotations.initMocks(this); - simulator = createEndlessSimulator(); - mockMvc = MockMvcBuilders - .standaloneSetup(controller) - .build(); - } - - private Simulator createEndlessSimulator() { - return spy(Simulator.builder() - .withCustomHttpClientAdapter(mock(HttpClientAdapter.class)) - .withInterval(Duration.ofMinutes(1)) - .build()); - } - - @Test - void wrongJSONFormatOnStart() throws Exception { - when(factory.createSimulatorWithNotification(any(), any(), any())).thenReturn(simulator); - doThrow(new ValidationException("")).when(validator).validate(anyString(), anyString()); - - mockMvc.perform(post("/simulator/start").content(incorrectJson)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.message").value("Cannot start simulator - Json format " + - "is not compatible with schema definitions")); - verify(validator).validate(anyString(), anyString()); - } - - @Test - void startSimulatorProperly() throws Exception { - startSimulatorWithPnfRegistration(); - - verify(validator).validate(anyString(), anyString()); - verify(factory).createSimulatorWithPnfRegistration(any(), any(), any()); - verify(simulator).start(); - } - - @Test - void notStartWhenAlreadyRunning() throws Exception { - startSimulatorWithPnfRegistration(); - - mockMvc - .perform(post(START_URL).content(pnfRegistrationJson)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath(JSON_MSG_EXPRESSION).value("Cannot start simulator since it's already running")); - } - - @Test - void stopSimulatorWhenRunning() throws Exception { - startSimulatorWithPnfRegistration(); - - mockMvc - .perform(post(STOP_URL)) - .andExpect(status().isOk()) - .andExpect(jsonPath(JSON_MSG_EXPRESSION).value("Simulator successfully stopped")); - } - - @Test - void getNotRunningMessageWhenOff() throws Exception { - mockMvc - .perform(post(STOP_URL)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath(JSON_MSG_EXPRESSION).value("Cannot stop simulator, because it's not running")); - } - - @Test - void getRunningStatusWhenOn() throws Exception { - startSimulatorWithPnfRegistration(); - - mockMvc - .perform(get(STATUS_URL)) - .andExpect(status().isOk()) - .andExpect(jsonPath(JSON_STATUS_EXPRESSION).value("RUNNING")); - } - - @Test - void getNotRunningStatusWhenOff() throws Exception { - mockMvc - .perform(get(STATUS_URL)) - .andExpect(status().isOk()) - .andExpect(jsonPath(JSON_STATUS_EXPRESSION).value("NOT RUNNING")); - } - - private void startSimulatorWithPnfRegistration() throws Exception { - when(factory.createSimulatorWithPnfRegistration(any(), any(), any())).thenReturn(simulator); - - mockMvc - .perform(post(START_URL).content(pnfRegistrationJson)) - .andExpect(status().isOk()) - .andExpect(jsonPath(JSON_MSG_EXPRESSION).value("Simulator started")); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorFactoryTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorFactoryTest.java deleted file mode 100644 index 5781bbc0b..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorFactoryTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018-2019 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.simulator; - -import com.github.fge.jsonschema.core.exceptions.ProcessingException; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.jupiter.api.Test; -import org.onap.pnfsimulator.message.MessageProvider; -import org.onap.pnfsimulator.simulator.validation.JSONValidator; -import org.onap.pnfsimulator.simulator.validation.ValidationException; - -import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class SimulatorFactoryTest { - private static final ResourceReader resourceReader = new ResourceReader("org/onap/pnfsimulator/simulator/SimulatorFactoryTest/"); - - private static final JSONObject VALID_SIMULATOR_PARAMS = new JSONObject(resourceReader.readResource("validSimulatorParams.json")); - private static final JSONObject VALID_COMMON_EVENT_HEADER_PARAMS = new JSONObject(resourceReader.readResource("validCommonEventHeaderParams.json")); - private static final JSONObject VALID_PNF_REGISTRATION_PARAMS = new JSONObject(resourceReader.readResource("validPnfRegistrationParams.json")); - private static final JSONObject VALID_NOTIFICATION_PARAMS = new JSONObject(resourceReader.readResource("validNotificationParams.json")); - - private static final JSONObject INVALID_SIMULATOR_PARAMS = new JSONObject(resourceReader.readResource("invalidSimulatorParams.json")); - private static final JSONObject INVALID_PNF_REGISTRATION_PARAMS_1 = new JSONObject(resourceReader.readResource("invalidPnfRegistrationParams1.json")); - private static final JSONObject INVALID_PNF_REGISTRATION_PARAMS_2 = new JSONObject(resourceReader.readResource("invalidPnfRegistrationParams2.json")); - private static final JSONObject INVALID_PNF_REGISTRATION_PARAMS_3 = new JSONObject(resourceReader.readResource("invalidPnfRegistrationParams3.json")); - - private SimulatorFactory simulatorFactory = new SimulatorFactory(new MessageProvider(), new JSONValidator()); - - @Test - void should_successfully_create_simulator_given_valid_pnf_registration_params_and_valid_output_message() - throws ValidationException, IOException, ProcessingException { - assertNotNull(simulatorFactory.createSimulatorWithPnfRegistration(VALID_SIMULATOR_PARAMS, VALID_COMMON_EVENT_HEADER_PARAMS, - VALID_PNF_REGISTRATION_PARAMS)); - } - - @Test - void should_successfully_create_simulator_given_valid_notification_params_and_valid_output_message() - throws ValidationException, IOException, ProcessingException { - assertNotNull(simulatorFactory.createSimulatorWithNotification(VALID_SIMULATOR_PARAMS, VALID_COMMON_EVENT_HEADER_PARAMS, - VALID_NOTIFICATION_PARAMS)); - } - - @Test - void should_throw_given_invalid_params() { - assertThrows( - JSONException.class, - () -> simulatorFactory.createSimulatorWithPnfRegistration(INVALID_SIMULATOR_PARAMS, VALID_COMMON_EVENT_HEADER_PARAMS, - VALID_PNF_REGISTRATION_PARAMS)); - } - - @Test - void should_throw_given_valid_params_and_invalid_output_message() { - - assertThrows( - ValidationException.class, - () -> simulatorFactory.createSimulatorWithPnfRegistration(VALID_SIMULATOR_PARAMS, VALID_COMMON_EVENT_HEADER_PARAMS, - INVALID_PNF_REGISTRATION_PARAMS_1)); - - assertThrows( - ValidationException.class, - () -> simulatorFactory.createSimulatorWithPnfRegistration(VALID_SIMULATOR_PARAMS, VALID_COMMON_EVENT_HEADER_PARAMS, - INVALID_PNF_REGISTRATION_PARAMS_2)); - - assertThrows( - ValidationException.class, - () -> simulatorFactory.createSimulatorWithPnfRegistration(VALID_SIMULATOR_PARAMS, VALID_COMMON_EVENT_HEADER_PARAMS, - INVALID_PNF_REGISTRATION_PARAMS_3)); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorTest.java deleted file mode 100644 index db9dbd785..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/SimulatorTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.simulator; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTimeout; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.verify; - -import java.time.Duration; -import org.json.JSONObject; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; -import org.mockito.Mockito; -import org.onap.pnfsimulator.simulator.client.HttpClientAdapter; - -class SimulatorTest { - - private static final String TEST_VES_URL = "http://test-ves-url"; - - @Test - void builder_should_create_endless_simulator_when_duration_not_specified() { - Simulator simulator = Simulator - .builder() - .withDuration(Duration.ofSeconds(1)) - .withVesUrl(TEST_VES_URL).build(); - - assertFalse(simulator.isEndless()); - - simulator = Simulator - .builder() - .withVesUrl(TEST_VES_URL).build(); - - assertTrue(simulator.isEndless()); - } - - @Test - void simulator_should_send_given_message() { - - JSONObject messageBody = new JSONObject("{\"key\":\"val\"}"); - HttpClientAdapter httpClientMock = Mockito.mock(HttpClientAdapter.class); - - Simulator simulator = Simulator.builder() - .withDuration(Duration.ofMillis(100)) - .withInterval(Duration.ofMillis(10)) - .withMessageBody(messageBody) - .withCustomHttpClientAdapter(httpClientMock) - .withVesUrl(TEST_VES_URL).build(); - - simulator.start(); - - assertTimeout(Duration.ofMillis(150), (Executable) simulator::join); - verify(httpClientMock, atLeast(2)).send(messageBody.toString(), TEST_VES_URL); - } - - @Test - void simulator_should_stop_when_interrupted() { - - JSONObject messageBody = new JSONObject("{\"key\":\"val\"}"); - HttpClientAdapter httpClientMock = Mockito.mock(HttpClientAdapter.class); - - Simulator simulator = Simulator.builder() - .withInterval(Duration.ofSeconds(1)) - .withMessageBody(messageBody) - .withCustomHttpClientAdapter(httpClientMock) - .withVesUrl(TEST_VES_URL).build(); - - simulator.start(); - simulator.interrupt(); - - assertTimeout(Duration.ofSeconds(1), (Executable) simulator::join); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/validation/JSONValidatorTest.java b/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/validation/JSONValidatorTest.java deleted file mode 100644 index 30dfe065e..000000000 --- a/test/mocks/pnfsimulator/src/test/java/org/onap/pnfsimulator/simulator/validation/JSONValidatorTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * PNF-REGISTRATION-HANDLER - * ================================================================================ - * Copyright (C) 2018 NOKIA Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.pnfsimulator.simulator.validation; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -import com.github.fge.jsonschema.core.exceptions.InvalidSchemaException; -import com.github.fge.jsonschema.core.exceptions.ProcessingException; -import java.io.IOException; -import java.net.URL; -import org.json.JSONObject; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class JSONValidatorTest { - - private final static String VALID_SCHEMA_NAME = "valid-test-schema.json"; - private final static String INVALID_SCHEMA_NAME = "invalid-test-schema.json"; - - private JSONValidator validator; - - @BeforeEach - void setUp() { - validator = new JSONValidator(); - } - - @Test - void validate_should_not_throw_given_valid_json() throws ProcessingException, IOException, ValidationException { - validator.validate(getValidJsonString(), getResourcePath(VALID_SCHEMA_NAME)); - } - - @Test - void validate_should_not_throw_when_optional_parameter_missing() - throws ProcessingException, IOException, ValidationException { - - String invalidJsonString = new JSONObject() - .put("key1", "value1") - .put("key2", "value2") - .toString(); - - validator.validate(invalidJsonString, getResourcePath(VALID_SCHEMA_NAME)); - } - - @Test - void validate_should_throw_when_mandatory_parameter_missing() { - - String invalidJsonString = new JSONObject() - .put("key1", "value1") - .put("key3", "value3") - .toString(); - - assertThrows( - ValidationException.class, - () -> validator.validate(invalidJsonString, getResourcePath(VALID_SCHEMA_NAME))); - } - - @Test - void validate_should_throw_when_invalid_json_format() { - String invalidJsonString = "{" + - "\"key1\": \"value1\"" + - "\"key2\": \"value2" + - "}"; - - assertThrows( - IOException.class, - () -> validator.validate(invalidJsonString, getResourcePath(VALID_SCHEMA_NAME))); - } - - @Test - void validate_should_throw_when_invalid_schema_format() { - assertThrows( - InvalidSchemaException.class, - () -> validator.validate(getValidJsonString(), getResourcePath(INVALID_SCHEMA_NAME))); - } - - @Test - void validate_should_throw_when_invalid_schema_path() { - - assertThrows( - IOException.class, - () -> validator.validate(getValidJsonString(), "/not/existing/path/schema.json")); - } - - private String getResourcePath(String schemaFileName) { - URL result = getClass() - .getClassLoader() - .getResource(schemaFileName); - - if (result == null) { - throw new IllegalArgumentException("Given file doesn't exist"); - } else { - return result - .toString() - .replace("file:", ""); - } - } - - private String getValidJsonString() { - return new JSONObject() - .put("key1", "value1") - .put("key2", "value2") - .put("key3", "value3") - .toString(); - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/invalid-test-schema.json b/test/mocks/pnfsimulator/src/test/resources/invalid-test-schema.json deleted file mode 100644 index 8c37c822b..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/invalid-test-schema.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "properties": { - "key1": { - "type": "string" - }, - "key2": { - "type": "string" - }, - "key3": { - "type": "string" - }, - "required": [ - "key1", - "key2" - ] - } -} diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/message/MessageProviderTest/notificationParams.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/message/MessageProviderTest/notificationParams.json deleted file mode 100644 index b73c379a8..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/message/MessageProviderTest/notificationParams.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "notKey1": "notVal1", - "notKey2": "notVal2", - "notKey3": "notVal3", - "notKey4": "notVal4" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/message/MessageProviderTest/pnfRegistrationParams.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/message/MessageProviderTest/pnfRegistrationParams.json deleted file mode 100644 index 95446bf80..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/message/MessageProviderTest/pnfRegistrationParams.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "pnfKey1": "pnfVal1", - "pnfKey2": "pnfVal2", - "pnfKey3": "pnfVal3", - "pnfKey4": "pnfVal4" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/rest/SimulatorControllerTest/incorrectJson.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/rest/SimulatorControllerTest/incorrectJson.json deleted file mode 100644 index 682afac9f..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/rest/SimulatorControllerTest/incorrectJson.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "mes": { - "vesServerUrl": "http://10.154.187.70:8080/eventListener/v5", - "testDuration": "10", - "messageInterval": "1" - }, - "messageParams": { - "sourceName": "val12", - "sourceId": "val13", - "reportingEntityName": "val14" - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/rest/SimulatorControllerTest/pnfRegistration.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/rest/SimulatorControllerTest/pnfRegistration.json deleted file mode 100644 index a7bf487e7..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/rest/SimulatorControllerTest/pnfRegistration.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "simulatorParams": { - "vesServerUrl": "http://10.154.187.70:8080/eventListener/v7", - "testDuration": "10", - "messageInterval": "1" - }, - "commonEventHeaderParams": { - "eventName": "val11", - "nfNamingCode": "val12", - "nfcNamingCode": "val13", - "sourceName": "val14", - "sourceId": "val15", - "reportingEntityName": "val16" - }, - "pnfRegistrationParams": { - "SerialNumber": "val1", - "VendorName": "val2", - "OamIpv4Address": "val3", - "OamIpv6Address": "val4", - "Family": "val5", - "ModelNumber": "val6", - "SoftwareVersion": "val7" - } -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams1.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams1.json deleted file mode 100644 index eb9b4c156..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams1.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pnfSerialNumber": "val1", - "pnfVendorName": "val2", - "pnfFamily": "val5", - "pnfModelNumber": "val6", - "pnfSoftwareVersion": "val7", - "pnfType": "val8", - "eventName": "val9", - "nfNamingCode": "val10", - "nfcNamingCode": "val11", - "sourceName": "val12", - "sourceId": "val13", - "reportingEntityName": "val14" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams2.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams2.json deleted file mode 100644 index 9196caa30..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams2.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "pnfVendorName": "val2", - "pnfOamIpv4Address": "val3", - "pnfOamIpv6Address": "val4", - "pnfFamily": "val5", - "pnfModelNumber": "val6", - "pnfSoftwareVersion": "val7", - "pnfType": "val8", - "eventName": "val9", - "nfNamingCode": "val10", - "nfcNamingCode": "val11", - "sourceName": "val12", - "sourceId": "val13", - "reportingEntityName": "val14" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams3.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams3.json deleted file mode 100644 index e8734e6a0..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidPnfRegistrationParams3.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "pnfSerialNumber": "val1", - "pnfOamIpv4Address": "val3", - "pnfFamily": "val5", - "pnfModelNumber": "val6", - "pnfSoftwareVersion": "val7", - "pnfType": "val8", - "eventName": "val9", - "nfNamingCode": "val10", - "nfcNamingCode": "val11", - "sourceName": "val12", - "sourceId": "val13", - "reportingEntityName": "val14" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidSimulatorParams.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidSimulatorParams.json deleted file mode 100644 index be7b79477..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/invalidSimulatorParams.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "vesServerUrl": "http://10.42.111.42:8080/eventListener/v5", - "messageInterval": "1" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validCommonEventHeaderParams.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validCommonEventHeaderParams.json deleted file mode 100644 index e0f455045..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validCommonEventHeaderParams.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "eventName": "pnfRegistration_Nokia_5gDu", - "nfNamingCode": "gNB", - "nfcNamingCode": "oam", - "sourceName": "NOK6061ZW3", - "sourceId": "val13", - "reportingEntityName": "NOK6061ZW3" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validNotificationParams.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validNotificationParams.json deleted file mode 100644 index f7f463d3d..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validNotificationParams.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "changeIdentifier": "PM_MEAS_FILES", - "changeType": "FileReady", - "arrayOfNamedHashMap": [ - {"name": "A20161221.1031-1041.bin.gz", "hashMap": { - "location": "ftpes://192.169.0.1:22/ftp/rop/A20161224.1030-1045.bin.gz", - "compression": "gzip", - "fileformatType": "org.3GPP.32.435#measCollec", - "fileFormatVersion": "V10" - } - }, - {"name": "A20161222.1042-1102.bin.gz", "hashMap": { - "location": "ftpes://192.168.0.102:22/ftp/rop/A20161224.1045-1100.bin.gz", - "compression": "gzip", - "fileFormatType": "org.3GPP.32.435#measCollec", - "fileFormatVersion": "V10" - } - } - ] -} diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validPnfRegistrationParams.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validPnfRegistrationParams.json deleted file mode 100644 index b95f8e60a..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validPnfRegistrationParams.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "serialNumber": "6061ZW3", - "vendorName": "Nokia", - "oamV4IpAddress": "val3", - "oamV6IpAddress": "val4", - "unitFamily": "BBU", - "modelNumber": "val6", - "softwareVersion": "val7", - "unitType": "val8" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validSimulatorParams.json b/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validSimulatorParams.json deleted file mode 100644 index 6485ee4a4..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/org/onap/pnfsimulator/simulator/SimulatorFactoryTest/validSimulatorParams.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "vesServerUrl": "http://VES-HOST:VES-PORT/eventListener/v7", - "testDuration": "10", - "messageInterval": "1" -}
\ No newline at end of file diff --git a/test/mocks/pnfsimulator/src/test/resources/valid-test-schema.json b/test/mocks/pnfsimulator/src/test/resources/valid-test-schema.json deleted file mode 100644 index 26e48a5e8..000000000 --- a/test/mocks/pnfsimulator/src/test/resources/valid-test-schema.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "properties": { - "key1": { - "type": "string" - }, - "key2": { - "type": "string" - }, - "key3": { - "type": "string" - } - }, - "required": [ - "key1", - "key2" - ] -} |