messages.py 49 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# -*- coding: utf-8 -*-

"""
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.

Usage:
------
15
>>> from messages import * # doctest: +SKIP
16
>>> m = MsgTestCaseSkip()
17
>>> m
18
MsgTestCaseSkip(_type = testcoordination.testcase.skip, _api_version = 0.1.28, testcase_id = TD_COAP_CORE_02_v01, )
19 20
>>> m.routing_key
'control.testcoordination'
21 22
>>> m.message_id # doctest: +SKIP
'802012eb-24e3-45c4-9dcc-dc293c584f63'
23 24
>>> m.testcase_id
'TD_COAP_CORE_02_v01'
25

26 27 28
# also we can modify some of the fields (rewrite the default ones)
>>> m = MsgTestCaseSkip(testcase_id = 'TD_COAP_CORE_03_v01')
>>> m
29
MsgTestCaseSkip(_type = testcoordination.testcase.skip, _api_version = 0.1.28, testcase_id = TD_COAP_CORE_03_v01, )
30 31
>>> m.testcase_id
'TD_COAP_CORE_03_v01'
32

33 34
# and even export the message in json format (for example for sending the message though the amqp event bus)
>>> m.to_json()
35
'{"_type": "testcoordination.testcase.skip", "_api_version": "0.1.28", "testcase_id": "TD_COAP_CORE_03_v01"}'
Federico Sismondi's avatar
Federico Sismondi committed
36

37
# We can use the Message class to import json into Message objects:
Federico Sismondi's avatar
Federico Sismondi committed
38 39
>>> m=MsgTestSuiteStart()
>>> m.to_json()
40
'{"_type": "testcoordination.testsuite.start", "_api_version": "0.1.28"}'
Federico Sismondi's avatar
Federico Sismondi committed
41 42 43
>>> json_message = m.to_json()
>>> obj=Message.from_json(json_message)
>>> type(obj)
44
<class 'messages.MsgTestSuiteStart'>
45 46 47 48 49 50 51 52

# We can use the library for generating error responses to the requests:
# the request:
>>> m = MsgSniffingStart()
>>>
# the error reply (note that we pass the message of the request to build the reply):
>>> err = MsgErrorReply(m)
>>> err
53
MsgErrorReply(_type = sniffing.start, _api_version = 0.1.28, ok = False, error_code = Some error code TBD,
54
error_message = Some error message TBD, )
55 56 57 58 59 60 61 62 63
>>> 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
64

65 66 67
"""

from collections import OrderedDict
68
import time
69 70 71
import json
import uuid

72
API_VERSION = '0.1.28'
73

74 75 76 77 78 79 80 81 82 83 84

# TODO use metaclasses instead?

class NonCompliantMessageFormatError(Exception):
    def __init__(self, value):
        self.value = value

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


85 86
class Message:
    def __init__(self, **kwargs):
87 88 89
        global API_VERSION

        # hard copy the message template
90
        self._msg_data = {k: v for k, v in self._msg_data_template.items()}
91

92 93
        # init properties
        self._properties = dict(
94
                content_type="application/json",
95
                message_id=str(uuid.uuid4()),
96
                timestamp=int(time.time())
97 98
        )

99
        try:
100 101 102
            if self.routing_key.endswith(".service"):
                self._properties["reply_to"] = "%s.%s" % (self.routing_key, "reply")
                self._properties["correlation_id"] = self._properties["message_id"]
103
        except AttributeError:
104
            pass
105

106
        # rewrite default data fields with the passed args
107 108 109
        self._msg_data.update(kwargs)

        # add API's version
110
        self._msg_data["_api_version"] = API_VERSION
111 112 113 114 115

        # add values as objects attributes
        for key in self._msg_data:
            setattr(self, key, self._msg_data[key])

116 117 118 119
        # add props as objects attributes
        for key in self._properties:
            setattr(self, key, self._properties[key])

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

126
        return OrderedDict(sorted(resp.items(), key=lambda t: t[0]))  # sorted by key
127 128 129 130

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

131
    def get_properties(self):
132 133 134 135
        resp = OrderedDict()
        for field in self._properties:
            resp[field] = getattr(self, field)
        return resp
136

137
    def __str__(self):
138 139 140 141 142 143 144
        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
145
        return s
146

147 148 149 150 151
    def update_properties(self, **kwargs):
        for key, value in kwargs.items():
            if key in self._properties:
                setattr(self, key, value)

152 153
    @classmethod
    def from_json(cls, body):
154 155 156 157 158 159 160 161 162 163
        """
        :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:
164
            message_dict = json.loads(body.decode("utf-8"))
165
        else:
166
            raise NonCompliantMessageFormatError("Not a Json")
167 168

        # check fist if it's a response
169
        if "ok" in message_dict:
170
            # cannot build a complete reply message just from the json representation
171
            return
172

173
        message_type = message_dict["_type"]
174 175 176
        if message_type in message_types_dict:
            return message_types_dict[message_type](**message_dict)
        else:
177
            raise NonCompliantMessageFormatError("Cannot load json message: %s" % str(body))
178

179
    def __repr__(self):
180
        ret = "%s(" % self.__class__.__name__
181
        for key, value in self.to_dict().items():
182 183
            ret += "%s = %s, " % (key, value)
        ret += ")"
184 185
        return ret

186

187 188 189 190 191
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
    """
192

193 194 195 196 197 198 199
    def __init__(self, request_message, **kwargs):
        assert request_message

        self.routing_key = request_message.routing_key + ".reply"

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

206
        super(MsgReply, self).__init__(**kwargs)
