messages.py 76.4 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
Federico Sismondi committed
48

49
# We can use the Message class to import json into Message objects:
Federico Sismondi's avatar
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
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
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

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
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 # # # # # # # #

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 523
class MsgUiRequestTextInput(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: TT -> UI

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

    _msg_data_template = {
527
        "_type": "ui.message.type.to.be.deprecated",
528
        "tags": [],
529
        "fields": [
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
            {
                "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 = {
551
        "_type": "ui.message.type.to.be.deprecated",
552
        "tags": [],
553 554
        "fields": [
            {
555
                "name": "test_button",
556 557 558 559 560 561 562
                "type": "button",
                "value": True
            },
        ]
    }


563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
class MsgUiRequestSessionConfiguration(Message):
    """
    Requirements: ...

    Type: Event

    Pub/Sub: TT -> UI

    Description: Message for requesting configuration message to UI
    """
    routing_key = "ui.core.session.configuration.get.request"

    _msg_data_template = {
        "_type": "ui.core.session.configuration.get.request",
    }


580 581 582 583 584 585 586 587 588 589 590 591 592
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 = {
593 594 595
        "_type": "ui.message.type.to.be.deprecated",
        "level": None,
        "tags": [],
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
        "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 = {
618
        "_type": "ui.message.type.to.be.deprecated",
619 620
        "level": None,
        "tags": [],
621 622 623 624 625
        "fields": [
            {
                "type": "p",
                "value": "Hello World!"
            },
626 627 628
        ]
    }

629

630
# # # # # # AGENT MESSAGES # # # # # #
Federico Sismondi's avatar
Federico Sismondi committed
631

632

Federico Sismondi's avatar
Federico Sismondi committed
633 634
class MsgAgentTunStart(Message):
    """
635
    Requirements: Testing Tool MAY implement (if IP tun needed)
Federico Sismondi's avatar
Federico Sismondi committed
636

637
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
638

639
    Pub/Sub: Testing Tool -> Agent
Federico Sismondi's avatar
Federico Sismondi committed
640

641
    Description: Message for triggering start IP tun interface in OS where the agent is running
Federico Sismondi's avatar
Federico Sismondi committed
642
    """
643
    routing_key = "control.tun.toAgent.agent_TT"
Federico Sismondi's avatar
Federico Sismondi committed
644 645

    _msg_data_template = {
646 647 648 649
        "_type": "tun.start",
        "name": "agent_TT",
        "ipv6_prefix": "bbbb",
        "ipv6_host": ":3",
650
        "ipv6_no_forwarding": False,
651 652 653
        "ipv4_host": None,
        "ipv4_network": None,
        "ipv4_netmask": None,
Federico Sismondi's avatar
Federico Sismondi committed
654 655 656
    }


657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
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
677 678
class MsgAgentTunStarted(Message):
    """
679
    Description: Message for indicating that agent tun has been started
Federico Sismondi's avatar
Federico Sismondi committed
680

681
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
682

683
    Pub/Sub: Agent -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
684

685
    Description: TBD
Federico Sismondi's avatar
Federico Sismondi committed
686
    """
687
    routing_key = "control.tun.from.tbd"
Federico Sismondi's avatar
Federico Sismondi committed
688 689

    _msg_data_template = {
690 691 692 693 694 695 696
        "_type": "tun.started",
        "name": "agent_TT",
        "ipv6_prefix": "bbbb",
        "ipv6_host": ":3",
        "ipv4_host": None,
        "ipv4_network": None,
        "ipv4_netmask": None,
697
        "ipv6_no_forwarding": False,
Federico Sismondi's avatar
Federico Sismondi committed
698 699
    }

700

701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
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]}


722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
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]}
741

742 743

# # # # # # SESSION MESSAGES # # # # # #
744

745
class MsgTestingToolTerminate(Message):
746
    """
747
    Requirements: TT MUST listen to event, and handle a gracefully termination of all it's processes
Federico Sismondi's avatar
Federico Sismondi committed
748

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

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

753
    Description: Testing tool should stop all it's processes gracefully.
754
    """
