Пример #1
0
def test_event_key():
    prefix = Prefix(Subsystems.TCS, "ENCAssembly")
    prefix2 = Prefix(Subsystems.TCS, "ENC.Assembly")
    eventName = EventName("CurrentPosition")
    k1 = EventKey(prefix, eventName)
    k2 = EventKey.from_str("TCS.ENCAssembly.CurrentPosition")
    assert k1 == k2
    k1 = EventKey(prefix2, eventName)
    k2 = EventKey.from_str("TCS.ENC.Assembly.CurrentPosition")
    assert k1 == k2
Пример #2
0
 def __init__(self):
     self.count = 0
     self.eventKey = EventKey(Prefix(Subsystems.CSW, "testassembly"),
                              EventName("myAssemblyEvent"))
     self.eventSubscriber = EventSubscriber()
     self.eventThread = self.eventSubscriber.subscribe([self.eventKey],
                                                       self.callback)
Пример #3
0
def test_connection_info():
    prefix = Prefix(Subsystems.CSW, "MyComp")
    info = ConnectionInfo.make(prefix, ComponentType.Service,
                               ConnectionType.HttpType)
    json = info.to_json()
    newInfo = ConnectionInfo.schema().loads(json)
    assert (newInfo == info)
Пример #4
0
    def __init__(self):
        intParam = Parameter("IntValue", KeyType.IntKey, [42], Units.arcsec)
        floatParam = Parameter("floatValue", KeyType.FloatKey, [float(42.1)], Units.arcsec)
        longParam = Parameter("longValue", KeyType.LongKey, [42], Units.arcsec)
        shortParam = Parameter("shortValue", KeyType.ShortKey, [42], Units.arcsec)
        byteParam = Parameter("byteValue", KeyType.ByteKey, b'\xDE\xAD\xBE\xEF')
        booleanParam = Parameter("booleanValue", KeyType.BooleanKey, [True, False], Units.arcsec)

        intArrayParam = Parameter("IntArrayValue", KeyType.IntArrayKey, [[1, 2, 3, 4], [5, 6, 7, 8]])
        floatArrayParam = Parameter("FloatArrayValue", KeyType.FloatArrayKey, [[1.2, 2.3, 3.4], [5.6, 7.8, 9.1]],
                                    Units.arcsec)
        doubleArrayParam = Parameter("DoubleArrayValue", KeyType.DoubleArrayKey, [[1.2, 2.3, 3.4], [5.6, 7.8, 9.1]],
                                     Units.arcsec)

        byteArrayParam = Parameter("ByteArrayValue", KeyType.ByteArrayKey, [b'\xDE\xAD\xBE\xEF', bytes([1, 2, 3, 4])])

        intMatrixParam = Parameter("IntMatrixValue", KeyType.IntMatrixKey,
                                   [[[1, 2, 3, 4], [5, 6, 7, 8]], [[-1, -2, -3, -4], [-5, -6, -7, -8]]], Units.meter)

        eqCoord = EqCoord.make(ra="12:13:14.15 hours", dec="-30:31:32.3 deg", frame=EqFrame.FK5, pm=(0.5, 2.33))
        solarSystemCoord = SolarSystemCoord.make("BASE", SolarSystemObject.Venus)
        minorPlanetCoord = MinorPlanetCoord.make("GUIDER1", 2000, "90 deg", "2 deg", "100 deg", 1.4, 0.234,
                                                 "220 deg")
        cometCoord = CometCoord.make("BASE", 2000.0, "90 deg", "2 deg", "100 deg", 1.4, 0.234)
        altAzCoord = AltAzCoord.make("301 deg", "42.5 deg")
        coordsParam = Parameter("CoordParam", KeyType.CoordKey,
                                [eqCoord, solarSystemCoord, minorPlanetCoord, cometCoord, altAzCoord])

        prefix = Prefix(Subsystems.CSW, "testassembly")
        eventName = EventName("myAssemblyEvent")
        paramSet = [coordsParam, byteParam, intParam, floatParam, longParam, shortParam, booleanParam, byteArrayParam,
                    intArrayParam, floatArrayParam, doubleArrayParam, intMatrixParam]
        event = SystemEvent(prefix, eventName, paramSet)
        self.pub.publish(event)
