Skip to content
Snippets Groups Projects
Commit ec7f002e authored by Taya Snijder's avatar Taya Snijder
Browse files

Merge branch 'master' of https://git.astron.nl/lofar2.0/tango into L2SS-1032_use_constants_in_tests

parents 87ff050f f227d3e0
Branches
Tags
1 merge request!470Resolve L2SS-1032 "Use constants in tests"
...@@ -9,13 +9,13 @@ RUN sudo apt-get install -y python3-dev libboost-python-dev pkg-config && sudo a ...@@ -9,13 +9,13 @@ RUN sudo apt-get install -y python3-dev libboost-python-dev pkg-config && sudo a
RUN sudo apt-get install -y rsync && sudo apt-get clean RUN sudo apt-get install -y rsync && sudo apt-get clean
COPY lofar-device-base/lofar-requirements.txt /lofar-requirements.txt COPY lofar-device-base/lofar-requirements.txt /lofar-requirements.txt
RUN sudo pip3 install -r /lofar-requirements.txt
# Manually install all requirements from the .txt as part of the base image # Manually install all requirements from the .txt as part of the base image
# This reduces runtime overhead as well as preventing issues around dependency # This reduces runtime overhead as well as preventing issues around dependency
# installation for development builds (pip install ./ ignores requirements.txt) # installation for development builds (pip install ./ ignores requirements.txt)
COPY tmp/requirements.txt /tangostationcontrol-requirements.txt COPY tmp/requirements.txt /tangostationcontrol-requirements.txt
RUN sudo pip3 install -r /tangostationcontrol-requirements.txt
RUN sudo pip3 install -r /tangostationcontrol-requirements.txt -r /lofar-requirements.txt
# install and use ephimerides and geodetic ("measures") tables for casacore. # install and use ephimerides and geodetic ("measures") tables for casacore.
# we install a _stub_ since the tables need to be deployed explicitly from within the software. # we install a _stub_ since the tables need to be deployed explicitly from within the software.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# #
# #
version: "3" version: "2.1"
services: services:
loki: loki:
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# integration process, which may cause wedges in the gate later. # integration process, which may cause wedges in the gate later.
importlib-metadata<2.0.0,>=0.12;python_version<"3.8" importlib-metadata<2.0.0,>=0.12;python_version<"3.8"
lofar-station-client@git+https://git.astron.nl/lofar2.0/lofar-station-client@0.9.1 lofar-station-client@git+https://git.astron.nl/lofar2.0/lofar-station-client@0.9.2
numpy numpy
mock mock
asyncua >= 0.9.90 # LGPLv3 asyncua >= 0.9.90 # LGPLv3
......
...@@ -26,7 +26,7 @@ package_dir= ...@@ -26,7 +26,7 @@ package_dir=
packages=find: packages=find:
python_requires => 3.7 python_requires => 3.7
install_requires = install_requires =
importlib-metadata>=0.12, <5.0;python_version<"3.8" importlib-metadata<2.0.0,>=0.12;python_version<"3.8"
pip>=1.5 pip>=1.5
[options.packages.find] [options.packages.find]
......
...@@ -3,23 +3,14 @@ ...@@ -3,23 +3,14 @@
# Distributed under the terms of the APACHE license. # Distributed under the terms of the APACHE license.
# See LICENSE.txt for more info. # See LICENSE.txt for more info.
from collections.abc import Sequence from tango.utils import is_seq
import numpy
def is_sequence(obj):
"""True for sequences, positionally ordered collections
See https://www.pythontutorial.net/advanced-python/python-sequences/
"""
return isinstance(obj, Sequence) or isinstance(obj, numpy.ndarray)
def sequence_not_str(obj): def sequence_not_str(obj):
"""True for sequences that are not str, bytes or bytearray""" """True for sequences that are not str, bytes or bytearray"""
return is_sequence(obj) and not isinstance(obj, (str, bytes, bytearray)) return is_seq(obj) and not isinstance(obj, (str, bytes, bytearray))
def type_not_sequence(obj): def type_not_sequence(obj):
"""True for types that are not sequences""" """True for types that are not sequences"""
return not is_sequence(obj) and isinstance(obj, type) return not is_seq(obj) and isinstance(obj, type)
# -*- 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 tangostationcontrol.test.devices.test_observation_base import TestObservationBase
from tangostationcontrol.integration_test import base
from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy
from lofar_station_client.observation.observation import Observation
from os import environ
from json import loads
from tango import DevState
class TestObservation(base.IntegrationTestCase):
def setUp(self):
self.observation_control_proxy = TestDeviceProxy("STAT/ObservationControl/1")
self.observation_control_proxy.off()
self.observation_control_proxy.warm_boot()
def test_observation(self):
"""Test of the observation_wrapper class basic functionality"""
# convert the JSON specificiation to a dict for this class
specification_dict = loads(TestObservationBase.VALID_JSON)
# create an observation class using the dict and as host just get it using a util function
observation = Observation(specification=specification_dict, host=environ["TANGO_HOST"])
# Assert the observation is running after starting it
observation.start()
self.assertTrue(observation.is_running())
# Assert the proxy is on
proxy = observation.observation_proxy()
self.assertTrue(proxy.state() == DevState.ON)
# Assert the observation has stopped after aborting
observation.abort()
self.assertFalse(observation.is_running())
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
# #
# Distributed under the terms of the APACHE license. # Distributed under the terms of the APACHE license.
# See LICENSE.txt for more info. # See LICENSE.txt for more info.
from tango.utils import is_seq
import numpy import numpy
from tangostationcontrol.common import type_checking from tangostationcontrol.common import type_checking
...@@ -32,7 +34,10 @@ class TestTypeChecking(base.TestCase): ...@@ -32,7 +34,10 @@ class TestTypeChecking(base.TestCase):
return False return False
def sequence_test(self, obj): def sequence_test(self, obj):
"""Test object is sequence based on properties and verify is_sequence""" """Test object is sequence based on properties and verify is_sequence
Recover alternative is_sequence method from commit 73177e9 if tests fail
"""
result = ( result = (
self.subscriptable(obj) & self.iterable(obj) self.subscriptable(obj) & self.iterable(obj)
...@@ -40,12 +45,15 @@ class TestTypeChecking(base.TestCase): ...@@ -40,12 +45,15 @@ class TestTypeChecking(base.TestCase):
) )
self.assertEqual( self.assertEqual(
result, type_checking.is_sequence(obj), result, is_seq(obj),
F"Test failed for type {type(obj)}" F"Test failed for type {type(obj)}"
) )
def test_is_sequence_for_types(self): def test_is_sequence_for_types(self):
"""Types to be tested by is_sequence""" """Types to be tested by is_sequence
Recover alternative is_seq method from commit 73177e9 if tests fail
"""
test_types = [ test_types = [
(False,), (False,),
......
...@@ -368,44 +368,6 @@ class TestAntennaToRecvMapper(base.TestCase): ...@@ -368,44 +368,6 @@ class TestAntennaToRecvMapper(base.TestCase):
actual = mapper.map_write("HBAT_PWR_on_RW", set_values) actual = mapper.map_write("HBAT_PWR_on_RW", set_values)
numpy.testing.assert_equal(expected, actual) numpy.testing.assert_equal(expected, actual)
# def test_merge_write(self):
# """Verify all None fields are replaced by merge_write if no control"""
#
# mapper = AntennaToRecvMapper(
# self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 1
# )
#
# merge_values = [[None] * N_rcu] * MAX_ANTENNA
# current_values = [[False] * N_rcu] * MAX_ANTENNA
#
# mapper.merge_write(merge_values, current_values)
# numpy.testing.assert_equal(merge_values, current_values)
#
# results = []
# for _i in range(25):
# start_time = time.monotonic_ns()
# mapper.merge_write(merge_values, current_values)
# stop_time = time.monotonic_ns()
# results.append(stop_time - start_time)
#
# logging.error(
# f"Merge write performance: Median {statistics.median(results) / 1.e9} "
# f"Stdev {statistics.stdev(results) / 1.e9}"
# )
#
# def test_merge_write_values(self):
# """Verify all fields with values are retained by merge_write"""
#
# mapper = AntennaToRecvMapper(
# self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 1
# )
#
# merge_values = [[True] * N_rcu] * 2 + [[None] * N_rcu] * (MAX_ANTENNA - 2)
# current_values = [[True] * N_rcu] * 2 + [[False] * N_rcu] * (MAX_ANTENNA - 2)
#
# mapper.merge_write(merge_values, current_values)
# numpy.testing.assert_equal(merge_values, current_values)
class TestAntennafieldDevice(device_base.DeviceTestCase): class TestAntennafieldDevice(device_base.DeviceTestCase):
......
...@@ -7,12 +7,20 @@ ...@@ -7,12 +7,20 @@
# Distributed under the terms of the APACHE license. # Distributed under the terms of the APACHE license.
# See LICENSE.txt for more info. # See LICENSE.txt for more info.
import numpy
from tango.test_context import DeviceTestContext from tango.test_context import DeviceTestContext
from tango.server import attribute from tango.server import attribute
from tango import DevState, DevFailed from tango.server import command
from tango import AttrWriteType
from tango import DevFailed
from tango import DevState
from tango import DevVarBooleanArray
from tangostationcontrol.devices import lofar_device from tangostationcontrol.devices import lofar_device
from unittest import mock
from tangostationcontrol.test.devices import device_base from tangostationcontrol.test.devices import device_base
...@@ -75,8 +83,54 @@ class TestLofarDevice(device_base.DeviceTestCase): ...@@ -75,8 +83,54 @@ class TestLofarDevice(device_base.DeviceTestCase):
# Just for demo, do not use class variables to store attribute state # Just for demo, do not use class variables to store attribute state
_bool_array = [False] * BOOL_ARRAY_DIM _bool_array = [False] * BOOL_ARRAY_DIM
bool_array = attribute(
dtype=(bool,), max_dim_x=BOOL_ARRAY_DIM,
access=AttrWriteType.READ_WRITE, fget="get_bool_array",
fset="set_bool_array"
)
def get_bool_array(self):
@attribute(dtype=(bool,), max_dim_x=BOOL_ARRAY_DIM)
def bool_array(self):
return self._bool_array return self._bool_array
def set_bool_array(self, bool_array):
self._bool_array = bool_array
@command(dtype_in=DevVarBooleanArray)
def do_read_modify_write(self, values: numpy.array):
bool_array_half = int(self.BOOL_ARRAY_DIM / 2)
# We have to mock the proxy because lofar_device.proxy will be
# patched
t_write = mock.Mock()
t_proxy = mock.Mock(
read_attribute=mock.Mock(
return_value=mock.Mock(
value=numpy.array(self._bool_array)
)
),
write_attribute=t_write
)
self.atomic_read_modify_write_attribute(
values, t_proxy, "bool_array",
numpy.array([True, False] * bool_array_half)
)
# Fake the write, extract the call argument from t_write mock
self._bool_array = t_write.call_args[0][1]
with DeviceTestContext(
AttributeLofarDevice, process=True
) as proxy:
bool_array_half = int(AttributeLofarDevice.BOOL_ARRAY_DIM / 2)
excepted_result = [True, False] * bool_array_half
proxy.initialise()
proxy.do_read_modify_write(
[True] * AttributeLofarDevice.BOOL_ARRAY_DIM
)
numpy.testing.assert_array_equal(
excepted_result, proxy.bool_array
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment