diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8dc2303883c44a3a4ad40e059a734378c6887e6f..e4fab6713dc1dddfdfdda89d18899c0841fda204 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,6 +15,7 @@ stages: - linting - static-analysis - unit-tests + - integration-tests linting: stage: linting script: @@ -34,3 +35,25 @@ unit_test: script: - cd devices - tox -e py37 +integration_test: + stage: integration-tests + allow_failure: true + services: + - name: docker:20.10.8-dind + variables: + DOCKER_TLS_CERTDIR: "/certs" +# Everything below does not work currently, we need a privileged container +# that can run the dind service + before_script: + - sudo apt update + - sudo apt install -y docker.io + - export USER=$(id | awk -F'=' '{print $2}' | awk -F'(' '{print $2}' | awk -F')' '{print $1}') + - echo $USER +# - sudo usermod -aG docker $USER + - sudo docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + script: + - touch /home/$USER/.Xauthority + - source bootstrap/etc/lofar20rc.sh + - export HOSTNAME=$(cat /run/systemd/netif/leases/2 | grep ^ADDRESS= | awk -F'=' '{print $2}') + - echo $HOSTNAME + - sudo $CI_PROJECT_DIR/sbin/run_integration_test.sh diff --git a/CDB/integration_ConfigDb.json b/CDB/integration_ConfigDb.json new file mode 100644 index 0000000000000000000000000000000000000000..b2f9cca6dc8db917942f35bb8be25e4cb88bdb93 --- /dev/null +++ b/CDB/integration_ConfigDb.json @@ -0,0 +1,64 @@ +{ + "servers": { + "PCC": { + "LTS": { + "PCC": { + "LTS/PCC/1": { + "properties": { + "OPC_Server_Name": [ + "pypcc-sim" + ], + "OPC_Server_Port": [ + "4842" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, + "SDP": { + "LTS": { + "SDP": { + "LTS/SDP/1": { + "properties": { + "OPC_Server_Name": [ + "sdptr-sim" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, + "SST": { + "LTS": { + "SST": { + "LTS/SST/1": { + "properties": { + "SST_Client_Port": [ + "5001" + ], + "OPC_Server_Name": [ + "sdptr-sim" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + } + } +} diff --git a/devices/.stestr.conf b/devices/.stestr.conf index ddc59860d5117ed8bdc44faeea1d893760b5520e..07147c8697683f270e9388da8b914c20cb8e4c45 100644 --- a/devices/.stestr.conf +++ b/devices/.stestr.conf @@ -1,3 +1,3 @@ [DEFAULT] -test_path=./test +test_path=${TESTS_DIR:-./test} top_dir=./ diff --git a/devices/integration_test/README.md b/devices/integration_test/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3292bfa0049b5c2312f8e0536e00cc581433ed61 --- /dev/null +++ b/devices/integration_test/README.md @@ -0,0 +1,26 @@ +# Integration Tests + +## Approach + +A special docker container is build to perform the integration tests. This +container will be build by the makefiles but should only be started by the +dedicated integration test script. This script will ensure that other containers +are running and are in the required state. + +* Launch pypcc-sim and sdptr-sim simulators. +* Reconfigure dsconfig to use these simulators. +* Create and start the integration-test container. + +## Running + +**Warning running these tests will make changes to your CDB database config!** + +```shell +source bootstrap/etc/lofar20rc.sh +$LOFAR20_DIR/sbin/run_integration_test.sh +``` + +## Limitations + +Our makefile will always launch the new container upon creation, resulting in +the integration tests actually being run twice. \ No newline at end of file diff --git a/devices/integration_test/__init__.py b/devices/integration_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/integration_test/base.py b/devices/integration_test/base.py new file mode 100644 index 0000000000000000000000000000000000000000..92601ec2d440753ae7f7be22fcbfad0c5028875c --- /dev/null +++ b/devices/integration_test/base.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +import unittest +import testscenarios + + +class BaseIntegrationTestCase(testscenarios.WithScenarios, unittest.TestCase): + """Integration test base class.""" + + def setUp(self): + super().setUp() + + +class IntegrationTestCase(BaseIntegrationTestCase): + """Integration test case base class for all unit tests.""" + + def setUp(self): + super().setUp() diff --git a/devices/integration_test/client/__init__.py b/devices/integration_test/client/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/integration_test/client/test_apsct_sim.py b/devices/integration_test/client/test_apsct_sim.py new file mode 100644 index 0000000000000000000000000000000000000000..775c34cd207699f7febb435000314c65db97b66a --- /dev/null +++ b/devices/integration_test/client/test_apsct_sim.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +from opcua import Client + +from integration_test import base + + +class TestAPSCTSim(base.IntegrationTestCase): + + def setUp(self): + super(TestAPSCTSim, self).setUp() + + def test_opcua_connection(self): + """Check if we can connect to apsct-sim""" + + #TODO(Corne): Replace to APSCT name once simulator name has changed + client = Client("opc.tcp://pypcc-sim:4842") + root_node = None + + try: + client.connect() + root_node = client.get_root_node() + finally: + client.disconnect() + + self.assertNotEqual(None, root_node) diff --git a/devices/integration_test/client/test_sdptr_sim.py b/devices/integration_test/client/test_sdptr_sim.py new file mode 100644 index 0000000000000000000000000000000000000000..3ba48e7d761c7ef366c8690e2d114c773de7311d --- /dev/null +++ b/devices/integration_test/client/test_sdptr_sim.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +from opcua import Client + +from integration_test import base + + +class TestSDPTRSim(base.IntegrationTestCase): + + def setUp(self): + super(TestSDPTRSim, self).setUp() + + def test_opcua_connection(self): + """Check if we can connect to sdptr-sim""" + + client = Client("opc.tcp://sdptr-sim:4840") + root_node = None + + try: + client.connect() + root_node = client.get_root_node() + finally: + client.disconnect() + + self.assertNotEqual(None, root_node) diff --git a/devices/integration_test/devices/__init__.py b/devices/integration_test/devices/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/integration_test/devices/test_device_pcc.py b/devices/integration_test/devices/test_device_pcc.py new file mode 100644 index 0000000000000000000000000000000000000000..b3b7a4672dbb18790d19144aeb35bcacd68e4bfb --- /dev/null +++ b/devices/integration_test/devices/test_device_pcc.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +import time + +from tango import DeviceProxy +from tango._tango import DevState + +from integration_test import base + + +class TestDevicePCC(base.IntegrationTestCase): + + def setUp(self): + super(TestDevicePCC, self).setUp() + + def tearDown(self): + """Turn device Off in teardown to prevent blocking tests""" + d = DeviceProxy("LTS/PCC/1") + + try: + d.Off() + except Exception as e: + """Failing to turn Off devices should not raise errors here""" + print(f"Failed to turn device off in teardown {e}") + + def test_device_proxy_pcc(self): + """Test if we can successfully create a DeviceProxy and fetch state""" + + d = DeviceProxy("LTS/PCC/1") + + self.assertEqual(DevState.OFF, d.state()) + + def test_device_pcc_initialize(self): + """Test if we can transition to standby""" + + d = DeviceProxy("LTS/PCC/1") + + d.initialise() + + self.assertEqual(DevState.STANDBY, d.state()) + + def test_device_pcc_on(self): + """Test if we can transition to on""" + + d = DeviceProxy("LTS/PCC/1") + + d.initialise() + + d.on() + + self.assertEqual(DevState.ON, d.state()) diff --git a/devices/integration_test/devices/test_device_sdp.py b/devices/integration_test/devices/test_device_sdp.py new file mode 100644 index 0000000000000000000000000000000000000000..cfd656748054cb21e0e3bb2110ce60072d9fb28a --- /dev/null +++ b/devices/integration_test/devices/test_device_sdp.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +import time + +from tango import DeviceProxy +from tango._tango import DevState + +from integration_test import base + + +class TestDeviceSDP(base.IntegrationTestCase): + + def setUp(self): + """Intentionally recreate the device object in each test""" + super(TestDeviceSDP, self).setUp() + + def tearDown(self): + """Turn device Off in teardown to prevent blocking tests""" + d = DeviceProxy("LTS/SDP/1") + + try: + d.Off() + except Exception as e: + """Failing to turn Off devices should not raise errors here""" + print(f"Failed to turn device off in teardown {e}") + + def test_device_proxy_sdp(self): + """Test if we can successfully create a DeviceProxy and fetch state""" + + d = DeviceProxy("LTS/SDP/1") + + self.assertEqual(DevState.OFF, d.state()) + + def test_device_sdp_initialize(self): + """Test if we can transition to standby""" + + d = DeviceProxy("LTS/SDP/1") + + d.initialise() + + self.assertEqual(DevState.STANDBY, d.state()) + + def test_device_sdp_on(self): + """Test if we can transition to on""" + + d = DeviceProxy("LTS/SDP/1") + + d.initialise() + + d.on() + + self.assertEqual(DevState.ON, d.state()) diff --git a/devices/tox.ini b/devices/tox.ini index 18c6cda38751d7bc447e8fb23d92e63b64288ddb..94d33c3e392272ac7341e039791f567cf2a7b9b4 100644 --- a/devices/tox.ini +++ b/devices/tox.ini @@ -17,6 +17,14 @@ deps = -r{toxinidir}/test-requirements.txt -r{toxinidir}/../docker-compose/lofar-device-base/lofar-requirements.txt commands = stestr run {posargs} +[testenv:integration] +; Warning running integration tests will make changes to your docker system! +; These tests should only be run by the integration-test docker container. +passenv = TANGO_HOST +setenv = TESTS_DIR=./integration_test +commands = + stestr run --serial + ; TODO(Corne): Integrate Hacking to customize pep8 rules [testenv:pep8] commands = diff --git a/docker-compose/integration-test.yml b/docker-compose/integration-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..e6a0e54939179ba0c4f5b043da3191dd9e11945d --- /dev/null +++ b/docker-compose/integration-test.yml @@ -0,0 +1,29 @@ +# +# Docker compose file that launches integration tests +# +# Defines: +# - integration: Integration testing +# +version: '2' + +services: + integration-test: + build: + context: itango + args: + SOURCE_IMAGE: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-itango:${TANGO_ITANGO_VERSION} + container_name: ${CONTAINER_NAME_PREFIX}integration-test + networks: + - control + volumes: + - ${TANGO_LOFAR_CONTAINER_MOUNT} + environment: + - TANGO_HOST=${TANGO_HOST} + working_dir: ${TANGO_LOFAR_CONTAINER_DIR}/devices + entrypoint: + - /usr/local/bin/wait-for-it.sh + - ${TANGO_HOST} + - --timeout=30 + - --strict + - -- + - tox -e integration diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..d54163625541c13816bf0309c09a2713ce35add9 --- /dev/null +++ b/sbin/run_integration_test.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Check if lofar20rc.sh is sourced and environment variables are set. +if [ -z "$LOFAR20_DIR" ]; then + echo "\$LOFAR20_DIR is unset or blank, is lofar20rc.sh sourced correctly?" + exit 1 +fi + +# Start all required containers +cd "$LOFAR20_DIR/docker-compose" || exit 1 +make start databaseds dsconfig device-sdp device-pcc jupyter elk sdptr-sim pypcc-sim + +# Update the dsconfig +cd "$TANGO_LOFAR_LOCAL_DIR" || exit 1 +sbin/update_ConfigDb.sh CDB/integration_ConfigDb.json + +# Start the integration test +cd "$LOFAR20_DIR/docker-compose" || exit 1 +make start integration-test + +# Run the integration test with the output displayed on stdout +docker start -a integration-test \ No newline at end of file