Пример #5
0
 def _fromDict(obj):
     """
     Returns a CurrentState for the given dict.
     """
     prefix = Prefix.from_str(obj['prefix'])
     stateName = obj['stateName']
     paramSet = list(map(lambda p: Parameter._fromDict(p), obj['paramSet']))
     return CurrentState(prefix, stateName, paramSet)
Пример #6
0
 def __init__(self):
     """
     Events are posted to Redis. This is internal class used to access Redis.
     """
     prefix = Prefix(Subsystems.CSW, "EventServer")
     conn = ConnectionInfo.make(prefix, ComponentType.Service, ConnectionType.TcpType)
     loc = LocationService().find(conn)
     uri = urlparse(loc.uri)
     sentinel = Sentinel([(uri.hostname, uri.port)], socket_timeout=0.1)
     self.__redis = sentinel.master_for('eventServer', socket_timeout=0.1)
     self.__redis_pubsub = self.__redis.pubsub()
Пример #7
0
 def _fromDict(obj):
     """
     Returns a ControlCommand for the given dict.
     """
     typ = obj["_type"]
     source = Prefix.from_str(obj['source'])
     commandName = CommandName(obj['commandName'])
     maybeObsId = obj['maybeObsId'] if 'maybeObsId' in obj else ""
     paramSet = list(map(lambda p: Parameter._fromDict(p), obj['paramSet']))
     assert (typ in {"Setup", "Observe"})
     if typ == 'Setup':
         return Setup(source, commandName, maybeObsId, paramSet)
     else:
         return Observe(source, commandName, maybeObsId, paramSet)
Пример #8
0
 def _fromDict(obj):
     """
     Returns a Event for the given dict.
     """
     typ = obj['_type']
     assert (typ in {"SystemEvent", "ObserveEvent"})
     paramSet = list(
         map(lambda p: Parameter._fromDict(p, True), obj['paramSet']))
     eventTime = EventTime._fromDict(obj['eventTime'])
     prefix = Prefix.from_str(obj['source'])
     eventName = EventName(obj['eventName'])
     eventId = obj['eventId']
     if typ == 'SystemEvent':
         return SystemEvent(prefix, eventName, paramSet, eventTime, eventId)
     else:
         return ObserveEvent(prefix, eventName, paramSet, eventTime,
                             eventId)
Пример #9
0
 def test_location_service_models(self):
     testDir = pathlib.Path(__file__).parent.absolute()
     with open(f"{testDir}/location-models.json") as json_file:
         data = json.load(json_file)
         for p in data['ComponentType']:
             assert (ComponentType[p].name == p)
         for p in data['Connection']:
             connectionInfo = ConnectionInfo.from_dict(p)
             self.log.debug(f"Connection: {connectionInfo}")
             assert (connectionInfo.to_dict() == p)
         for p in data['Registration']:
             regType = p['_type']
             if regType == "HttpRegistration":
                 registration = HttpRegistration.from_dict(p)
             elif regType == "TcpRegistration":
                 registration = TcpRegistration.from_dict(p)
             elif regType == "AkkaRegistration":
                 registration = AkkaRegistration.from_dict(p)
             assert (registration.to_dict() == p)
         for p in data['ComponentId']:
             componentId = ComponentId.from_dict(p)
             self.log.debug(f"ComponentId: {componentId}")
             assert (componentId.to_dict() == p)
         for p in data['Prefix']:
             prefix = Prefix.from_str(p)
             assert (str(prefix) == p)
         for p in data['ConnectionType']:
             assert (ConnectionType(p).value == p)
         for p in data['Subsystem']:
             assert (Subsystems[p].name == p)
         for p in data['Location']:
             locType = p['_type']
             if locType == "AkkaLocation":
                 loc = AkkaLocation.from_dict(p)
             elif locType == "HttpLocation":
                 loc = HttpLocation.from_dict(p)
             elif locType == "TcpLocation":
                 loc = TcpLocation.from_dict(p)
             self.log.debug(f"Location: {loc}")
             assert (loc.to_dict() == p)