755
    routing_key = "control.session"
756 757

    _msg_data_template = {
758
        "_type": "testingtool.terminate",
759
        "description": "Command TERMINATE testing tool execution"
760 761 762 763 764
    }


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

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

769
    Pub/Sub: Testing Tool -> GUI
Federico Sismondi's avatar
Federico Sismondi committed
770

771
    Description: Used to indicate to the GUI that testing is ready to start the test suite
772
    """
773
    routing_key = "control.session"
774 775

    _msg_data_template = {
776
        "_type": "testingtool.ready",
777
        "description": "Testing tool READY to start test suite."
778 779 780 781 782
    }


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

785
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
786

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

789
    Description: Once a testing tool's component is ready, it should publish a compoennt ready message
790
    """
791
    routing_key = "control.session"
792 793

    _msg_data_template = {
794
        "_type": "testingtool.component.ready",
795
        "component": "SomeComponent",
796
        "description": "Component READY to start test suite."
797 798 799
    }


800 801 802 803 804 805 806 807 808 809
class MsgSessionChat(Message):
    """
    Requirements: GUI should implement

    Type: Event

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

    Description: Generic descriptor of chat messages
    """
810
    routing_key = "control.session"
811 812 813 814

    _msg_data_template = {
        "_type": "chat",
        "user_name": "Ringo",
815
        "node": "tbd",
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
        "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
834
        "component": "misc",
835
        "message": "I've got blisters on my fingers!"
836 837 838
    }


839 840
class MsgSessionConfiguration(Message):
    """
841
    Requirements: TT MUST listen to event, and configure accordingly
842 843 844 845 846

    Type: Event

    Pub/Sub: Orchestrator -> Testing Tool

847
    Description: TT MUST listen to this message and configure the testsuite correspondingly
848 849
    """
    routing_key = "control.session"
850

851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
    _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
869
class MsgInteropSessionConfiguration(Message):
870
    """
871
    Requirements: TT MUST listen to event
Federico Sismondi's avatar
Federico Sismondi committed
872

873
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
874

875
    Pub/Sub: Orchestrator -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
876

877
    Description: TT MUST listen to this message and configure the testsuite correspondingly
878
    """
879
    routing_key = "control.session"
880 881

    _msg_data_template = {
882 883
        "_type": "session.interop.configuration",
        "session_id": "TBD",
884 885 886 887 888 889 890 891
        "configuration":
            {
                'testsuite.testcases': [
                    'http://doc.f-interop.eu/tests/TD_COAP_CORE_01',
                    'http://doc.f-interop.eu/tests/TD_COAP'
                ]
            },

892
        "testing_tools": "f-interop/interoperability-coap",
893
        "users": [
894 895 896
            "u1",
            "f-interop"
        ],
897
        "tests": [
898
            {
Federico Sismondi's avatar
Federico Sismondi committed
899
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_01",
900
                "settings": {}
901 902
            },
            {
Federico Sismondi's avatar
Federico Sismondi committed
903
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_02",
904 905 906
                "settings": {}
            },
            {
Federico Sismondi's avatar
Federico Sismondi committed
907
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_03",
908
                "settings": {}
909 910 911 912 913
            }
        ]
    }


914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
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",
929
        "description": "Agent successfully CONFIGURED",
930 931 932 933
        'name': 'agent_TT'
    }


934 935
class MsgTestingToolConfigured(Message):
    """
936
    Requirements: TT MUST publish event once session.configuration message has been processed.
Federico Sismondi's avatar
Federico Sismondi committed
937

938
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
939

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

942
    Description: The goal is to notify orchestrator and other components that the testing tool has been configured
943 944 945 946 947
    """

    routing_key = "control.session"

    _msg_data_template = {
948
        "_type": "testingtool.configured",
949
        "description": "Testing tool CONFIGURED",
950
        "session_id": "TBD",
951 952 953
        "testing_tools": "f-interop/interoperability-coap",
    }

954

955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
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",
    }


