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)