Пример #10
0
    def test_pub_sub(self):
        pub = EventPublisher()
        sub = EventSubscriber()

        prefix = Prefix(Subsystems.CSW, "assembly")
        eventName = EventName("test_event")
        eventKey = EventKey(prefix, eventName)
        keyName = "testEventValue"
        keyType = KeyType.IntKey
        values = [42]
        param = Parameter(keyName, keyType, values)
        paramSet = [param]
        event = SystemEvent(prefix, eventName, paramSet)

        thread = sub.subscribe([eventKey], self.callback)
        pub.publish(event)
        time.sleep(1)
        e = sub.get(eventKey)
        assert (e == event)
        assert (self.count == 1)
        sub.unsubscribe([eventKey])
        thread.stop()
Пример #11
0
def test_location_service():
    log = structlog.get_logger()
    locationService = LocationService()

    # List all registered connections
    log.debug("\nAll Locations:")
    allLocations = locationService.list()
    for i in allLocations:
        log.debug("    " + str(i))
    # Check that the standard CSW services were found
    assert [
        x for x in allLocations if x.connection.prefix == 'CSW.AAS'
        and x.connection.componentType == 'Service'
    ]
    assert [
        x for x in allLocations if x.connection.prefix == 'CSW.AlarmServer'
        and x.connection.componentType == 'Service'
    ]
    assert [
        x for x in allLocations if x.connection.prefix == 'CSW.DatabaseServer'
        and x.connection.componentType == 'Service'
    ]
    assert [
        x for x in allLocations if x.connection.prefix == 'CSW.EventServer'
        and x.connection.componentType == 'Service'
    ]
    assert [
        x for x in allLocations if x.connection.prefix == 'CSW.ConfigServer'
        and x.connection.componentType == 'Service'
    ]

    # List the registered HCDs
    log.debug("\nHCDs:")
    for i in locationService.list(ComponentType.HCD):
        log.debug("    " + str(i))

    # List the registered http connections
    log.debug("\nConnections on 192.168.178.78")
    for i in locationService.list("192.168.178.78"):
        log.debug("    " + str(i))

    # List the registered http connections
    log.debug("\nHTTP connections:")
    httpServices = locationService.list(ConnectionType.HttpType)
    for i in httpServices:
        log.debug("    " + str(i))
    assert [
        x for x in httpServices if x.connection.prefix == 'CSW.AAS'
        and x.connection.componentType == 'Service'
    ]
    assert not [
        x for x in httpServices if x.connection.prefix == 'CSW.AlarmServer'
        and x.connection.componentType == 'Service'
    ]
    assert not [
        x for x in httpServices if x.connection.prefix == 'CSW.DatabaseServer'
        and x.connection.componentType == 'Service'
    ]
    assert not [
        x for x in httpServices if x.connection.prefix == 'CSW.EventServer'
        and x.connection.componentType == 'Service'
    ]
    assert [
        x for x in httpServices if x.connection.prefix == 'CSW.ConfigServer'
        and x.connection.componentType == 'Service'
    ]

    # Register a connection
    prefix = Prefix(Subsystems.CSW, "myComp")
    connection = ConnectionInfo.make(prefix, ComponentType.Service,
                                     ConnectionType.HttpType)
    reg = HttpRegistration(connection, 8080, path="myservice/test")
    regResult = locationService.register(reg)
    log.debug("\nRegistration result: " + str(regResult))
    assert regResult.componentType == ComponentType.Service.value
    assert regResult.prefix == 'CSW.myComp'
    assert regResult.connectionType == ConnectionType.HttpType.value

    # Find a connection
    location1 = locationService.find(connection)
    log.debug("location1 = " + str(location1))
    assert location1.connection.componentType == ComponentType.Service.value
    assert location1.connection.prefix == 'CSW.myComp'
    assert location1.connection.connectionType == ConnectionType.HttpType.value

    # Resolve a connection (waiting if needed)
    location2 = locationService.resolve(connection)
    log.debug("location2 = " + str(location2))
    assert location1 == location2

    # Unregister
    unregResult = locationService.unregister(connection)
    log.debug("\nUnregister result: " + str(unregResult))

    assert not locationService.find(connection)