207

208
        # overwrite correlation id template and attribute
209
        self._properties["correlation_id"] = request_message.correlation_id
210 211 212 213 214 215 216 217 218 219 220
        self.correlation_id = request_message.correlation_id


class MsgErrorReply(MsgReply):
    """
    F-Interop conventions:
        - if event is a service request then the routing keys is control.someFunctionality.service
        also, its reply will be control.someFunctionality.service.reply
        - reply.correlation_id = request.correlation_id

    """
221

222 223
    def __init__(self, request_message, **kwargs):
        assert request_message
224
        # msg_data_template doesnt include _type cause this class is generic, we can only get this at init from request
225
        # so, let's copy the _type from request and let the MsgReply handle the rest of the fields
226
        self._msg_data_template["_type"] = request_message._type
227
        super(MsgErrorReply, self).__init__(request_message, **kwargs)
228 229

    _msg_data_template = {
230 231 232
        "ok":            False,
        "error_message": "Some error message TBD",
        "error_code":    "Some error code TBD"
233 234
    }

235 236

# # # # # # AGENT MESSAGES # # # # # #
Federico Sismondi's avatar
Federico Sismondi committed
237 238 239 240 241

class MsgAgentTunStart(Message):
    """
    Message for triggering start IP tun interface in OS where the agent is running
    """
242
    routing_key = "control.tun.toAgent.agent_TT"
Federico Sismondi's avatar
Federico Sismondi committed
243 244

    _msg_data_template = {
245 246 247 248 249 250 251 252
        "_type":              "tun.start",
        "name":               "agent_TT",
        "ipv6_prefix":        "bbbb",
        "ipv6_host":          ":3",
        "ipv6_no_forwarding": False,
        "ipv4_host":          None,
        "ipv4_network":       None,
        "ipv4_netmask":       None,
Federico Sismondi's avatar
Federico Sismondi committed
253 254 255 256 257 258 259
    }


class MsgAgentTunStarted(Message):
    """
    Message for indicating that agent tun has been started
    """
260
    routing_key = "control.tun.from.agent_TT"
Federico Sismondi's avatar
Federico Sismondi committed
261 262

    _msg_data_template = {
263 264 265 266 267 268 269 270
        "_type":              "tun.started",
        "name":               "agent_TT",
        "ipv6_prefix":        "bbbb",
        "ipv6_host":          ":3",
        "ipv4_host":          None,
        "ipv4_network":       None,
        "ipv4_netmask":       None,
        "ipv6_no_forwarding": False,
Federico Sismondi's avatar
Federico Sismondi committed
271 272
    }

273

Federico Sismondi's avatar
Federico Sismondi committed
274 275 276 277 278 279 280 281
'''
TODO add packet.sniffed.raw
ROUTING_KEY: data.tun.fromAgent.coap_server_agent
 - - -
PROPS: {"delivery_mode": 2, "content_type": "application/json", "headers": {}, "priority": 0, "content_encoding": "utf-8"}
 - - -
BODY {"timestamp": "1488586183.45", "_type": "packet.sniffed.raw", "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]}
'''
282

283 284

# # # # # # SESSION MESSAGES # # # # # #
285

286
class MsgTestingToolTerminate(Message):
287 288 289 290 291
    """
    Testing Tool MUST-implement API endpoint
    GUI, (or Orchestrator?) -> Testing Tool
    Testing tool should stop all it's processes gracefully.
    """
292
    routing_key = "control.session"
293 294

    _msg_data_template = {
295
        "_type": "testingtool.terminate",
296 297 298 299 300 301 302 303 304 305
    }


class MsgTestingToolReady(Message):
    """
    Testing Tool MUST-implement notification.
    Testing Tool -> GUI

    Used to indicate to the GUI that testing is ready to start the test suite
    """
306
    routing_key = "control.session"
307 308

    _msg_data_template = {
309
        "_type":   "testingtool.ready",
310 311 312 313 314 315 316 317 318 319
        "message": "Testing tool ready to start test suite."
    }


class MsgTestingToolComponentReady(Message):
    """
    Testing Tools'internal call.
    Component x -> Test Coordinator
    Testing Tool SHOULD implement (design recommendation)
    """
320
    routing_key = "control.session"
321 322

    _msg_data_template = {
323 324
        "_type":     "testingtool.component.ready",
        "component": "SomeComponent",
325
        "message":   "Component ready to start test suite."
326 327 328
    }


329
class MsgInteropSessionConfiguration(Message):
330
    """
331 332 333
    Testing Tool MUST-implement API endpoint
    Orchestrator -> Testing Tool
    Testing tool should listen to this message and configure the testsuite correspondingly
334
    """
335
    routing_key = "control.session"
336 337

    _msg_data_template = {
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
        "_type":         "session.interop.configuration",
        "session_id":    "8ea6b6d5-ffcc-4a0e-ba93-92ee1befea23",
        "testing_tools": "f-interop/interoperability-coap",
        "users":         [
            "u1",
            "f-interop"
        ],
        "iuts":          [
            {
                "id":             "someImplementationFromAUser",
                "role":           "coap_server",
                "execution_mode": "user-assisted",
                "location":       "user-facilities",
                "owner":          "someUserName",
                "version":        "0.1"
            },
            {
                "id":             "automated_iut-coap_client-coapthon-v0.1",
                "role":           "coap_client",
                "execution_mode": "automated-iut",
                "location":       "central-server-docker",
                "owner":          "f-interop",
                "version":        "0.1"
            }
        ],
        "tests":         [
            {
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_01_v01",
                "settings":    {}
            },
            {
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_02_v01",
                "settings":    {}
            }
        ]
    }


