messages.py 76.1 KB
Newer Older
1
2
3
# -*- coding: utf-8 -*-

"""
4
5
6
7

About the library:
-----------------

8
9
10
11
12
13
14
15
16
This module provides the API message formats used in F-Interop.

The idea is to be able to have an
- organized and centralized way of dealing with the big amount of messages formats used in the platform;
- to be able to import (or just copy/paste) these messages formats from any component in the F-Interop platform,
- re-use this also for the integration testing;
- to have version control the messages e.g. messages_testcase_start API v1 and API v2;
- to have a direct way of exporting this as doc.

17
18
19
20
21
22
23
24

F-Interop conventions:
---------------------
- if event is a service request then the routing key (r_key) is control.someFunctionality.service
- a reply to a service will be on topic/r_key : control.someFunctionality.service.reply
- reply.correlation_id = request.correlation_id


25
26
Usage:
------
27
>>> from messages import * # doctest: +SKIP
Federico Sismondi's avatar
Federico Sismondi committed
28
>>> m = MsgTestCaseSkip(testcase_id = 'some_testcase_id')
29
>>> m
30
MsgTestCaseSkip(_api_version = 1.0.1, _type = testcoordination.testcase.skip, description = Skip testcase, node = someNode, testcase_id = some_testcase_id, )
31
32
>>> m.routing_key
'control.testcoordination'
33
34
>>> m.message_id # doctest: +SKIP
'802012eb-24e3-45c4-9dcc-dc293c584f63'
35
>>> m.testcase_id
Federico Sismondi's avatar
Federico Sismondi committed
36
'some_testcase_id'
37

38
# also we can modify some of the fields (rewrite the default ones)
Federico Sismondi's avatar
Federico Sismondi committed
39
>>> m = MsgTestCaseSkip(testcase_id = 'TD_COAP_CORE_03')
40
>>> m
41
MsgTestCaseSkip(_api_version = 1.0.1, _type = testcoordination.testcase.skip, description = Skip testcase, node = someNode, testcase_id = TD_COAP_CORE_03, )
42
>>> m.testcase_id
Federico Sismondi's avatar
Federico Sismondi committed
43
'TD_COAP_CORE_03'
44

45
46
# and even export the message in json format (for example for sending the message though the amqp event bus)
>>> m.to_json()
47
'{"_api_version": "1.0.1", "_type": "testcoordination.testcase.skip", "description": "Skip testcase", "node": "someNode", "testcase_id": "TD_COAP_CORE_03"}'
Federico Sismondi's avatar
add doc    
Federico Sismondi committed
48

49
# We can use the Message class to import json into Message objects:
Federico Sismondi's avatar
add doc    
Federico Sismondi committed
50
51
>>> m=MsgTestSuiteStart()
>>> m.to_json()
52
'{"_api_version": "1.0.1", "_type": "testcoordination.testsuite.start", "description": "Event test suite START"}'
Federico Sismondi's avatar
add doc    
Federico Sismondi committed
53
54
55
>>> json_message = m.to_json()
>>> obj=Message.from_json(json_message)
>>> type(obj)
56
<class 'messages.MsgTestSuiteStart'>
57

58
# We can use the library for generating error responses:
59
60
61
62
63
64
# the request:
>>> m = MsgSniffingStart()
>>>
# the error reply (note that we pass the message of the request to build the reply):
>>> err = MsgErrorReply(m)
>>> err
65
MsgErrorReply(_api_version = 1.0.1, _type = sniffing.start, error_code = Some error code TBD, error_message = Some error message TBD, ok = False, )
66
67
68
69
70
71
72
73
74
>>> m.reply_to
'control.sniffing.service.reply'
>>> err.routing_key
'control.sniffing.service.reply'

>>> m.correlation_id # doctest: +SKIP
'360b0f67-4455-43e3-a00f-eca91f2e84da'
>>> err.correlation_id # doctest: +SKIP
'360b0f67-4455-43e3-a00f-eca91f2e84da'
Federico Sismondi's avatar
add doc    
Federico Sismondi committed
75

76
77
78
"""

from collections import OrderedDict
79
import time
80
81
82
import json
import uuid

83
API_VERSION = '0.1.72'
84

85
86
87
88
89
90
91
92
93
94