Пример #12
0
class TestEventsWithAssembly:
    log = structlog.get_logger()
    dir = pathlib.Path(__file__).parent.absolute()
    inFileName = "PyTestAssemblyEventHandlers.in"
    outFileName = "PyTestAssemblyEventHandlers.out"
    tmpInFile = f"/tmp/{inFileName}"
    tmpOutFile = f"/tmp/{outFileName}"
    inFile = f"{dir}/{inFileName}"
    outFile = f"{dir}/{outFileName}"
    pub = EventPublisher()
    sub = EventSubscriber()
    prefix = Prefix(Subsystems.CSW, "TestPublisher")

    # def setup_method(self):
    #     self.cleanup()

    def teardown_method(self):
        # pass
        self.cleanup()

    def cleanup(self):
        if os.path.exists(self.tmpInFile):
            os.remove(self.tmpInFile)
        if os.path.exists(self.tmpOutFile):
            os.remove(self.tmpOutFile)

    def test_pub_sub(self):
        time.sleep(1.0)
        self.log.debug("Starting test...")
        thread = self.sub.subscribe([
            EventKey(self.prefix, EventName("testEvent1")),
            EventKey(self.prefix, EventName("testEvent2")),
            EventKey(self.prefix, EventName("testEvent3"))
        ], self.callback)
        try:
            self.publishEvent1()
            self.publishEvent2()
            self.publishEvent3()
            self.publishEvent4()
            self.log.debug("Published three events...")
            # make sure assembly has time to write the file
            time.sleep(3)
            # compare file created from received events below with known good version
            assert filecmp.cmp(self.inFile, self.tmpInFile, False)
            # compare file created by assembly with known good version
            assert filecmp.cmp(self.outFile, self.tmpOutFile, False)
            self.log.info("Event pub/sub tests passed")
        finally:
            self.log.debug("Stopping subscriber...")
            thread.stop()

    def publishEvent1(self):
        keyName = "assemblyEventValue"
        keyType = KeyType.DoubleKey
        values = [42.0]
        param = Parameter(keyName, keyType, values)
        paramSet = [param]
        event = SystemEvent(self.prefix, EventName("testEvent1"), paramSet)
        self.log.debug(f"Publishing event {event}")
        self.pub.publish(event)

    def publishEvent2(self):
        intParam = Parameter("IntValue", KeyType.IntKey, [42], Units.arcsec)
        intArrayParam = Parameter("IntArrayValue", KeyType.IntArrayKey,
                                  [[1, 2, 3, 4], [5, 6, 7, 8]])
        floatArrayParam = Parameter("FloatArrayValue", KeyType.FloatArrayKey,
                                    [[1.2, 2.3, 3.4], [5.6, 7.8, 9.1]],
                                    Units.marcsec)
        intMatrixParam = Parameter("IntMatrixValue", KeyType.IntMatrixKey,
                                   [[[1, 2, 3, 4], [5, 6, 7, 8]],
                                    [[-1, -2, -3, -4], [-5, -6, -7, -8]]],
                                   Units.meter)
        paramSet = [intParam, intArrayParam, floatArrayParam, intMatrixParam]
        event = SystemEvent(self.prefix, EventName("testEvent2"), paramSet)
        self.pub.publish(event)

    def publishEvent3(self):
        intParam = Parameter("IntValue", KeyType.IntKey, [42], Units.arcsec)
        floatParam = Parameter("floatValue", KeyType.FloatKey, [float(42.1)],
                               Units.arcsec)
        longParam = Parameter("longValue", KeyType.LongKey, [42], Units.arcsec)
        shortParam = Parameter("shortValue", KeyType.ShortKey, [42],
                               Units.arcsec)
        byteParam = Parameter("byteValue", KeyType.ByteKey,
                              b'\xDE\xAD\xBE\xEF')
        booleanParam = Parameter("booleanValue", KeyType.BooleanKey,
                                 [True, False], Units.arcsec)

        intArrayParam = Parameter("IntArrayValue", KeyType.IntArrayKey,
                                  [[1, 2, 3, 4], [5, 6, 7, 8]])
        floatArrayParam = Parameter("FloatArrayValue", KeyType.FloatArrayKey,
                                    [[1.2, 2.3, 3.4], [5.6, 7.8, 9.1]],
                                    Units.arcsec)
        doubleArrayParam = Parameter("DoubleArrayValue",
                                     KeyType.DoubleArrayKey,
                                     [[1.2, 2.3, 3.4], [5.6, 7.8, 9.1]],
                                     Units.arcsec)

        byteArrayParam = Parameter(
            "ByteArrayValue", KeyType.ByteArrayKey,
            [b'\xDE\xAD\xBE\xEF', bytes([1, 2, 3, 4])])

        intMatrixParam = Parameter("IntMatrixValue", KeyType.IntMatrixKey,
                                   [[[1, 2, 3, 4], [5, 6, 7, 8]],
                                    [[-1, -2, -3, -4], [-5, -6, -7, -8]]],
                                   Units.meter)

        eqCoord = EqCoord.make(ra="12:13:14.15 hours",
                               dec="-30:31:32.3 deg",
                               frame=EqFrame.FK5,
                               pm=(0.5, 2.33))
        solarSystemCoord = SolarSystemCoord.make("BASE",
                                                 SolarSystemObject.Venus)
        minorPlanetCoord = MinorPlanetCoord.make("GUIDER1", 2000, "90 deg",
                                                 "2 deg", "100 deg", 1.4,
                                                 0.234, "220 deg")
        cometCoord = CometCoord.make("BASE", 2000.0, "90 deg", "2 deg",
                                     "100 deg", 1.4, 0.234)
        altAzCoord = AltAzCoord.make("301 deg", "42.5 deg")
        coordsParam = Parameter("CoordParam", KeyType.CoordKey, [
            eqCoord, solarSystemCoord, minorPlanetCoord, cometCoord, altAzCoord
        ])

        paramSet = [
            coordsParam, byteParam, intParam, floatParam, longParam,
            shortParam, booleanParam, byteArrayParam, intArrayParam,
            floatArrayParam, doubleArrayParam, intMatrixParam
        ]
        event = SystemEvent(self.prefix, EventName("testEvent3"), paramSet)
        self.pub.publish(event)

    def publishEvent4(self):
        keyName = "assemblyEventValue"
        keyType = KeyType.UTCTimeKey
        values = [UTCTime.from_str("2021-09-20T20:43:35.419053077Z")]
        param = Parameter(keyName, keyType, values)
        keyName2 = "assemblyEventValue2"
        keyType2 = KeyType.TAITimeKey
        values2 = [TAITime.from_str("2021-09-20T18:44:12.419084072Z")]
        param2 = Parameter(keyName2, keyType2, values2)
        paramSet = [param, param2]
        event = SystemEvent(self.prefix, EventName("testEvent4"), paramSet)
        self.log.debug(f"Publishing event {event}")
        self.pub.publish(event)

    # Event subscriber callback
    def callback(self, systemEvent):
        self.log.debug(f"Received system event '{systemEvent}'")
        # Save event to file as JSON like dict (Not JSON, since byte arrays are not serializable in python),
        # but change the date and id for comparison
        systemEvent.eventId = "test"
        systemEvent.eventTime = EventTime(0, 0)
        mode = "w" if (systemEvent.eventName.name == "testEvent1") else "a"
        f = open(self.tmpInFile, mode)
        jsonStr = str(systemEvent._asDict())
        f.write(f"{jsonStr}\n")
        f.close()