976 977
class MsgTestingToolComponentShutdown(Message):
    """
978
    Requirements: Testing Tool SHOULD implement (other components should not subscribe to event)
Federico Sismondi's avatar
Federico Sismondi committed
979

980
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
981

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

984 985
    Description: tbd
    """
986 987 988
    routing_key = "control.session"

    _msg_data_template = {
989
        "_type": "testingtool.component.shutdown",
990
        "component": "SomeComponent",
991
        "description": "Component SHUTDOWN. Bye!"
992 993
    }

994
    # # # # # # TEST COORDINATION MESSAGES # # # # # #
995

996 997 998

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

1001
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
1002

1003
    Pub/Sub: GUI -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
1004

1005
    Description: tbd
1006 1007
    """

1008
    # TODO change to control.testsuite
1009
    routing_key = "control.testcoordination"
1010 1011

    _msg_data_template = {
1012
        "_type": "testcoordination.testsuite.start",
1013
        "description": "Test suite START command"
1014 1015
    }

1016

Federico Sismondi's avatar
Federico Sismondi committed
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
class MsgTestSuiteStarted(Message):
    """
    Requirements: Testing Tool SHOULD publish to event

    Type: Event

    Pub/Sub: Testing Tool -> GUI

    Description: tbd
    """

1028
    # TODO change to control.testsuite
Federico Sismondi's avatar
Federico Sismondi committed
1029 1030 1031 1032
    routing_key = "control.testcoordination"

    _msg_data_template = {
        "_type": "testcoordination.testsuite.started",
1033
        "description": "Test suite STARTED"
Federico Sismondi's avatar
Federico Sismondi committed
1034
    }
1035

1036

1037 1038
class MsgTestSuiteFinish(Message):
    """
1039
    Requirements: TT MUST listen to event
Federico Sismondi's avatar
Federico Sismondi committed
1040

1041
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
1042

1043
    Pub/Sub: GUI -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
1044

1045
    Description: tbd
1046 1047
    """

1048
    # TODO change to control.testsuite
1049 1050 1051
    routing_key = "control.testcoordination"

    _msg_data_template = {
1052
        "_type": "testcoordination.testsuite.finish",
1053
        "description": "Test suite FINISH command"
1054 1055
    }

1056

1057 1058
class MsgTestCaseReady(Message):
    """
1059
    Requirements: TT MUST publish event
Federico Sismondi's avatar
Federico Sismondi committed
1060

1061
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
1062

Federico Sismondi's avatar
Federico Sismondi committed
1063
    Pub/Sub: Testing Tool -> GUI
Federico Sismondi's avatar
Federico Sismondi committed
1064

1065 1066 1067
    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)
1068 1069
    """

1070
    # TODO change to control.testsuite
1071
    routing_key = "control.testcoordination"
1072 1073

    _msg_data_template = {
1074
        "_type": "testcoordination.testcase.ready",
Federico Sismondi's avatar
Federico Sismondi committed
1075 1076 1077
        "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",
1078 1079
        "objective": "Perform GET transaction(CON mode)",
        "state": None
1080 1081 1082
    }


1083 1084
class MsgTestCaseStart(Message):
    """
1085
    Requirements: TT MUST listen to event
Federico Sismondi's avatar
Federico Sismondi committed
1086

1087
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
1088

1089
    Pub/Sub: GUI -> Testing Tool
Federico Sismondi's avatar
Federico Sismondi committed
1090

1091 1092
    Description:
        - Message used for indicating the testing tool to start the test case (the one previously selected)
1093 1094
        - if testcase_id is Null then testing tool starts previously announced testcase in message
        "testcoordination.testcase.ready",
1095
    """
1096
    # TODO change to control.testsuite
1097
    routing_key = "control.testcoordination"
1098 1099

    _msg_data_template = {
1100
        "_type": "testcoordination.testcase.start",
1101
        "description": "Test case START command",
1102
        "testcase_id": None,
1103 1104
    }

Federico Sismondi's avatar
Federico Sismondi committed
1105

1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
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
    """
1117
    # TODO change to control.testsuite
1118 1119 1120 1121
    routing_key = "control.testcoordination"

    _msg_data_template = {
        "_type": "testcoordination.testcase.started",
1122
        "description": "Test case STARTED",
1123 1124
        "testcase_id": "TBD",
    }