# TODO use metaclasses instead?
class NonCompliantMessageFormatError(Exception):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)


Federico Sismondi's avatar
Federico Sismondi committed
95
class Message(object):
96
    def __init__(self, **kwargs):
97
98
        global API_VERSION

99
100
101
102
103
104
105
        try:
            # hard copy the message template
            self._msg_data = {k: v for k, v in self._msg_data_template.items()}
        except AttributeError: # if message is built directly using Message class then there's no data template
            self._msg_data={}
            self._msg_data_template={}

106

107
108
        # init properties
        self._properties = dict(
109
110
111
            content_type="application/json",
            message_id=str(uuid.uuid4()),
            timestamp=int(time.time())
112
113
        )

114
        try:
115
            # TODO deprecate .service in favour of .request
116
            if self.routing_key.endswith(".service"):
117
118
                import logging
                logging.warning('(!) deprecate .service in favour of .request')
119
120
                self._properties["reply_to"] = "%s.%s" % (self.routing_key, "reply")
                self._properties["correlation_id"] = self._properties["message_id"]
121
122
123
124
125

            elif self.routing_key.endswith(".request"):
                self._properties["reply_to"] = self.routing_key.replace(".request", ".reply")
                self._properties["correlation_id"] = self._properties["message_id"]

126
        except AttributeError:
127
            pass
128

129
        # rewrite default data fields with the passed args
130
131
132
        self._msg_data.update(kwargs)

        # add API's version
133
        if "_api_version" not in self._msg_data:
134
            self._msg_data["_api_version"] = API_VERSION
135

Federico Sismondi's avatar
Federico Sismondi committed
136
        # add values as object's attributes
137
138
139
        for key in self._msg_data:
            setattr(self, key, self._msg_data[key])

140
141
142
143
        # add props as objects attributes
        for key in self._properties:
            setattr(self, key, self._properties[key])

144
145
    def to_dict(self):
        resp = {}
146
147
        # let's use sorted so API returns items inside always in the same order
        for field in sorted(self._msg_data.keys()):
148
            resp[field] = getattr(self, field)
149

150
151
152
153
154
155
156
157
        return resp

    def to_odict(self):
        resp = {}
        # let's use sorted so API returns items inside always in the same order
        for field in sorted(self._msg_data.keys()):
            resp[field] = getattr(self, field)

158
        return OrderedDict(sorted(resp.items(), key=lambda t: t[0]))  # sorted by key
159
160
161
162

    def to_json(self):
        return json.dumps(self.to_dict())

163
    def get_properties(self):
164
165
166
167
        resp = OrderedDict()
        for field in self._properties:
            resp[field] = getattr(self, field)
        return resp
168

169
    def __str__(self):
170
171
172
173
174
175
176
        s = " - " * 20 + "\n"
        s += "Message routing key: %s" % self.routing_key
        s += "\n -  -  - \n"
        s += "Message properties: %s" % json.dumps(self.get_properties(), indent=4, )
        s += "\n -  -  - \n"
        s += "Message body: %s" % json.dumps(self.to_dict(), indent=4, )
        s += "\n" + " - " * 20
177
        return s
178

179
180
    def update_properties(self, **kwargs):
        for key, value in kwargs.items():
181
182
183
            # if key in self._properties:
            #     setattr(self, key, value)
            setattr(self, key, value)
184

185
186
    @classmethod
    def from_json(cls, body):
187
188
189
190
191
192
193
194
195
196
        """
        :param body: json string or string encoded as utf-8
        :return:  Message object generated from the body
        :raises NonCompliantMessageFormatError: If the message cannot be build from the provided json
        """

        if type(body) is str:
            message_dict = json.loads(body)
        # Note: pika re-encodes json.dumps strings as utf-8 for some reason, the following line undoes this
        elif type(body) is bytes:
197
            message_dict = json.loads(body.decode("utf-8"))
198
        else:
199
            raise NonCompliantMessageFormatError("Not a Json")
200

201
202
203
204
205
206
207
208
209
210
211
        return cls.from_dict(message_dict)

    @classmethod
    def from_dict(cls, message_dict):
        """
        :param body: dict
        :return:  Message object generated from the body
        :raises NonCompliantMessageFormatError: If the message cannot be build from the provided json
        """
        assert type(message_dict) is dict

