messages_doc.py 9.47 KB
Newer Older
1 2 3
"""
Module for building automatically the doc of the API messages in markdown format.
"""
4
import inspect
5
import logging
6 7
from messages import *

8
gitlab_url = 'https://gitlab.f-interop.eu/f-interop-contributors/utils/blob/master/messages/messages.py'
9
doc_parser = 'https://gitlab.f-interop.eu/f-interop-contributors/utils/blob/master/messages_doc.py'
Federico Sismondi's avatar
Federico Sismondi committed
10
header = """Events (core API)
11

12
This section describes the format of the messages used in F-Interop.
13 14

This section of the documentation is autogenerated by
15 16 17 18
[tool](%s)

Check out the messages library
[tool](%s)
19 20

Version %s
21
""" % (doc_parser, gitlab_url, API_VERSION)
22 23 24 25

services = []
events = []

26

27
def message_amqp_section(file, message_instance):
28 29
    #file.write("\n\n```amqp")
    file.write("\n\n```")
30 31 32 33 34
    try:
        file.write("\n %s" % str(message_instance))
    except Exception as e:
        logging.error("\n FAILED FOR (!) ->  n %s" % repr(message_instance))
        logging.error(e)
35 36 37
    file.write("\n ```")
    return

38

39
def message_json_section(file, message_instance):
40 41
    #file.write("\n\n```json")
    file.write("\n\n```")
42 43 44 45 46
    try:
        file.write("\n %s" % json.dumps(message_instance.to_dict(), indent=4, ))
    except Exception as e:
        logging.error("\n FAILED FOR (!) ->  n %s" % repr(message_instance))
        logging.error(e)
47 48 49
    file.write("\n ```")
    return

50

51 52 53 54 55 56 57 58 59 60 61
def print_doc_tables(services, events):
    """

    expected result (this method cannot do all this, some modifs need to be done manually)

    ### API services

    TBD provides the following services:

    |SERVICES | DESCRIPTION|
    |---| ---|
62 63 64 65
    |[*testcoordination.testsuite.getstatus*](#testcoordination-testsuite-getstatus) | Message for debugging
    purposes. The coordination component returns the status of the execution |
    |[*testcoordination.testsuite.gettestcases*](#testcoordination-testsuite-gettestcases) | Message for requesting
    the list of test cases included in the test suite.|
66 67 68 69 70 71 72

    ### API events

    TBD listens and consumes the following messages from the bus:

    |MESSAGES CONSUMED | DESCRIPTION|
    |---| ---|
73 74 75 76 77 78
    |[*testcoordination.testsuite.start*](#testcoordination-testsuite-start) | Message for triggering start of test
    suite. The command is given by one of the users of the session.|
    |[*testcoordination.testsuite.abort*](#testcoordination-testsuite-abort)| Message for aborting the ongoing test
    session.|
    |[*testcoordination.testcase.skip*](#testcoordination-testcase-skip) | Message for skipping a test case.
    Coordinator passes to the next test case if there is any left.|
79 80 81 82 83 84

    Coordinator generates and publishes the following messages:

    |MESSAGES PUBLISHED | DESCRIPTION|
    |---| ---|
    |[*testcoordination.testcase.next*](#testcoordination-testcase-next) | Indicates next testcase to be executed |
85 86
    |[*testcoordination.testsuite.finished*](#testcoordination-testsuite-finished) | Indicates there's no more test
    cases to execute |
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    |[*testcoordination.error*](#testcoordination-error) | Message used to indicate errors on coordiation component |


    """

    head_1 = """### API services

TBD provides the following services:

|SERVICES | DESCRIPTION|
|---| ---|"""

    head_2 = """### API events

TBD listens and consumes the following messages from the bus:

|MESSAGES CONSUMED | DESCRIPTION|
|---| ---|"""

    head_3 = """TBD generates and publishes the following messages:

|MESSAGES PUBLISHED | DESCRIPTION|
|---| ---|"""

    def table_row(event_type):
112 113 114 115 116 117
        s = ""
        s += "|[*%s*](#%s) | Some description that needs to be writen manually |" \
             % (
                 event_type,
                 event_type.replace('.', '-')
             )
118 119 120 121
        return s

    print(head_1)
    for s in services:
122
        print(table_row(s.routing_key))
123 124 125 126 127

    print()
    print()
    print(head_2)
    for e in events:
128
        print(table_row(e.routing_key))
129 130 131 132 133

    print()
    print()
    print(head_3)
    for e in events:
134
        print(table_row(e.routing_key))
135 136


137 138 139
def generate_doc_section_into_file(file_to_write, section, list_of_message_classes):
    f = file_to_write
    f.write('\n\n## %s' % (section))
140

141
    for msg_class in list_of_message_classes:
142

143
        msg_type = msg_class().routing_key
144
        print('generating doc for %s,%s' % (msg_type, msg_class))
145

146 147
        # Message Type
        f.write('\n\n\n### %s' % (msg_type))
148

149
        # Header
150
        # f.write('\n\n#### Description:\n\n')
151

152 153
        # markdown table header
        f.write("\n| []() | |\n| --- | --- |\n")
154

155 156 157 158 159
        try:
            # add routing key in table
            f.write("|Routing key|{0}|\n".format(msg_class().routing_key))
        except TypeError as te:
            print("No routing key found for %s" % repr(msg_class))
160

161 162
        md_bullet_list = ''
        unknown = ''
163