class MsgTestingToolConfigured(Message):
    """
    Testing Tool MUST-implement notification.
    Testing Tool -> Orchestrator, GUI
    Notify orchestrator and other components that the testing tool has been configured
    """

    routing_key = "control.session"

    _msg_data_template = {
        "_type":         "testingtool.configured",
        "session_id":    "8ea6b6d5-ffcc-4a0e-ba93-92ee1befea23",
        "testing_tools": "f-interop/interoperability-coap",
    }

class MsgTestingToolComponentShutdown(Message):
    """
        Testing Tools'internal call.
        Component x -> Test Coordinator
        Testing Tool SHOULD implement (design recommendation)
        """
    routing_key = "control.session"

    _msg_data_template = {
        "_type":     "testingtool.component.shutdown",
        "component": "SomeComponent",
402
        "message":   "Component is shutting down. Bye!"
403 404
    }

405
    # # # # # # TEST COORDINATION MESSAGES # # # # # #
406

407 408 409 410 411 412 413

class MsgTestSuiteStart(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI -> Testing Tool
    """

414
    routing_key = "control.testcoordination"
415 416

    _msg_data_template = {
417
        "_type": "testcoordination.testsuite.start",
418 419 420
    }


421 422 423 424 425 426 427 428 429
class MsgTestSuiteFinish(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI -> Testing Tool
    """

    routing_key = "control.testcoordination"

    _msg_data_template = {
430
        "_type": "testcoordination.testsuite.finish",
431 432
    }

433

434 435 436 437 438 439 440 441 442
class MsgTestCaseReady(Message):
    """
    Testing Tool MUST-implement notification.
    Testing Tool -> GUI

    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)
    """

443
    routing_key = "control.testcoordination"
444 445

    _msg_data_template = {
446 447 448
        "_type":        "testcoordination.testcase.ready",
        "message":      "Next test case to be executed is TD_COAP_CORE_01_v01",
        "testcase_id":  "TD_COAP_CORE_01_v01",
449
        "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_01_v01",
450 451
        "objective":    "Perform GET transaction(CON mode)",
        "state":        None
452 453 454
    }


455 456 457 458 459 460
class MsgTestCaseStart(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI -> Testing Tool
    Message used for indicating the testing tool to start the test case (the one previously selected)
    """
461
    routing_key = "control.testcoordination"
462 463

    _msg_data_template = {
464
        "_type": "testcoordination.testcase.start",
465 466 467
    }


468 469 470 471 472 473 474 475 476
class MsgTestCaseConfiguration(Message):
    """
    Testing Tool MUST-implement notification
    Testing Tool -> GUI
    Messages used to indicate GUI which configuration to use.
    """
    routing_key = "control.testcoordination"

    _msg_data_template = {
477
        "_type":            "testcoordination.testcase.configuration",
478
        "configuration_id": "COAP_CFG_01_v01",
479 480 481
        "node":             "coap_server",
        "testcase_id":      "TBD",
        "testcase_ref":     "TBD",
482
        "message":
483 484 485 486 487 488 489 490 491 492 493
                            ["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"],
494 495
                             ["/large_create",
                              "Large resource that can be  created using POST method (>1024 bytes)",
496 497 498 499 500
                              "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"]
                             ]
501 502 503
    }


504 505 506 507 508 509 510
class MsgTestCaseStop(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI -> Testing Tool
    Message used for indicating the testing tool to stop the test case (the one running)
    """

511
    routing_key = "control.testcoordination"
512 513

    _msg_data_template = {
514
        "_type": "testcoordination.testcase.stop",
515 516 517 518 519 520 521 522 523
    }


class MsgTestCaseRestart(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI -> Testing Tool
    """

524
    routing_key = "control.testcoordination"
525 526

    _msg_data_template = {
527
        "_type": "testcoordination.testcase.restart",
528 529
    }

530 531 532 533 534 535 536 537 538

class MsgStepExecute(Message):
    """
    Testing Tool MUST-implement notification.
    Testing Tool -> GUI

    Used to indicate to the GUI (or automated-iut) which is the step to be executed by the user (or automated-IUT)
    """

539
    routing_key = "control.testcoordination"
540 541

    _msg_data_template = {
542 543 544 545 546
        "_type":               "testcoordination.step.execute",
        "message":             "Next test step to be executed is TD_COAP_CORE_01_v01_step_01",
        "step_id":             "TD_COAP_CORE_01_v01_step_01",
        "step_type":           "stimuli",
        "step_info":           [
547 548 549 550
            "Client is requested to send a GET request with",
            "Type = 0(CON)",
            "Code = 1(GET)"
        ],
551 552
        "step_state":          "executing",
        "node":                "coap_client",
553
        "node_execution_mode": "user_assisted",
554 555
        "testcase_id":         "TBD",
        "testcase_ref":        "TBD"
556 557
    }

558 559 560 561 562 563 564

class MsgStimuliExecuted(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI (or automated-IUT)-> Testing Tool
    """

565
    routing_key = "control.testcoordination"
566 567

    _msg_data_template = {
568
        "_type": "testcoordination.step.stimuli.executed",
569 570 571 572 573 574 575 576 577 578 579 580
    }


class MsgCheckResponse(Message):
    """
    Testing Tools'internal call.
    In the context of IUT to IUT test execution, this message is used for indicating that the previously executed
    messages (stimuli message and its reply) CHECK or comply to what is described in the Test Description.
    Testing tools' coordinator -> Testing Tool's analyzer (TAT)
    Not used in CoAP testing Tool (analysis of traces is done post mortem)
    """

581
    routing_key = "control.testcoordination"
582

583
    _msg_data_template = {
584 585 586
        "_type":           "testcoordination.step.check.response",
        "partial_verdict": "pass",
        "description":     "TAT says: step complies (checks) with specification"
587 588 589 590 591 592 593 594 595 596 597
    }


class MsgVerifyResponse(Message):
    """
    Testing Tool MUST-implement API endpoint
    Message provided by user declaring if the IUT VERIFY the step previously executed as described in the Test
    Description.
    GUI (or automated-IUT)-> Testing Tool
    """

598
    routing_key = "control.testcoordination"
599 600

    _msg_data_template = {
601 602 603
        "_type":           "testcoordination.step.verify.response",
        "verify_response": True,
        "response_type":   "bool"
604 605
    }

606

607 608 609 610 611 612 613
class MsgTestCaseFinish(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI (or automated-IUT)-> Testing Tool
    Not used in CoAP Testing Tool (test coordinator deduces it automatically by using the testcase's step sequence)
    """

614
    routing_key = "control.testcoordination"
615 616

    _msg_data_template = {
617
        "_type": "testcoordination.testcase.finish",
618 619
    }

620

621 622 623 624 625 626 627 628
class MsgTestCaseFinished(Message):
    """
    Testing Tool MUST-implement notification.
    Testing Tool -> GUI

    This message is followed by a verdict
    """

629
    routing_key = "control.testcoordination"
630 631

    _msg_data_template = {
632 633
        "_type":        "testcoordination.testcase.finished",
        "testcase_id":  "TD_COAP_CORE_01",
634
        "testcase_ref": "TBD",
635
        "message":      "Testcase finished"
636 637
    }

638

639 640 641 642
class MsgTestCaseSkip(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI (or automated-IUT)-> Testing Tool
643 644

    - testcase_id (optional) : if not provided then current tc is skipped
645 646
    """

647
    routing_key = "control.testcoordination"
648 649

    _msg_data_template = {
650 651
        "_type":       "testcoordination.testcase.skip",
        "testcase_id": "TD_COAP_CORE_02_v01",
652 653 654 655 656 657 658 659 660
    }


class MsgTestCaseSelect(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI (or automated-IUT)-> Testing Tool
    """

661
    routing_key = "control.testcoordination"
662 663

    _msg_data_template = {
664 665
        "_type":       "testcoordination.testcase.select",
        "testcase_id": "TD_COAP_CORE_03_v01",
666 667
    }

668

669 670 671 672 673 674
class MsgTestSuiteAbort(Message):
    """
    Testing Tool MUST-implement API endpoint
    GUI (or automated-IUT)-> Testing Tool
    """

675
    routing_key = "control.testcoordination"
676 677

    _msg_data_template = {
678
        "_type": "testcoordination.testsuite.abort",
679 680
    }

681

682 683
class MsgTestSuiteGetStatus(Message):
    """
684
    Testing Tool SHOULD-implement API endpoint
685 686 687 688 689 690
    Describes current state of the test suite.
    Format for the response not standardised.

    GUI -> Testing Tool
    """

691
    routing_key = "control.testcoordination.service"
692 693

    _msg_data_template = {
694
        "_type": "testcoordination.testsuite.getstatus",
695 696
    }

697

698
class MsgTestSuiteGetStatusReply(MsgReply):
699 700 701 702 703 704 705 706 707
    """
    Testing Tool SHOULD-implement API endpoint
    Describes current state of the test suite.
    Format for the response not standardised.

    Testing Tool -> GUI

    """

708
    routing_key = "control.testcoordination.service.reply"
709 710

    _msg_data_template = {
711 712
        "_type":          "testcoordination.testsuite.getstatus.reply",
        "ok":             True,
713 714
        "started":        True,
        "testcase_id":    "TD_COAP_CORE_01_v01",
715
        "testcase_state": "executing",
716
        "step_id":        "TD_COAP_CORE_01_v01_step_01"
717

718 719
    }

720

721 722
class MsgTestSuiteGetTestCases(Message):
    """
723
    Testing Tool's MUST-implement API endpoint
724 725 726 727
    GUI -> Testing Tool
    GUI MUST implement
    """

728
    routing_key = "control.testcoordination.service"
729 730

    _msg_data_template = {
731
        "_type": "testcoordination.testsuite.gettestcases",
732 733
    }

734 735 736 737 738 739 740

class MsgTestSuiteGetTestCasesReply(MsgReply):
    """
    Testing Tool's MUST-implement API endpoint
    Testing Tool -> GUI
    """

741
    routing_key = "control.testcoordination.service.reply"
742 743

    _msg_data_template = {
744 745
        "_type":   "testcoordination.testsuite.gettestcases.reply",
        "ok":      True,
746 747
        "tc_list": [
            {
748
                "testcase_id":  "TD_COAP_CORE_01_v01",
749
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_01_v01",
750 751
                "objective":    "Perform GET transaction(CON mode)",
                "state":        None
752 753
            },
            {
754
                "testcase_id":  "TD_COAP_CORE_02_v01",
755
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_02_v01",
756 757
                "objective":    "Perform DELETE transaction (CON mode)",
                "state":        None
758 759
            },
            {
760
                "testcase_id":  "TD_COAP_CORE_03_v01",
761
                "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_03_v01",
762 763
                "objective":    "Perform PUT transaction (CON mode)",
                "state":        None
764 765 766 767 768 769 770 771 772 773 774 775 776
            }
        ]
    }


class MsgTestCaseVerdict(Message):
    """
    Testing Tool MUST-implement notification.
    Testing Tool -> GUI

    Used to indicate to the GUI (or automated-iut) which is the final verdict of the testcase.
    """

777
    routing_key = "control.testcoordination"
778 779

    _msg_data_template = {
780 781 782
        "_type":            "testcoordination.testcase.verdict",
        "verdict":          "pass",
        "description":      "No interoperability error was detected,",
783 784 785 786 787 788 789 790 791 792 793
        "partial_verdicts": [
            ["TD_COAP_CORE_01_v01_step_02", None, "CHECK postponed", ""],
            ["TD_COAP_CORE_01_v01_step_03", None, "CHECK postponed", ""],
            ["TD_COAP_CORE_01_v01_step_04", "pass",
             "VERIFY step: User informed that the information was displayed correclty on his/her IUT", ""],
            ["CHECK_1_post_mortem_analysis", "pass",
             "<Frame   3: [bbbb::1 -> bbbb::2] CoAP [CON 43211] GET /test> Match: CoAP(type=0, code=1)"],
            ["CHECK_2_post_mortem_analysis", "pass",
             "<Frame   4: [bbbb::2 -> bbbb::1] CoAP [ACK 43211] 2.05 Content > Match: CoAP(code=69, mid=0xa8cb, tok=b'', pl=Not(b''))"],
            ["CHECK_3_post_mortem_analysis", "pass",
             "<Frame   4: [bbbb::2 -> bbbb::1] CoAP [ACK 43211] 2.05 Content > Match: CoAP(opt=Opt(CoAPOptionContentFormat()))"]],
794 795 796
        "testcase_id":      "TD_COAP_CORE_01_v01",
        "testcase_ref":     "http://f-interop.paris.inria.fr/tests/TD_COAP_CORE_01_v01",
        "objective":        "Perform GET transaction(CON mode)", "state": "finished"
797 798 799 800 801 802 803 804 805 806 807
    }


class MsgTestSuiteReport(Message):
    """
    Testing Tool MUST-implement notification.
    Testing Tool -> GUI

    Used to indicate to the GUI (or automated-iut) the final results of the test session.
    """

808
    routing_key = "control.testcoordination"
809 810

    _msg_data_template = {
811
        "_type": "testcoordination.testsuite.report",
812
        "TD_COAP_CORE_01_v01":
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
                 {
                     "verdict":     "pass",
                     "description": "No interoperability error was detected,",
                     "partial_verdicts":
                                    [
                                        ["TD_COAP_CORE_01_v01_step_02", None, "CHECK postponed", ""],
                                        ["TD_COAP_CORE_01_v01_step_03", None, "CHECK postponed", ""],
                                        ["TD_COAP_CORE_01_v01_step_04", "pass",
                                         "VERIFY step: User informed that the information was displayed correclty on his/her IUT",
                                         ""],
                                        ["CHECK_1_post_mortem_analysis", "pass",
                                         "<Frame   3: [bbbb::1 -> bbbb::2] CoAP [CON 43211] GET /test> Match: CoAP(type=0, code=1)"],
                                        ["CHECK_2_post_mortem_analysis", "pass",
                                         "<Frame   4: [bbbb::2 -> bbbb::1] CoAP [ACK 43211] 2.05 Content > Match: CoAP(code=69, mid=0xa8cb, tok=b'', pl=Not(b''))"],
                                        [
                                            "CHECK_3_post_mortem_analysis",
                                            "pass",
                                            "<Frame   4: [bbbb::2 -> bbbb::1] CoAP [ACK 43211] 2.05 Content > Match: CoAP(opt=Opt(CoAPOptionContentFormat()))"]
                                    ]
                 },
833 834

        "TD_COAP_CORE_02_v01":
835 836 837 838 839 840 841 842 843 844 845 846 847
                 {
                     "verdict":          "pass",
                     "description":      "No interoperability error was detected,",
                     "partial_verdicts": [
                         ["TD_COAP_CORE_02_v01_step_02", None, "CHECK postponed", ""],
                         ["TD_COAP_CORE_02_v01_step_03", None, "CHECK postponed", ""],
                         ["TD_COAP_CORE_02_v01_step_04", "pass",
                          "VERIFY step: User informed that the information was displayed correclty on his/her IUT",
                          ""], ["CHECK_1_post_mortem_analysis", "pass",
                                "<Frame   3: [bbbb::1 -> bbbb::2] CoAP [CON 43213] DELETE /test> Match: CoAP(type=0, code=4)"],
                         ["CHECK_2_post_mortem_analysis", "pass",
                          "<Frame   4: [bbbb::2 -> bbbb::1] CoAP [ACK 43213] 2.02 Deleted > Match: CoAP(code=66, mid=0xa8cd, tok=b'')"]]
                 }
848 849
    }

850
    # # # # # # SNIFFING SERVICES REQUEST MESSAGES # # # # # #
851

852 853 854 855 856 857 858 859

class MsgSniffingStart(Message):
    """
    Testing Tools'internal call.
    Coordinator -> Sniffer
    Testing Tool SHOULD implement (design recommendation)
    """

860
    routing_key = "control.sniffing.service"
861 862

    _msg_data_template = {
863 864 865 866
        "_type":        "sniffing.start",
        "capture_id":   "TD_COAP_CORE_01",
        "filter_if":    "tun0",
        "filter_proto": "udp port 5683"
867 868
    }

869

870 871 872 873 874 875 876
class MsgSniffingStartReply(MsgReply):
    """
    Testing Tools'internal call.
    Sniffer -> Coordinator
    Testing Tool SHOULD implement (design recommendation)
    """

877
    routing_key = "control.sniffing.service.reply"
878 879

    _msg_data_template = {
880 881
        "_type": "sniffing.start.reply",
        "ok":    True
882 883
    }

884

885 886 887 888 889 890 891
class MsgSniffingStop(Message):
    """
    Testing Tools'internal call.
    Coordinator -> Sniffer
    Testing Tool SHOULD implement (design recommendation)
    """

892
    routing_key = "control.sniffing.service"
893 894

    _msg_data_template = {
895
        "_type": "sniffing.stop",
896 897
    }

898

899 900 901 902 903 904 905
class MsgSniffingStoptReply(MsgReply):
    """
    Testing Tools'internal call.
    Sniffer -> Coordinator
    Testing Tool SHOULD implement (design recommendation)
    """

906
    routing_key = "control.sniffing.service.reply"
907 908

    _msg_data_template = {
909 910
        "_type": "sniffing.stop.reply",
        "ok":    True
911 912
    }

913

914 915 916 917 918 919 920
class MsgSniffingGetCapture(Message):
    """
    Testing Tools'internal call.
    Coordinator -> Sniffer
    Testing Tool SHOULD implement (design recommendation)
    """

921
    routing_key = "control.sniffing.service"
922 923

    _msg_data_template = {
924
        "_type":      "sniffing.getcapture",
925 926 927 928
        "capture_id": "TD_COAP_CORE_01",

    }

929

930
class MsgSniffingGetCaptureReply(MsgReply):
931
    routing_key = "control.sniffing.service.reply"
932 933

    _msg_data_template = {
934 935 936 937 938
        "_type":    "sniffing.getcapture.reply",
        "ok":       True,
        "file_enc": "pcap_base64",
        "filename": "TD_COAP_CORE_01.pcap",
        "value":    "1MOyoQIABAAAAAAAAAAAAMgAAAAAAAAA",  # empty PCAP
939 940
    }

941

942 943 944 945 946 947 948
class MsgSniffingGetCaptureLast(Message):
    """
    Testing Tools'internal call.
    Coordinator -> Sniffer
    Testing Tool SHOULD implement (design recommendation)
    """

949
    routing_key = "control.sniffing.service"
950 951

    _msg_data_template = {
952
        "_type": "sniffing.getlastcapture",
953
    }
954

955

956
class MsgSniffingGetCaptureLastReply(MsgReply):
957
    routing_key = "control.sniffing.service.reply"
958 959

    _msg_data_template = {
960 961 962 963 964
        "_type":    "sniffing.getlastcapture.reply",
        "ok":       True,
        "file_enc": "pcap_base64",
        "filename": "TD_COAP_CORE_01.pcap",
        "value":    "1MOyoQIABAAAAAAAAAAAAMgAAAAAAAAA",  # empty PCAP
965 966
    }

967
    # # # # # # ANALYSIS MESSAGES # # # # # #
968

969

970
class MsgInteropTestCaseAnalyze(Message):
971 972
    """
    Testing Tools'internal call.
973 974 975 976 977 978

    Method to launch an analysis from a pcap file or a token if the pcap file has already been provided.
    # TODO token support

    The method need a token or a pcap_file but doesn't allow someone to provide both.

979
    Coordinator -> Analyzer
980

981 982 983
    Testing Tool SHOULD implement (design recommendation)
    """

984
    PCAP_empty_base64 = "1MOyoQIABAAAAAAAAAAAAMgAAAAAAAAA"
985

986
    routing_key = "control.analysis.service"
987 988

    _msg_data_template = {
989
        "_type":        "analysis.interop.testcase.analyze",
990
        "testcase_id":  "TD_COAP_CORE_01",
991
        "testcase_ref": "http://doc.f-interop.eu/tests/TD_COAP_CORE_01_v01",
992 993 994
        "file_enc":     "pcap_base64",
        "filename":     "TD_COAP_CORE_01.pcap",
        "value":        PCAP_empty_base64,
995 996
    }

997

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
class MsgInteropTestCaseAnalyzeReply(MsgReply):
    """
    Testing Tools'internal call.
    Analyzer -> Coordinator
    Testing Tool SHOULD implement (design recommendation)

    The recommended structure for the partial_verdicts field is a list of partial verdicts with the following
    requirements:
     - each one of those elements of the list correspond to one CHECK or VERIFY steps of the test description
     - first value of the list MUST be a "pass", "fail", "inconclusive" or eventually "error" partial verdict (string)
     - the second value MUST be a string with a description of partial verdict (intended for the user)
     - more values elements MAY be added to the list

    """

    _msg_data_template = {
1014 1015 1016 1017 1018 1019 1020
        "_type":            "analysis.interop.testcase.analyze.reply",
        "ok":               True,
        "verdict":          "pass",
        "analysis_type":    "postmortem",
        "description":      "The test purpose has been verified without any fault detected",
        "review_frames":    [],
        "token":            "0lzzb_Bx30u8Gu-xkt1DFE1GmB4",
1021 1022
        "partial_verdicts": [
            [
1023 1024
                "pass",
                "<Frame   1: [127.0.0.1 -> 127.0.0.1] CoAP [CON 43521] GET /test> Match: CoAP(type=0, code=1)"
1025
            ],
1026 1027 1028 1029 1030

            [
                "pass",
                "<Frame   2: [127.0.0.1 -> 127.0.0.1] CoAP [ACK 43521] 2.05 Content > Match: CoAP(code=69, mid=0xaa01, \
                tok=b'b\\xda', pl=Not(b''))"
1031
            ],
1032 1033 1034 1035
            [
                "pass",
                "<Frame   2: [127.0.0.1 -> 127.0.0.1] CoAP [ACK 43521] 2.05 Content > \
                Match: CoAP(opt=Opt(CoAPOptionContentFormat()))"
1036
            ]
1037
        ],
1038 1039
        "testcase_id":      "TD_COAP_CORE_01",
        "testcase_ref":     "http://doc.f-interop.eu/tests/TD_COAP_CORE_01_v01",
1040 1041
    }

1042
    # # # # # # DISSECTION MESSAGES # # # # # #
1043

1044

1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
class MsgDissectionDissectCapture(Message):
    """
    Testing Tools'internal call.
    Coordinator -> Dissector
    and
    Analyzer -> Dissector
    Testing Tool SHOULD implement (design recommendation)
    """

    PCAP_COAP_GET_OVER_TUN_INTERFACE_base64 = "1MOyoQIABAAAAAAAAAAAAMgAAABlAAAAqgl9WK8aBgA7AAAAOwAAAGADPxUAExFAu7s" \
                                              "AAAAAAAAAAAAAAAAAAbu7AAAAAAAAAAAAAAAAAALXvBYzABNZUEABcGO0dGVzdMECqg" \
                                              "l9WMcaBgCQAAAAkAAAAGAAAAAAaDr//oAAAAAAAAAAAAAAAAAAA7u7AAAAAAAAAAAAA" \
                                              "AAAAAGJAAcTAAAAALu7AAAAAAAAAAAAAAAAAAK7uwAAAAAAAAAAAAAAAAACBAgAAAAA" \
                                              "AABgAz8VABMRQLu7AAAAAAAAAAAAAAAAAAG7uwAAAAAAAAAAAAAAAAAC17wWMwATWVB" \
                                              "AAXBjtHRlc6oJfVjSGgYAOwAAADsAAABgAz8VABMRP7u7AAAAAAAAAAAAAAAAAAG7uw" \
                                              "AAAAAAAAAAAAAAAAAC17wWMwATWVBAAXBjtHRlc3TBAg=="

1062
    routing_key = "control.dissection.service"
1063 1064

    _msg_data_template = {
1065
        "_type":              "dissection.dissectcapture",
1066 1067 1068
        "file_enc":           "pcap_base64",
        "filename":           "TD_COAP_CORE_01.pcap",
        "value":              PCAP_COAP_GET_OVER_TUN_INTERFACE_base64,
1069
        "protocol_selection": "coap",
1070 1071 1072
    }


1073 1074 1075 1076 1077 1078 1079 1080 1081
class MsgDissectionDissectCaptureReply(MsgReply):
    """
    Testing Tools'internal call.
    Dissector -> Coordinator
    and
    Dissector -> Analyzer
    Testing Tool SHOULD implement (design recommendation)
    """

1082
    _frames_example = [
1083
        {
1084 1085 1086 1087
            "_type":          "frame",
            "id":             1,
            "timestamp":      1464858393.547275,
            "error":          None,
1088 1089
            "protocol_stack": [
                {
1090 1091 1092
                    "_type":          "protocol",
                    "_protocol":      "NullLoopback",
                    "AddressFamily":  "2",
1093 1094 1095
                    "ProtocolFamily": "0"
                },
                {
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
                    "_type":              "protocol",
                    "_protocol":          "IPv4",
                    "Version":            "4",
                    "HeaderLength":       "5",
                    "TypeOfService":      "0x00",
                    "TotalLength":        "41",
                    "Identification":     "0x71ac",
                    "Reserved":           "0",
                    "DontFragment":       "0",
                    "MoreFragments":      "0",
                    "FragmentOffset":     "0",
                    "TimeToLive":         "64",
                    "Protocol":           "17",
                    "HeaderChecksum":     "0x0000",
                    "SourceAddress":      "127.0.0.1",
1111
                    "DestinationAddress": "127.0.0.1",
1112
                    "Options":            "b''"
1113
                }
1114 1115 1116
            ]
        },
    ]
1117 1118

    _msg_data_template = {
1119 1120 1121 1122
        "_type":  "dissection.dissectcapture.reply",
        "ok":     True,
        "token":  "0lzzb_Bx30u8Gu-xkt1DFE1GmB4",
        "frames": _frames_example
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
    }


class MsgDissectionAutoDissect(Message):
    """
    Testing Tool's MUST-implement.
    Testing Tool -> GUI
    GUI MUST display this info during execution:
     - interop session
     - conformance session
     - performance ?
     - privacy?

    """
1137
    routing_key = "control.dissection"
1138

1139
    _frames_example = MsgDissectionDissectCaptureReply._frames_example
1140 1141

    _msg_data_template = {
1142 1143 1144
        "_type":        "dissection.autotriggered",
        "token":        "0lzzb_Bx30u8Gu-xkt1DFE1GmB4",
        "frames":       _frames_example,
1145
        "testcase_id":  "TBD",
1146
        "testcase_ref": "TBD"
1147 1148
    }

1149
    # # # # # # PRIVACY TESTING TOOL MESSAGES # # # # # #
Luca Lamorte's avatar
Luca Lamorte committed
1150 1151 1152 1153 1154


class MsgPrivacyAnalyze(Message):
    """
        Testing Tool's MUST-implement.
1155
        Analyze PCAP File for Privacy checks.
Luca Lamorte's avatar
Luca Lamorte committed
1156
    """
1157
    routing_key = "control.privacy.service"
Luca Lamorte's avatar
Luca Lamorte committed
1158 1159

    # TODO: This message should be update with a valuable privacy example
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
    # PCAP_COAP_GET_OVER_TUN_INTERFACE_base64 = "1MOyoQIABAAAAAAAAAAAAMgAAABlAAAAqgl9WK8aBgA7AAAAOwAAAGADPxUAExFAu7s" \
    #                                           "AAAAAAAAAAAAAAAAAAbu7AAAAAAAAAAAAAAAAAALXvBYzABNZUEABcGO0dGVzdMECqg" \
    #                                           "l9WMcaBgCQAAAAkAAAAGAAAAAAaDr//oAAAAAAAAAAAAAAAAAAA7u7AAAAAAAAAAAAA" \
    #                                           "AAAAAGJAAcTAAAAALu7AAAAAAAAAAAAAAAAAAK7uwAAAAAAAAAAAAAAAAACBAgAAAAA" \
    #                                           "AABgAz8VABMRQLu7AAAAAAAAAAAAAAAAAAG7uwAAAAAAAAAAAAAAAAAC17wWMwATWVB" \
    #                                           "AAXBjtHRlc6oJfVjSGgYAOwAAADsAAABgAz8VABMRP7u7AAAAAAAAAAAAAAAAAAG7uw" \
    #                                           "AAAAAAAAAAAAAAAAAC17wWMwATWVBAAXBjtHRlc3TBAg=="

    PCAP_COAP_GET_OVER_TUN_INTERFACE_base64 = "Cg0NCpgAAABNPCsaAQAAAP//////////AwAuAE1hYyBPUyBYIDEwLjEyLjQsIGJ1aWxk" \
                                              "IDE2RTE5NSAoRGFyd2luIDE2LjUuMCkAAAQAPQBEdW1wY2FwIChXaXJlc2hhcmspIDIu" \
                                              "Mi4wICh2Mi4yLjAtMC1nNTM2OGM1MCBmcm9tIG1hc3Rlci0yLjIpAAAAAAAAAJgAAAAB" \
                                              "AAAAXAAAAAAAAAAAAAQAAgAEAHR1bjAJAAEABgAAAAwALgBNYWMgT1MgWCAxMC4xMi40" \
                                              "LCBidWlsZCAxNkUxOTUgKERhcndpbiAxNi41LjApAAAAAAAAXAAAAAUAAABsAAAAAAAA" \
                                              "AIdOBQCsif6eAQAcAENvdW50ZXJzIHByb3ZpZGVkIGJ5IGR1bXBjYXACAAgAh04FAN2Z" \
                                              "ip4DAAgAh04FAKGJ/p4EAAgAAAAAAAAAAAAFAAgAAAAAAAAAAAAAAAAAbAAAAA=="
Luca Lamorte's avatar
Luca Lamorte committed
1175 1176

    _msg_data_template = {
1177 1178
        "_type":    "privacy.analyze",
        "value":    PCAP_COAP_GET_OVER_TUN_INTERFACE_base64,
Luca Lamorte's avatar
Luca Lamorte committed
1179 1180 1181 1182 1183
        "file_enc": "pcap_base64",
        "filename": "TD_PRIVACY_DEMO_01.pcap",
    }


1184 1185 1186 1187 1188 1189
class MsgPrivacyAnalyzeReply(MsgReply):
    """
            Testing Tool's MUST-implement.
            Response of Analyze request from GUI
    """

1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
    _privacy_empty_report = {"type":           "Anomalies Report",
                             "protocols":      ["coap"],
                             "conversation":   [],
                             "status":         "none",
                             "testing_tool":   "Privacy Testing Tool",
                             "byte_exchanged": 0,
                             "timestamp":      1493798811.53124,
                             "is_final":       True,
                             "packets":        {},
                             "version":        "0.0.1"}
1200 1201

    _msg_data_template = {
1202 1203 1204 1205
        "_type":       "privacy.analyze.reply",
        "ok":          True,
        "verdict":     _privacy_empty_report,
        "testcase_id": "TBD",
1206 1207
    }

1208

Luca Lamorte's avatar
Luca Lamorte committed
1209 1210 1211 1212 1213
class MsgPrivacyGetConfiguration(Message):
    """
           Read Privacy configuration.
           GUI MUST display this info during setup
    """
1214
    routing_key = "control.privacy.service"
Luca Lamorte's avatar
Luca Lamorte committed
1215 1216 1217 1218 1219

    _msg_data_template = {
        "_type": "privacy.configuration.get",
    }

1220

1221 1222 1223 1224 1225
class MsgPrivacyGetConfigurationReply(MsgReply):
    """
           Read Privacy configuration.
           GUI MUST display this info during setup
    """
1226
    routing_key = "control.privacy.service.reply"
1227 1228

    _msg_data_template = {
1229 1230 1231
        "_type":         "privacy.configuration.get.reply",
        "configuration": {},
        "ok":            True,
1232 1233
    }

Luca Lamorte's avatar
Luca Lamorte committed
1234 1235 1236 1237 1238 1239

class MsgPrivacySetConfiguration(Message):
    """
        Write Privacy configuration.
        GUI MUST display this info during setup
    """
1240
    routing_key = "control.privacy.service"
Luca Lamorte's avatar
Luca Lamorte committed
1241

1242
    CFG_EXAMPLE = dict()