212
        message_type = message_dict["_type"]
213

214
215
216
        if message_type in message_types_dict:
            return message_types_dict[message_type](**message_dict)
        else:
217
218
            raise NonCompliantMessageFormatError("Cannot load json message: %s" % str(message_dict))

219
    def __repr__(self):
220
        ret = "%s(" % self.__class__.__name__
221
        for key, value in self.to_dict().items():
222
223
            ret += "%s = %s, " % (key, value)
        ret += ")"
224
225
        return ret

226

227
228
229
230
231
class MsgReply(Message):
    """
    Auxiliary class which creates replies messages with fields based on the request.
    Routing key, corr_id and _type are generated based on the request message
    """
232

233
    def __init__(self, request_message=None, **kwargs):
234

235
236
237
238
239
240
        if request_message and hasattr(request_message, "routing_key"):
            # TODO (!) deprecate .service in favour of .request
            if request_message.routing_key.endswith(".service"):
                import logging
                logging.warning('(!) messages library | deprecate .service in favour of .request')
                self.routing_key = request_message.routing_key + ".reply"
241

242
243
244
245
246
247
248
249
250
251
            elif self.routing_key.endswith(".request"):
                self.routing_key = self.routing_key.replace(".request", ".reply")

            # if not data template, then let's build one for a reply
            # (possible when creating a MsgReply directly and not by using subclass)
            if not hasattr(self, "_msg_data_template"):
                self._msg_data_template = {
                    "_type": request_message._type,
                    "ok": True,
                }
252

253
            super(MsgReply, self).__init__(**kwargs)
254

255
256
257
            # overwrite correlation id template and attribute
            self._properties["correlation_id"] = request_message.correlation_id
            self.correlation_id = request_message.correlation_id
258

259
        else:  # note this doesnt generate amqp properties
260
            import logging
261
            logging.warning('(!) messages library | lazy response built, generating reply message without corr_id')
262
            super(MsgReply, self).__init__(**kwargs)
263

264
265
266
267
268
269
270
271
    def correlate_to(self, request_message):
        """
        add to reply message the right correlation information to request
        """
        # overwrite correlation id template and attribute
        self._properties["correlation_id"] = request_message.correlation_id
        self.correlation_id = request_message.correlation_id

272
273
274

class MsgErrorReply(MsgReply):
    """
275
    see section "F-Interop conventions" on top
276
    """
277

Federico Sismondi's avatar
Federico Sismondi committed
278
279
    def __init__(self, request_message, **kwargs):
        assert request_message
280
        # msg_data_template doesnt include _type cause this class is generic, we can only get this at init from request
Federico Sismondi's avatar
Federico Sismondi committed
281
        # so, let's copy the _type from request and let the MsgReply handle the rest of the fields
282
        self._msg_data_template["_type"] = request_message._type
283
        super(MsgErrorReply, self).__init__(request_message, **kwargs)
284
285

    _msg_data_template = {
286
        "ok": False,
287
        "error_message": "Some error message TBD",
288
        "error_code": "Some error code TBD"
289
290
    }

Federico Sismondi's avatar
Federico Sismondi committed
291

292
# # # # # # CORE API messages # # # # #
293
294

class MsgOrchestratorVersionReq(Message):
295
296
297
298
299
300
301
302
303
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for returning current version of SO
    """
304
    routing_key = "control.orchestrator.version.request"
305
306

    _msg_data_template = {
Federico Sismondi's avatar
Federico Sismondi committed
307
        "_type": "orchestrator.version.request"
308
    }
309

Federico Sismondi's avatar
Federico Sismondi committed
310

311
312
313
314
315
316
317
318
319
320
class MsgOrchestratorUsersList(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for returning user list of SO
    """
321
    routing_key = "control.orchestrator.users.list.request"
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

    _msg_data_template = {
        "_type": "orchestrator.users.list.request"
    }