1125

Federico Sismondi's avatar
Federico Sismondi committed
1126

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

1129

1130 1131
class MsgTestCaseConfiguration(Message):
    """
1132
    Requirements: Testing Tool MAY publish event (if needed for executing the test case)
1133 1134 1135 1136 1137 1138
    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
    """
1139 1140

    # TODO change to control.testsuite
1141 1142 1143
    routing_key = "control.testcoordination"
    _msg_data_template = {
        "_type": "testcoordination.testcase.configuration",
Federico Sismondi's avatar
Federico Sismondi committed
1144
        "configuration_id": "COAP_CFG_01",
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
        "node": "coap_server",
        "testcase_id": "TBD",
        "testcase_ref": "TBD",
        "description":
            ["CoAP servers running service at [bbbb::2]:5683",
             "CoAP servers are requested to offer the following resources",
             ["/test", "Default test resource", "Should not exceed 64bytes"],
             ["/seg1/seg2/seg3", "Long path ressource", "Should not exceed 64bytes"],
             ["/query", "Ressource accepting query parameters", "Should not exceed 64bytes"],
             ["/separate",
              "Ressource which cannot be served immediately and which cannot be "
              "acknowledged in a piggy-backed way",
              "Should not exceed 64bytes"],
             ["/large", "Large resource (>1024 bytes)", "shall not exceed 2048bytes"],
             ["/large_update",
              "Large resource that can be updated using PUT method (>1024 bytes)",
              "shall not exceed 2048bytes"],
             ["/large_create",
              "Large resource that can be  created using POST method (>1024 bytes)",
              "shall not exceed 2048bytes"],
             ["/obs", "Observable resource which changes every 5 seconds",
              "shall not exceed 2048bytes"],
             ["/.well-known/core", "CoRE Link Format", "may require usage of Block options"]
             ]
    }


class MsgConfigurationExecute(Message):
    """
    Requirements: Testing Tool MAY publish event (if needed for executing the test case)
Federico Sismondi's avatar
Federico Sismondi committed
1175

1176
    Type: Event
Federico Sismondi's avatar
Federico Sismondi committed
1177

1178
    Pub/Sub: Testing Tool -> GUI & automated-iut
Federico Sismondi's avatar
Federico Sismondi committed
1179

1180 1181
    Description:
        - Message used to indicate GUI and/or automated-iut which configuration to use.
1182
    """
1183 1184

    # TODO change to control.testsuite
1185 1186 1187
    routing_key = "control.testcoordination"

    _msg_data_template = {
1188
        "_type": "testcoordination.configuration.execute",
Federico Sismondi's avatar
Federico Sismondi committed
1189
        "configuration_id": "COAP_CFG_01",
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
        "node": "coap_server",
        "testcase_id": "TBD",
        "testcase_ref": "TBD",
        "description":
            ["CoAP servers running service at [bbbb::2]:5683",
             "CoAP servers are requested to offer the following resources",
             ["/test", "Default test resource", "Should not exceed 64bytes"],
             ["/seg1/seg2/seg3", "Long path ressource", "Should not exceed 64bytes"],
             ["/query", "Ressource accepting query parameters", "Should not exceed 64bytes"],
             ["/separate",
              "Ressource which cannot be served immediately and which cannot be "
              "acknowledged in a piggy-backed way",
              "Should not exceed 64bytes"],
             ["/large", "Large resource (>1024 bytes)", "shall not exceed 2048bytes"],
             ["/large_update",
              "Large resource that can be updated using PUT method (>1024 bytes)",
              "shall not exceed 2048bytes"],
             ["/large_create",
              "Large resource that can be  created using POST method (>1024 bytes)",
              "shall not exceed 2048bytes"],
             ["/obs", "Observable resource which changes every 5 seconds",
              "shall not exceed 2048bytes"],
             ["/.well-known/core", "CoRE Link Format", "may require usage of Block options"]
             ]
1214 1215 1216
    }


1217 1218 1219 1220 1221 1222