164 165 166
        # Message class docstring to table
        for line in msg_class.__doc__.splitlines():
            if line and not line.isspace():
167

168 169 170 171 172 173 174 175
                if "description:" in str(line).lower():
                    sp_line = line.split(':')
                    if len(sp_line) > 1:
                        f.write("|Description:|{0}|\n".format(sp_line[1].strip()))
                    elif len(sp_line) == 1:
                        f.write("|Description:||\n")
                    else:
                        raise NotImplementedError()
176

177 178
                elif '- ' in line:
                    md_bullet_list += "||{0}|\n".format(line.strip())
179

180 181 182
                elif "Type:" in line:
                    sp_line = line.split(':')
                    f.write('|{0}|{1}|\n'.format(sp_line[0].strip(), sp_line[1].strip()))
183

184 185 186
                elif "Requirements:" in line:
                    sp_line = line.split(':')
                    f.write('|{0}|{1}|\n'.format(sp_line[0].strip(), sp_line[1].strip()))
187

188 189 190
                elif "Pub/Sub:" in line or "Typical_use:" in line:
                    sp_line = line.split(':')
                    f.write('|{0}|{1}|\n'.format(sp_line[0].strip(), sp_line[1].strip()))
191

192 193 194
                else:
                    if md_bullet_list is not '':
                        md_bullet_list += '||{0}|\n'.format(line)
195
                    else:
196
                        unknown += '||{0}|\n'.format(line)
197

198 199
        f.write(md_bullet_list)
        f.write(unknown)
200

201 202 203 204
        # Message code source:
        line_number = (inspect.findsource(msg_class)[1])
        url = gitlab_url + "#L%s" % line_number
        f.write('\n\nSource code: [%s](%s)\n' % (msg_class.__name__, url))
205

206
        msg_instance = None
207

208
        # Messages's example AMQP + JSON
209
        if 'reply' not in msg_class.routing_key:  # Message is not a reply
210
            msg_instance = msg_class()
211

212
        else:  # Message is a reply -> we need to generate it using a request (messages.py library API requierement)
213

214 215 216 217 218
            reply_routing_key = msg_class.routing_key
            request_routing_key = reply_routing_key.replace("reply", "request")
            # get message class of request
            request_class = rk_pattern_to_message_type_map.get_message_type(request_routing_key)
            if request_class is None:
219
                raise Exception('cannot process message event: %s' % msg_type)
220 221 222
            # create request
            request_instance = request_class()
            # create reply
223
            msg_instance = msg_class(request_message=request_instance)
224

225 226 227
        # add the amqo + json section
        message_amqp_section(f, msg_instance)
        message_json_section(f, msg_instance)
228

229
        try:
230
            if 'request' in msg_instance.routing_key:
231 232 233
                services.append(msg_instance)
            else:
                events.append(msg_instance)
234 235 236 237 238 239 240 241 242 243
        except TypeError as te:
            print("error found trying to document %s, \nerror %s" % (msg_instance, te))


if __name__ == '__main__':
    tt_messages = [
        MsgTestingToolReady,
        MsgSessionConfiguration,
        MsgTestingToolConfigured,
        MsgTestSuiteStart,
244 245 246 247 248
        MsgStepStimuliExecute,
        MsgStepStimuliExecuted,
        MsgStepVerifyExecute,
        MsgStepVerifyExecuted,
        MsgTestCaseVerdict,
249 250
        MsgTestSuiteReport,
        MsgTestingToolTerminate,
Federico Sismondi's avatar
Federico Sismondi committed
251 252 253 254 255 256 257 258 259 260
        MsgSniffingStart,
        MsgSniffingStop,
        MsgSniffingGetCapture,
        MsgSniffingGetCaptureLast,
        MsgDissectionDissectCapture,
        MsgDissectionDissectCaptureReply,
        MsgInteropTestCaseAnalyze,
        MsgInteropTestCaseAnalyzeReply,


261 262 263 264 265 266
    ]

    so_messages = [
    ]

    ui_messages = [
267 268 269 270 271 272 273 274 275
        MsgUiDisplayMarkdownText,
        MsgUiRequestTextInput,
        MsgUiRequestConfirmationButton,
        MsgUiRequestSessionConfiguration,
        MsgUiSessionConfigurationReply,
        MsgUiRequestUploadFile,
        MsgUiRequestQuestionCheckbox,
        MsgUiRequestQuestionRadio

276 277 278 279 280
    ]

    results_repo_messages = [
    ]

281 282 283 284 285 286 287
    viz_tools = [
        MsgVizInitRequest,
        MsgVizInitReply,
        MsgVizDashboardRequest,
        MsgVizDashboardReply,
        MsgVizWrite,
    ]
288 289 290 291 292 293 294 295 296 297 298
    resurces_repo_messages = [
    ]

    with open('_messages.md', "w+") as f:
        # Message Type
        f.write('# %s' % (header))
        generate_doc_section_into_file(f, 'Orchestrator events', so_messages)
        generate_doc_section_into_file(f, 'User interface events', ui_messages)
        generate_doc_section_into_file(f, 'Testing Tool events', tt_messages)
        generate_doc_section_into_file(f, 'Results Repository events', results_repo_messages)
        generate_doc_section_into_file(f, 'Resources Repository events', resurces_repo_messages)
299
        generate_doc_section_into_file(f, 'Visualization tools events', viz_tools)
300 301

    print_doc_tables(services, events)