class MsgOrchestratorUserAdd(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for adding a user to SO
    """
338

339
    routing_key = "control.orchestrator.users.add.request"
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355

    _msg_data_template = {
        "_type": "orchestrator.users.add.request"
    }


class MsgOrchestratorUserDelete(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for deleting a user from SO
    """
356

357
    routing_key = "control.orchestrator.users.delete.request"
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373

    _msg_data_template = {
        "_type": "orchestrator.users.delete.request"
    }


class MsgOrchestratorUserGet(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for getting a user from SO
    """
374

375
    routing_key = "control.orchestrator.users.get.request"
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391

    _msg_data_template = {
        "_type": "orchestrator.users.get.request"
    }


class MsgOrchestratorSessionsList(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for listing sessions from SO
    """
392
    routing_key = "control.orchestrator.sessions.list.request"
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408

    _msg_data_template = {
        "_type": "orchestrator.sessions.list.request"
    }


class MsgOrchestratorSessionsGet(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for getting a session from SO
    """
409
    routing_key = "control.orchestrator.sessions.get.request"
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425

    _msg_data_template = {
        "_type": "orchestrator.sessions.get.request"
    }


class MsgOrchestratorSessionsAdd(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for adding a session to SO
    """
426
    routing_key = "control.orchestrator.sessions.add.request"
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442

    _msg_data_template = {
        "_type": "orchestrator.sessions.add.request"
    }


class MsgOrchestratorSessionsDelete(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for deleting a session to SO
    """
443

444
    routing_key = "control.orchestrator.sessions.delete.request"
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461

    _msg_data_template = {
        "_type": "orchestrator.sessions.delete.request"
    }


class MsgOrchestratorSessionsUpdate(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for updating a session from SO
    """

462
    routing_key = "control.orchestrator.sessions.update.request"
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
    _msg_data_template = {
        "_type": "orchestrator.sessions.update.request"
    }


class MsgOrchestratorTestsGet(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for getting tests from SO
    """
478
    routing_key = "control.orchestrator.tests.get.request"
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494

    _msg_data_template = {
        "_type": "orchestrator.tests.get.request"
    }


class MsgOrchestratorTestsGetContributorName(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: UI -> SO

    Description: Message for getting tests from SO with contributor and name
    """
495
    routing_key = "control.orchestrator.tests.get_contributor_name.request"
496
497
498
499
500
501

    _msg_data_template = {
        "_type": "orchestrator.tests.get_contributor_name.request"
    }


502
503
# # # # # # UI API messages # # # # # # # #

Federico Sismondi's avatar
Federico Sismondi committed
504
505
506
507
508
509
510
511
512
class MsgUiReply(Message):
    routing_key = "ui.user.all.reply"

    _msg_data_template = {
        "_type": "ui.message.type.to.be.deprecated",
        "fields": [
        ]
    }

513
514
515
516
517
518
519
520
521
522
class MsgUiRequestTextInput(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: TT -> UI

    Description: Message for requesting action or information to user
    """
523
    routing_key = "ui.user.all.request"
524
525

    _msg_data_template = {
526
        "_type": "ui.message.type.to.be.deprecated",
Federico Sismondi's avatar
Federico Sismondi committed
527
        "tags": [],
528
        "fields": [
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
            {
                "name": "input_name",
                "type": "text"
            },
        ]
    }


class MsgUiRequestConfirmationButton(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: TT -> UI

    Description: Message for requesting confirmation button
    """
    routing_key = "ui.user.all.request"

    _msg_data_template = {
550
        "_type": "ui.message.type.to.be.deprecated",
Federico Sismondi's avatar
Federico Sismondi committed
551
        "tags": [],
552
553
        "fields": [
            {
554
                "name": "Please confirm that Uruguay es el mejor pais",
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
                "type": "button",
                "value": True
            },
        ]
    }


class MsgUiDisplay(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: TT -> UI

    Description: Message to display in user interface
    """
    routing_key = "ui.user.all.display"

    _msg_data_template = {
575
576
577
        "_type": "ui.message.type.to.be.deprecated",
        "level": None,
        "tags": [],
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
        "fields": [
            {
                "type": "p",
                "value": "Hello World!"
            },
        ]
    }


class MsgUiDisplayMarkdownText(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: TT -> UI

    Description: Message for displaying Mardown text to user interface
    """
    routing_key = "ui.user.all.display"

    _msg_data_template = {
600
        "_type": "ui.message.type.to.be.deprecated",
Federico Sismondi's avatar
Federico Sismondi committed
601
602
        "level": None,
        "tags": [],
603
604
605
606
607
        "fields": [
            {
                "type": "p",
                "value": "Hello World!"
            },
608
609
610
        ]
    }

611

612
# # # # # # AGENT MESSAGES # # # # # #
Federico Sismondi's avatar
Federico Sismondi committed
613

614

Federico Sismondi's avatar
Federico Sismondi committed
615
616
class MsgAgentTunStart(Message):
    """
617
    Requirements: Testing Tool MAY implement (if IP tun needed)
Federico Sismondi's avatar
Federico Sismondi committed
618

619
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
620

621
    Pub/Sub: Testing Tool -> Agent
Federico Sismondi's avatar
Federico Sismondi committed
622

623
    Description: Message for triggering start IP tun interface in OS where the agent is running
Federico Sismondi's avatar
Federico Sismondi committed
624
    """
625
    routing_key = "control.tun.toAgent.agent_TT"
Federico Sismondi's avatar
Federico Sismondi committed
626
627

    _msg_data_template = {
628
629
630
631
        "_type": "tun.start",
        "name": "agent_TT",
        "ipv6_prefix": "bbbb",
        "ipv6_host": ":3",
632
        "ipv6_no_forwarding": False,
633
634
635
        "ipv4_host": None,
        "ipv4_network": None,
        "ipv4_netmask": None,
Federico Sismondi's avatar
Federico Sismondi committed
636
637
638
    }


639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
class MsgAgentSerialStarted(Message):
    """
    Description: Message for indicating that agent serial interface has been started

    Type: Event

    Pub/Sub: Testing Tool -> Agent

    Description: TBD
    """
    routing_key = "control.serial.from.tbd"

    _msg_data_template = {
        "_type": "serial.started",
        "name": "tbd",
        "port": "tbd",
        "boudrate": "tbd",
    }


Federico Sismondi's avatar
Federico Sismondi committed
659
660
class MsgAgentTunStarted(Message):
    """
661
    Description: Message for indicating that agent tun has been started
Federico Sismondi's avatar
Federico Sismondi committed
662

663
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
664

665
    Pub/Sub: Agent -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
666

667
    Description: TBD
Federico Sismondi's avatar
Federico Sismondi committed
668
    """
669
    routing_key = "control.tun.from.tbd"
Federico Sismondi's avatar
Federico Sismondi committed
670
671

    _msg_data_template = {
672
673
674
675
676
677
678
        "_type": "tun.started",
        "name": "agent_TT",
        "ipv6_prefix": "bbbb",
        "ipv6_host": ":3",
        "ipv4_host": None,
        "ipv4_network": None,
        "ipv4_netmask": None,
679
        "ipv6_no_forwarding": False,
Federico Sismondi's avatar
Federico Sismondi committed
680
681
    }

682

683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
class MsgPacketInjectRaw(Message):
    """
    Description: Message to be captured by the agent an push into the correct embedded interface (e.g. tun, serial, etc..)

    Type: Event

    Pub/Sub: Testing Tool -> Agent

    Description: TBD
    """
    routing_key = None  # depends on the agent_id and the agent interface being used, re-write after creation

    _msg_data_template = {
        "_type": "packet.to_inject.raw",
        "timestamp": "1488586183.45",
        "interface_name": "tun0",
        "data": [96, 0, 0, 0, 0, 36, 0, 1, 254, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 255, 2, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 22, 58, 0, 5, 2, 0, 0, 1, 0, 143, 0, 112, 7, 0, 0, 0, 1, 4, 0, 0, 0, 255, 2, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]}


704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
class MsgPacketSniffedRaw(Message):
    """
    Description: Message captured by the agent in one of its embedded interfaces (e.g. tun, serial, etc..)

    Type: Event

    Pub/Sub: Agent -> Testing Tool

    Description: TBD
    """
    routing_key = None  # depends on the agent_id and the agent interface being used, re-write after creation

    _msg_data_template = {
        "_type": "packet.sniffed.raw",
        "timestamp": "1488586183.45",
        "interface_name": "tun0",
        "data": [96, 0, 0, 0, 0, 36, 0, 1, 254, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 255, 2, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 22, 58, 0, 5, 2, 0, 0, 1, 0, 143, 0, 112, 7, 0, 0, 0, 1, 4, 0, 0, 0, 255, 2, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]}
723

724
725

# # # # # # SESSION MESSAGES # # # # # #
726

727
class MsgTestingToolTerminate(Message):
728
    """
729
    Requirements: TT MUST listen to event, and handle a gracefully termination of all it's processes
Federico Sismondi's avatar
Federico Sismondi committed
730

731
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
732

733
    Pub/Sub: GUI, (or Orchestrator) -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
734

735
    Description: Testing tool should stop all it's processes gracefully.
736
    """
737
    routing_key = "control.session"
738
739

    _msg_data_template = {
740
        "_type": "testingtool.terminate",
741
        "description": "Command TERMINATE testing tool execution"
742
743
744
745
746
    }


class MsgTestingToolReady(Message):
    """
747
    Requirements: TT MUST publish event as soon as TT is up and listening on the event bus
Federico Sismondi's avatar
Federico Sismondi committed
748

749
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
750

751
    Pub/Sub: Testing Tool -> GUI
Federico Sismondi's avatar
Federico Sismondi committed
752

753
    Description: Used to indicate to the GUI that testing is ready to start the test suite
754
    """
755
    routing_key = "control.session"
756
757

    _msg_data_template = {
758
        "_type": "testingtool.ready",
759
        "description": "Testing tool READY to start test suite."
760
761
762
763
764
    }


class MsgTestingToolComponentReady(Message):
    """
765
    Requirements: Testing Tool SHOULD implement (other components should not subscribe to event)
Federico Sismondi's avatar
Federico Sismondi committed
766

767
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
768

769
    Pub/Sub: Any Testing tool's component -> Test Coordinator
Federico Sismondi's avatar
Federico Sismondi committed
770

771
    Description: Once a testing tool's component is ready, it should publish a compoennt ready message
772
    """
773
    routing_key = "control.session"
774
775

    _msg_data_template = {
776
        "_type": "testingtool.component.ready",
777
        "component": "SomeComponent",
778
        "description": "Component READY to start test suite."
779
780
781
    }


782
783
784
785
786
787
788
789
790
791
class MsgSessionChat(Message):
    """
    Requirements: GUI should implement

    Type: Event

    Pub/Sub: UI 1 (2) -> UI 2 (1)

    Description: Generic descriptor of chat messages
    """
792
    routing_key = "control.session"
793
794
795
796

    _msg_data_template = {
        "_type": "chat",
        "user_name": "Ringo",
797
        "node": "tbd",
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
        "description": "I've got blisters on my fingers!"
    }


class MsgSessionLog(Message):
    """
    Requirements: Testing Tool SHOULD implement

    Type: Event

    Pub/Sub: Any Testing tool's component -> user/devs interfaces

    Description: Generic descriptor of log messages
    """
    routing_key = "log.warning.the_drummer"

    _msg_data_template = {
        "_type": "log",
Federico Sismondi's avatar
Federico Sismondi committed
816
        "component": "misc",
817
        "message": "I've got blisters on my fingers!"
818
819
820
    }


821
822
class MsgSessionConfiguration(Message):
    """
823
    Requirements: TT MUST listen to event, and configure accordingly
824
825
826
827
828

    Type: Event

    Pub/Sub: Orchestrator -> Testing Tool

829
    Description: TT MUST listen to this message and configure the testsuite correspondingly
830
831
    """
    routing_key = "control.session"
832

833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
    _msg_data_template = {
        "_type": "session.configuration",
        "session_id": "666",
        "configuration": {
            'testsuite.testcases': [
                'someTestCaseId1',
                'someTestCaseId2'
            ]
        },
        "testing_tools": "f-interop/someTestToolId",
        "users": [
            "u1",
            "f-interop"
        ],
    }


# TODO deprecate this in favor of the generic MsgSessionConfiguration
851
class MsgInteropSessionConfiguration(Message):
852
    """
853
    Requirements: TT MUST listen to event
Federico Sismondi's avatar
Federico Sismondi committed
854

855
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
856

857
    Pub/Sub: Orchestrator -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
858

859
    Description: TT MUST listen to this message and configure the testsuite correspondingly
860
    """
861
    routing_key = "control.session"
862
863

    _msg_data_template = {
864
865
        "_type": "session.interop.configuration",
        "session_id": "TBD",
866
867
868
869
870
871
872
873
        "configuration":
            {
                'testsuite.testcases': [
                    'http://doc.f-interop.eu/tests/TD_COAP_CORE_01',
                    'http://doc.f-interop.eu/tests/TD_COAP'
                ]
            },

874
        "testing_tools": "f-interop/interoperability-coap",
875
        "users": [
876
877
878
            "u1",
            "f-interop"
        ],
879
        "tests": [
880
            {
Federico Sismondi's avatar
Federico Sismondi committed
881
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_01",
882
                "settings": {}
883
884
            },
            {
Federico Sismondi's avatar
Federico Sismondi committed
885
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_02",
886
887
888
                "settings": {}
            },
            {
Federico Sismondi's avatar
Federico Sismondi committed
889
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_03",
890
                "settings": {}
891
892
893
894
895
            }
        ]
    }


896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
class MsgAgentConfigured(Message):
    """
    Requirements: Testing Tool SHOULD publish event

    Type: Event

    Pub/Sub: Testing Tool -> GUI

    Description: The goal is to notify GUI when agents are ready to start the session
    """

    routing_key = "control.session"

    _msg_data_template = {
        "_type": "agent.configured",
911
        "description": "Agent successfully CONFIGURED",
912
913
914
915
        'name': 'agent_TT'
    }


916
917
class MsgTestingToolConfigured(Message):
    """
918
    Requirements: TT MUST publish event once session.configuration message has been processed.
Federico Sismondi's avatar
Federico Sismondi committed
919

920
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
921

922
    Pub/Sub: Testing Tool -> Orchestrator, GUI
Federico Sismondi's avatar
Federico Sismondi committed
923

924
    Description: The goal is to notify orchestrator and other components that the testing tool has been configured
925
926
927
928
929
    """

    routing_key = "control.session"

    _msg_data_template = {
930
        "_type": "testingtool.configured",
931
        "description": "Testing tool CONFIGURED",
932
        "session_id": "TBD",
933
934
935
        "testing_tools": "f-interop/interoperability-coap",
    }

936

937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
class MsgSessionCreated(Message):
    """
    Requirements: Session Orchestrator MUST publish message on common-services channel (on every session creation)

    Type: Event

    Pub/Sub: SO -> viz tools

    Description: The goal is to notify viz tools about new sessions
    """

    routing_key = "control.session.created"

    _msg_data_template = {
        "_type": "session.created",
        "description": "A new session has been created",
        "session_id": "TBD",
        "testing_tools": "TBD",
    }


958
959
class MsgTestingToolComponentShutdown(Message):
    """
960
    Requirements: Testing Tool SHOULD implement (other components should not subscribe to event)
Federico Sismondi's avatar
Federico Sismondi committed
961

962
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
963

964
    Pub/Sub: Any Testing tool's component -> Test Coordinator
Federico Sismondi's avatar
Federico Sismondi committed
965

966
967
    Description: tbd
    """
968
969
970
    routing_key = "control.session"

    _msg_data_template = {
971
        "_type": "testingtool.component.shutdown",
972
        "component": "SomeComponent",
973
        "description": "Component SHUTDOWN. Bye!"
974
975
    }

976
    # # # # # # TEST COORDINATION MESSAGES # # # # # #
977

978
979
980

class MsgTestSuiteStart(Message):
    """
981
    Requirements: TT MUST listen to event and start the test suite right after reception. MsgTestSuiteStarted
Federico Sismondi's avatar
Federico Sismondi committed
982

983
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
984

985
    Pub/Sub: GUI -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
986

987
    Description: tbd
988
989
    """

990
    # TODO change to control.testsuite
991
    routing_key = "control.testcoordination"
992
993

    _msg_data_template = {
994
        "_type": "testcoordination.testsuite.start",
995
        "description": "Test suite START command"
996
997
    }

998

Federico Sismondi's avatar
Federico Sismondi committed
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
class MsgTestSuiteStarted(Message):
    """
    Requirements: Testing Tool SHOULD publish to event

    Type: Event

    Pub/Sub: Testing Tool -> GUI

    Description: tbd
    """

1010
    # TODO change to control.testsuite
Federico Sismondi's avatar
Federico Sismondi committed
1011
1012
1013
1014
    routing_key = "control.testcoordination"

    _msg_data_template = {
        "_type": "testcoordination.testsuite.started",
1015
        "description": "Test suite STARTED"
Federico Sismondi's avatar
Federico Sismondi committed
1016
    }
1017

1018

1019
1020
class MsgTestSuiteFinish(Message):
    """
1021
    Requirements: TT MUST listen to event
Federico Sismondi's avatar
Federico Sismondi committed
1022

1023
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
1024

1025
    Pub/Sub: GUI -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
1026

1027
    Description: tbd
1028
1029
    """

1030
    # TODO change to control.testsuite
1031
1032
1033
    routing_key = "control.testcoordination"

    _msg_data_template = {
1034
        "_type": "testcoordination.testsuite.finish",
1035
        "description": "Test suite FINISH command"
1036
1037
    }

1038

1039
1040
class MsgTestCaseReady(Message):
    """
1041
    Requirements: TT MUST publish event
Federico Sismondi's avatar
Federico Sismondi committed
1042

1043
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
1044

Federico Sismondi's avatar
Federico Sismondi committed
1045
    Pub/Sub: Testing Tool -> GUI
Federico Sismondi's avatar
Federico Sismondi committed
1046

1047
1048
1049
    Description:
        - Used to indicate to the GUI (or automated-iut) which is the next test case to be executed.
        - This message is normally followed by a MsgTestCaseStart (from GUI-> Testing Tool)
1050
1051
    """

1052
    # TODO change to control.testsuite
1053
    routing_key = "control.testcoordination"
1054
1055

    _msg_data_template = {
1056
        "_type": "testcoordination.testcase.ready",
Federico Sismondi's avatar
Federico Sismondi committed
1057
1058
1059
        "description": "Next test case to be executed is TD_COAP_CORE_01",
        "testcase_id": "TD_COAP_CORE_01",
        "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_01",
1060
1061
        "objective": "Perform GET transaction(CON mode)",
        "state": None
1062
1063
1064
    }


1065
1066
class MsgTestCaseStart(Message):
    """
1067
    Requirements: TT MUST listen to event
Federico Sismondi's avatar
Federico Sismondi committed
1068

1069
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
1070

1071
    Pub/Sub: GUI -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
1072

1073
1074
    Description:
        - Message used for indicating the testing tool to start the test case (the one previously selected)
1075
1076
        - if testcase_id is Null then testing tool starts previously announced testcase in message
        "testcoordination.testcase.ready",
1077
    """
1078
    # TODO change to control.testsuite
1079
    routing_key = "control.testcoordination"
1080
1081

    _msg_data_template = {
1082
        "_type": "testcoordination.testcase.start",
1083
        "description": "Test case START command",
Federico Sismondi's avatar
Federico Sismondi committed
1084
        "testcase_id": None,
1085
1086
    }

Federico Sismondi's avatar
Federico Sismondi committed
1087

1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
class MsgTestCaseStarted(Message):
    """
    Requirements: Testing Tool SHOULD publish event

    Type: Event

    Pub/Sub: Testing Tool -> GUI

    Description:
        - Message used for indicating that testcase has started
    """
1099
    # TODO change to control.testsuite
1100
1101
1102
1103
    routing_key = "control.testcoordination"

    _msg_data_template = {
        "_type": "testcoordination.testcase.started",
1104
        "description": "Test case STARTED",
1105
1106
        "testcase_id": "TBD",
    }
1107

Federico Sismondi's avatar
Federico Sismondi committed
1108

1109
1110
# TODO MsgTestCaseNotes, see https://portal.etsi.org/cti/downloads/TestSpecifications/6LoWPAN_Plugtests_TestDescriptions_1.0.pdf

1111

1112
1113
class MsgTestCaseConfiguration(Message):
    """
1114
    Requirements: Testing Tool MAY publish event (if needed for executing the test case)
1115
1116
1117
1118
1119
1120
    Type: Event
    Pub/Sub: Testing Tool -> GUI & automated-iut
    Description:
        - Message used to indicate GUI and/or automated-iut which configuration to use.
        - IMPORTANT: deprecate this message in favor of MsgConfigurationExecute and MsgConfigurationExecuted
    """
1121
1122

    # TODO change to control.testsuite
1123
1124
1125
    routing_key = "control.testcoordination"
    _msg_data_template = {
        "_type": "testcoordination.testcase.configuration",