Пример #13
0
from csw.Event import SystemEvent, EventName
from csw.EventPublisher import EventPublisher
from csw.KeyType import KeyType
from csw.Parameter import Parameter
from csw.Prefix import Prefix
from csw.Subsystem import Subsystems

# Test publishing events
source = Prefix(Subsystems.CSW, "testassembly")
eventName = EventName("myAssemblyEvent")

keyName = "assemblyEventValue"
keyType = KeyType.DoubleKey
values = [42.0]
param = Parameter(keyName, keyType, values)
paramSet = [param]

event = SystemEvent(source, eventName, paramSet)
pub = EventPublisher()
pub.publish(event)
Пример #14
0
 def from_str(class_object, eventKeyStr: str):
     i = eventKeyStr.rindex('.')
     return EventKey(Prefix.from_str(eventKeyStr[:i]),
                     EventName(eventKeyStr[i + 1:]))
Пример #15
0
class MyComponentHandlers(ComponentHandlers):
    prefix = Prefix(Subsystems.CSW, "pycswTest")

    async def longRunningCommand(self, runId: str,
                                 command: ControlCommand) -> CommandResponse:
        await asyncio.sleep(3)
        print("Long running task completed")
        # TODO: Do this in a timer task
        await self.publishCurrentStates()
        return Completed(runId)

    def onSubmit(self, runId: str,
                 command: ControlCommand) -> (CommandResponse, Task):
        """
        Overrides the base class onSubmit method to handle commands from a CSW component

        Args:
            runId (str): unique id for this command
            command (ControlCommand): contains the ControlCommand from CSW

        Returns: (CommandResponse, Task)
            a subclass of CommandResponse that is serialized and passed back to the CSW component
        """
        n = len(command.paramSet)
        print(
            f"MyComponentHandlers Received setup {str(command)} with {n} params"
        )
        # filt = command.get("filter").values[0]
        # encoder = command.get("encoder").values[0]
        # print(f"filter = {filt}, encoder = {encoder}")

        # --- Example return values ---

        # return Completed(runId), None

        # return Error(runId, "There is a problem ..."), None

        # return Invalid(runId, MissingKeyIssue("Missing required key XXX")), None

        # result = Result("tcs.filter", [Parameter("myValue", 'DoubleKey', [42.0])])
        # return Completed(runId, result), None

        if command.commandName.name == "LongRunningCommand":
            task = asyncio.create_task(self.longRunningCommand(runId, command))
            return Started(runId, "Long running task in progress..."), task
        elif command.commandName.name == "SimpleCommand":
            return Completed(runId), None
        elif command.commandName.name == "ResultCommand":
            result = Result([Parameter("myValue", KeyType.DoubleKey, [42.0])])
            return Completed(runId, result), None
        else:
            return Invalid(
                runId,
                UnsupportedCommandIssue(
                    f"Unknown command: {command.commandName.name}")), None

    def onOneway(self, runId: str, command: ControlCommand) -> CommandResponse:
        """
        Overrides the base class onOneway method to handle commands from a CSW component.

        Args:
            runId (str): unique id for this command
            command (ControlCommand): contains the ControlCommand from CSW

        Returns: CommandResponse
            an instance of one of these command responses: Accepted, Invalid, Locked (OnewayResponse in CSW)
        """
        n = len(command.paramSet)
        print(
            f"MyComponentHandlers Received oneway {str(command)} with {n} params"
        )
        # filt = command.get("filter").values[0]
        # encoder = command.get("encoder").values[0]
        # print(f"filter = {filt}, encoder = {encoder}")
        return Accepted(runId)

    def validateCommand(self, runId: str,
                        command: ControlCommand) -> CommandResponse:
        """
        Overrides the base class validate method to verify that the given command is valid.

        Args:
            runId (str): unique id for this command
            command (ControlCommand): contains the ControlCommand from CSW

        Returns: CommandResponse
            an instance of one of these command responses: Accepted, Invalid, Locked (OnewayResponse in CSW)
        """
        return Accepted(runId)

    # Returns the current state
    def currentStates(self) -> List[CurrentState]:
        intParam = Parameter("IntValue", KeyType.IntKey, [42], Units.arcsec)
        intArrayParam = Parameter("IntArrayValue", KeyType.IntArrayKey,
                                  [[1, 2, 3, 4], [5, 6, 7, 8]])
        floatArrayParam = Parameter("FloatArrayValue", KeyType.FloatArrayKey,
                                    [[1.2, 2.3, 3.4], [5.6, 7.8, 9.1]],
                                    Units.marcsec)
        intMatrixParam = Parameter("IntMatrixValue", KeyType.IntMatrixKey,
                                   [[[1, 2, 3, 4], [5, 6, 7, 8]],
                                    [[-1, -2, -3, -4], [-5, -6, -7, -8]]],
                                   Units.meter)
        return [
            CurrentState(
                self.prefix, "PyCswState",
                [intParam, intArrayParam, floatArrayParam, intMatrixParam])
        ]