1Contributing to OpenBMC Test Automation
2=======================================
3Guide to working on OpenBMC test automation. This document will always be a
4work-in-progress, feel free to propose changes.
5
6Submitting changes via Gerrit server
7------------------------------------
8-   Reference [OpenBMC CLA signers](https://github.com/openbmc/openbmc-tools/blob/master/emilyshaffer/cla-signers/cla-signers)
9-   Reference [OpenBMC docs](https://github.com/openbmc/docs/blob/master/contributing.md#submitting-changes-via-gerrit-server)
10
11Robot Coding Guidelines
12-----------------------
13-   For this project, we will write Robot keyword definitions in either Robot
14    or Python.  Robot code should be quite simple.  Therefore, if the algorithm
15    in question is the least bit complex, please write it in Python.
16-   Observe a maximum line length of 79 characters.
17-   Avoid trailing space at the end of any line of Robot code.
18-   Avoid the use of tabs.
19-   Robot supports delimiting cells with either two or more spaces or with a
20    pipe symbol (e.g. "\|"). Our team has chosen to use spaces rather than the
21    pipe character. Make sure all space delimiters in Robot code are the
22    **minimum** of two spaces. There may be some exceptions to this rule.
23
24    Exceptions to two-space delimiter rule:
25    - When you wish to line up resource, library or variable values:
26      ```
27      Library         Lib1
28      Resource        Resource1
29      *** Variables ***
30      ${var1}         ${EMPTY}
31      ```
32    - When you wish to line up fields for test templates:
33      ```
34      [Template]  Set System LED State
35      # LED Name  LED State
36      power       On
37      power       Off
38      ```
39    - When you wish to indent if/else or loop bodies for visual effect:
40      ```
41      Run Keyword If  '${this}' == '${that}'
42      ...    Log  Bla, bla...
43      ...  ELSE
44      ...    Run Keywords  Key1  parms
45      ...    AND  Key2  parms
46      ```
47-   Use spaces to make conditions more readable:
48
49    Correct example:
50    ```
51    Run Keyword If  '${var1}' == '${0}'  My Keyword
52    ```
53    Incorrect example:
54    ```
55    Run Keyword If  '${var1}'=='${0}'  My Keyword
56    ```
57-   When you define or call a Robot keyword, Robot pays no attention to spaces,
58    underscores or case.  However, our team will observe the following
59    conventions in both our definitions and our calls:
60    - Separate words with single spaces.
61    - Capitalize the first character of each word.
62    - Capitalize all characters in any word that is an acronym (e.g. JSON, BMC,
63      etc).
64
65    Examples:
66    ```
67    *** Keywords ***
68
69    This Is Correct
70
71        # This keyword name is correct.
72
73    this_is_incorrect
74
75        # This keyword name is incorrect because of 1) the
76        # underscores instead of spaces and 2) the failure to
77        # capitalize each word in the keyword.
78
79    soisthis
80
81        # This keyword name is incorrect because of 1) a failure to
82        # separate words with spaces and 2) a failure to capitalize
83        # each word in the keyword.
84
85    BMC Is An Acronym
86
87        # This keyword name is correct.  Note that "BMC" is an
88        # acronym and as such is entirely uppercase.
89    ```
90-   Documentation strings:
91    -  Each documentation string should be phrased as an **English command**.
92       Punctuate it correctly with the first word capitalized and a period at
93       the end.
94
95       Correct example:
96        ```
97        Boot BMC
98            [Documentation]  Boot the BMC.
99        ```
100        Incorrect example:
101        ```
102        Boot BMC
103            [Documentation]  This keyword boots the BMC.
104
105            # The doc string above is not phrased as a command.
106        ```
107    -   Doc strings should be just one terse, descriptive sentence.
108        Remember that this doc string shows up in the HTML log file.  Put
109        additional commentary below in standard comment lines.
110
111        Correct example:
112        ```
113        Stop SOL Console Logging
114
115            [Documentation]  Stop system console logging and return log output.
116        ```
117        Incorrect example:
118        ```
119        Stop SOL Console Logging
120
121            [Documentation]  Stop system console logging.  If there are multiple
122            ...              system console processes, they will all be
123            ...              stopped.  If there is no existing log file this
124            ...              keyword will return an error message to that
125            ...              effect (and write that message to targ_file_path,
126            ...              if specified).  NOTE: This keyword will not fail
127            ...              if there is no running system console process.
128
129            # This doc string is way too long.
130        ```
131-   Tags:
132    -   Create a tag for every test case with a tag name that mirrors the test case
133        name as follows:
134        ```
135        Create Intermediate File
136
137            [Tags]  Create_Intermediate_File
138        ```
139-   Description of argument(s):
140    -   As shown in the following example, if your keyword has any arguments, include
141        a "**Description of argument(s)**" section.  This effectively serves as the
142        help text for anyone wanting to use or understand your keyword.  Include
143        real data examples wherever possible and applicable.  Leave at least 2 spaces
144        between the argument name and the description.  Align all description text as
145        shown in the example below.
146
147        Example:
148        ```
149        Get URL List
150            [Documentation]  Return list of URLs under given URL.
151            [Arguments]  ${openbmc_url}  ${policy}
152
153            # Description of argument(s):
154            # openbmc_url  URL for list operation (e.g.
155            #              "/xyz/openbmc_project/inventory").
156            # policy       Power restore policy (e.g "RESTORE_LAST_STATE",
157            #              ${RESTORE_LAST_STATE}).
158        ```
159-   Variable assignments:
160
161    When assigning a variable as output from a keyword, do not precede the
162    equal sign with a space.
163
164    Correct examples:
165    ```
166    ${var1}=  Set Variable  ${1}
167    ${var1}=  My Keyword
168    ```
169    Incorrect examples:
170
171    ```
172    ${var1} =  Set Variable  ${1}
173    ${var1} =  My Keyword
174    ```
175-   General variable naming conventions:
176    -   Variable names should be lower case with few exceptions:
177        -   Environment variables should be all upper case.
178        -   Variables intended to be set by Robot -v parameters may be all
179            upper case.
180    -   Words within a variable name should be separated by underscores:
181
182        Correct examples:
183        ```
184        ${host_name}
185        ${program_pid}
186        ```
187        Incorrect examples:
188        ```
189        ${HostName}
190        ${ProgramPid}
191        ```
192-   Special variable naming conventions.
193
194    For certain very commonly used kinds of variables, please observe these
195    conventions in order to achieve consistency throughout the code.
196
197    -   hosts
198
199        When a variable is intended to contain **either** an IP address **or**
200        a host name (either long or short), please give it a suffix of "_host".
201
202        Examples:
203        ```
204        openbmc_host
205        os_host
206        pdu_host
207        openbmc_serial_host
208        ```
209    -   host names
210
211        For host names (long or short, e.g. "bmc1" or "bmc1.example.com"), use
212        a suffix of _host_name.
213
214        Examples:
215        ```
216        openbmc_host_name
217        os_host_name
218        pdu_host_name
219        openbmc_serial_host_name
220        ```
221    -   Short host names
222
223        For short host names (e.g. "bmc1"), use a suffix of _host_short_name.
224
225        Examples:
226        ```
227        openbmc_host_short_name
228        os_host_short_name
229        pdu_host_short_name
230        openbmc_serial_host_short_name
231        ```
232    -   IP addresses
233
234        For IP addresses, use a suffix of _ip.
235
236        Example:
237        ```
238        openbmc_ip
239        os_ip
240        pdu_ip
241        openbmc_serial_ip
242        ```
243    -   Files and directories:
244        -   Files:
245            -   If your variable is to contain only the file's name, use a suffix
246                of _file_name.
247
248                Examples:
249                ```
250                ffdc_file_name = "bmc1.170428.120200.ffdc"
251                ```
252            -   If your variable is to contain the path to a file, use a suffix of
253                _file_path.  Bear in mind that a file path can be relative or
254                absolute so that should not be a consideration in whether to use
255                the "_file_path" suffix.
256
257                Examples:
258                ```
259                status_file_path = "bmc1.170428.120200.status"
260                status_file_path = "subdir/bmc1.170428.120200.status"
261                status_file_path = "./bmc1.170428.120200.status"
262                status_file_path = "../bmc1.170428.120200.status"
263                status_file_path = "/home/user1/status/bmc1.170428.120200.status"
264                ```
265                To re-iterate, it doesn't matter whether the contents of the
266                variable are a relative or absolute path (as shown in the
267                examples above).  A file path is simply a value with enough
268                information in it for the program to find the file.
269
270            -   If the variable **must** contain an absolute path (which should be
271                the rare case), use a suffix _abs_file_path.
272
273        -   Directories:
274            -   Directory variables should follow the same conventions as file
275                variables.
276
277            -   If your variable is to contain only the directory's name, use a
278                suffix of _dir_name.
279
280                Example:
281                ```
282                ffdc_dir_name = "ffdc"
283                ```
284            -   If your variable is to contain the path to a directory, use a
285                suffix of _dir_path.  Bear in mind that a dir path can be
286                relative or absolute so that should not be a consideration in
287                whether to use _dir_path.
288
289                Examples:
290                ```
291                status_dir_path = "status/"
292                status_dir_path = "subdir/status"
293                status_dir_path = "./status/"
294                status_dir_path = "../status/"
295                status_dir_path = "/home/user1/status/"
296                ```
297                To re-iterate, it doesn't matter whether the contents of
298                the variable are a relative or absolute path (as shown in
299                the examples above).  A dir path is simply a value with
300                enough information in it for the program to find the
301                directory.
302
303            -   If the variable **must** contain an absolute path (which
304                should be the rare case), use a suffix _abs_dir_path.
305            -   IMPORTANT:  As a programming convention, do pre-
306                processing on all dir_path variables to ensure that they
307                contain a trailing slash.  If we follow that convention
308                religiously, that when changes are made in other parts of
309                the program, the programmer can count on the value having
310                a trailing slash.  Therefore they can safely do this kind
311                of thing:
312                ```
313                my_file_path = my_dir_path + my_file_name
314                ```
315    -   Setup/Teardown keywords
316
317        Use standardized names for setup and teardown keywords:
318        - Suite Setup Execution
319        - Suite Teardown Execution
320        - Test Setup Execution
321        - Test Teardown Execution
322-   Traditional comments (i.e. using the hashtag style comments)
323    -   Please leave one space following the hashtag.
324        ```
325        #wrong
326
327        # Right
328        ```
329    -   Please use proper English punction:
330        -   Capitalize the first word in the sentence or phrase.
331        -   End sentences (or stand-alone phrases) with a period.
332
333    -   Do not keep commented out code in your program.  Instead, remove it
334        entirely.
335
336Python Coding Guidelines
337-----------------------
338-   The minimum required Python version is 2.7.x.
339-   Run pep8 on all Python files and correct errors.
340
341    Example as run from a Linux command line:
342    ```
343    pep8 my_pgm.py
344
345    my_pgm.py:41:1: E302 expected 2 blank lines, found 1
346    my_pgm.py:58:52: W291 trailing whitespace
347    ```
348-   Include doc strings in every function and follow the guidelines in
349    https://www.python.org/dev/peps/pep-0257/.
350
351    Example:
352    ```
353        r"""
354        Return the function name associated with the indicated stack frame.
355
356        Description of argument(s):
357        stack_frame_ix                  The index of the stack frame whose
358                                        function name should be returned.  If
359                                        the caller does not specify a value,
360                                        this function will set the value to 1
361                                        which is the index of the caller's
362                                        stack frame.  If the caller is the
363                                        wrapper function "print_func_name",
364                                        this function will bump it up by 1.
365        """
366    ```
367-   As shown in the prior example, if your function has any arguments, include
368    a "Description of argument(s)" section.  This effectively serves as the
369    help text for anyone wanting to use or understand your function.  Include
370    real data examples wherever possible and applicable.
371-   Function definitions:
372    -   Put each function parameter on its own line:
373        ```
374        def func1(parm1,
375
376                  parm2):
377        ```
378-   Do not keep commented out code in your program.  Instead, remove it
379    entirely.
380-   When you define or call a Robot keyword, Robot pays no attention to spaces,
381    underscores or case.  However, our team will observe the following
382    conventions in both our definitions and our calls:
383    - Separate words with single spaces.
384    - Capitalize the first character of each word.
385    - Capitalize all characters in any word that is an acronym (e.g. JSON, BMC,
386      etc).
387
388    Examples:
389    ```
390    *** Keywords ***
391
392    This Is Correct
393
394        # This keyword name is correct.
395
396    this_is_incorrect
397
398        # This keyword name is incorrect because of 1) the
399        # underscores instead of spaces and 2) the failure to
400        # capitalize each word in the keyword.
401
402    soisthis
403
404        # This keyword name is incorrect because of 1) a failure to
405        # separate words with spaces and 2) a failure to capitalize
406        # each word in the keyword.
407
408    BMC Is An Acronym
409
410        # This keyword name is correct.  Note that "BMC" is an
411        # acronym and as such is entirely uppercase.
412    ```
413-   Documentation strings:
414    -  Each documentation string should be phrased as an **English command**.
415       Punctuate it correctly with the first word capitalized and a period at
416       the end.
417
418       Correct example:
419        ```
420        Boot BMC
421            [Documentation]  Boot the BMC.
422        ```
423        Incorrect example:
424        ```
425        Boot BMC
426            [Documentation]  This keyword boots the BMC.
427
428            # The doc string above is not phrased as a command.
429        ```
430    -   Doc strings should be just one terse, descriptive sentence.
431        Remember that this doc string shows up in the HTML log file.  Put
432        additional commentary below in standard comment lines.
433
434        Correct example:
435        ```
436        Stop SOL Console Logging
437
438            [Documentation]  Stop system console logging and return log output.
439        ```
440        Incorrect example:
441        ```
442        Stop SOL Console Logging
443
444            [Documentation]  Stop system console logging.  If there are multiple
445            ...              system console processes, they will all be
446            ...              stopped.  If there is no existing log file this
447            ...              keyword will return an error message to that
448            ...              effect (and write that message to targ_file_path,
449            ...              if specified).  NOTE: This keyword will not fail
450            ...              if there is no running system console process.
451
452            # This doc string is way too long.
453        ```
454-   Tags:
455    -   Create a tag for every test case with a tag name that mirrors the test case
456        name as follows:
457        ```
458        Create Intermediate File
459
460            [Tags]  Create_Intermediate_File
461        ```
462-   General variable naming conventions:
463    -   Variable names should be lower case with few exceptions:
464        -   Environment variables should be all upper case.
465        -   Variables intended to be set by Robot -v parameters may be all
466            upper case.
467    -   Words within a variable name should be separated by underscores:
468
469        Correct examples:
470        ```
471        ${host_name}
472        ${program_pid}
473        ```
474        Incorrect examples:
475        ```
476        ${HostName}
477        ${ProgramPid}
478        ```
479-   Special variable naming conventions.
480
481    For certain very commonly used kinds of variables, please observe these
482    conventions in order to achieve consistency throughout the code.
483
484    -   hosts
485
486        When a variable is intended to contain **either** an IP address **or**
487        a host name (either long or short), please give it a suffix of "_host".
488
489        Examples:
490        ```
491        openbmc_host
492        os_host
493        pdu_host
494        openbmc_serial_host
495        ```
496    -   host names
497
498        For host names (long or short, e.g. "bmc1" or "bmc1.example.com"), use
499        a suffix of _host_name.
500
501        Examples:
502        ```
503        openbmc_host_name
504        os_host_name
505        pdu_host_name
506        openbmc_serial_host_name
507        ```
508    -   Short host names
509
510        For short host names (e.g. "bmc1"), use a suffix of _host_short_name.
511
512        Examples:
513        ```
514        openbmc_host_short_name
515        os_host_short_name
516        pdu_host_short_name
517        openbmc_serial_host_short_name
518        ```
519    -   IP addresses
520
521        For IP addresses, use a suffix of _ip.
522
523        Example:
524        ```
525        openbmc_ip
526        os_ip
527        pdu_ip
528        openbmc_serial_ip
529        ```
530-   Files and directories:
531    -   Files:
532        -   If your variable is to contain only the file's name, use a suffix
533            of _file_name.
534
535            Examples:
536            ```
537            ffdc_file_name = "bmc1.170428.120200.ffdc"
538            ```
539        -   If your variable is to contain the path to a file, use a suffix of
540            _file_path.  Bear in mind that a file path can be relative or
541            absolute so that should not be a consideration in whether to use
542            the "_file_path" suffix.
543
544            Examples:
545            ```
546            status_file_path = "bmc1.170428.120200.status"
547            status_file_path = "subdir/bmc1.170428.120200.status"
548            status_file_path = "./bmc1.170428.120200.status"
549            status_file_path = "../bmc1.170428.120200.status"
550            status_file_path = "/home/user1/status/bmc1.170428.120200.status"
551            ```
552            To re-iterate, it doesn't matter whether the contents of the
553            variable are a relative or absolute path (as shown in the
554            examples above).  A file path is simply a value with enough
555            information in it for the program to find the file.
556
557        -   If the variable **must** contain an absolute path (which should be
558            the rare case), use a suffix _abs_file_path.
559
560    -   Directories:
561        -   Directory variables should follow the same conventions as file
562            variables.
563
564        -   If your variable is to contain only the directory's name, use a
565            suffix of _dir_name.
566
567            Example:
568            ```
569            ffdc_dir_name = "ffdc"
570            ```
571        -   If your variable is to contain the path to a directory, use a
572            suffix of _dir_path.  Bear in mind that a dir path can be
573            relative or absolute so that should not be a consideration in
574            whether to use _dir_path.
575
576            Examples:
577            ```
578            status_dir_path = "status/"
579            status_dir_path = "subdir/status"
580            status_dir_path = "./status/"
581            status_dir_path = "../status/"
582            status_dir_path = "/home/user1/status/"
583            ```
584            To re-iterate, it doesn't matter whether the contents of
585            the variable are a relative or absolute path (as shown in
586            the examples above).  A dir path is simply a value with
587            enough information in it for the program to find the
588            directory.
589
590        -   If the variable **must** contain an absolute path (which
591            should be the rare case), use a suffix _abs_dir_path.
592        -   IMPORTANT:  As a programming convention, do pre-
593            processing on all dir_path variables to ensure that they
594            contain a trailing slash.  If we follow that convention
595            religiously, that when changes are made in other parts of
596            the program, the programmer can count on the value having
597            a trailing slash.  Therefore they can safely do this kind
598            of thing:
599            ```
600            my_file_path = my_dir_path + my_file_name
601            ```
602-   Traditional comments (i.e. using the hashtag style comments)
603    -   Please leave one space following the hashtag.
604        ```
605        #wrong
606
607        # Right
608        ```
609    -   Please use proper English punction:
610        -   Capitalize the first word in the sentence or phrase.
611        -   End sentences (or stand-alone phrases) with a period.
612
613    -   Do not keep commented out code in your program.  Instead, remove it
614        entirely.
615
616Python Coding Guidelines
617-----------------------
618-   Run pep8 on all Python files and correct errors.
619
620    Example as run from a Linux command line:
621    ```
622    pep8 my_pgm.py
623
624    my_pgm.py:41:1: E302 expected 2 blank lines, found 1
625    my_pgm.py:58:52: W291 trailing whitespace
626    ```
627-   Include doc strings in every function and follow the guidelines in
628    https://www.python.org/dev/peps/pep-0257/.
629
630    Example:
631    ```
632        r"""
633        Return the function name associated with the indicated stack frame.
634
635        Description of argument(s):
636        stack_frame_ix                  The index of the stack frame whose
637                                        function name should be returned.  If
638                                        the caller does not specify a value,
639                                        this function will set the value to 1
640                                        which is the index of the caller's
641                                        stack frame.  If the caller is the
642                                        wrapper function "print_func_name",
643                                        this function will bump it up by 1.
644        """
645    ```
646-   As shown in the prior example, if your function has any arguments, include
647    a "Description of argument(s)" section.  This effectively serves as the
648    help text for anyone wanting to use or understand your function.  Include
649    real data examples wherever possible and applicable.
650-   Function definitions:
651    -   Put each function parameter on its own line:
652        ```
653        def func1(parm1,
654
655                  parm2):
656        ```
657-   Do not keep commented out code in your program.  Instead, remove it
658    entirely.
659
660Template Usage Guidelines
661-------------------------
662We have several templates in the templates/ sub-directory. If there is a
663template that applies to your programming situation (Python, bash, etc.),
664it should be used to create new programs as in the following example
665
666- Example:
667
668    ```
669    $ cd templates
670    $ cp python_pgm_template ../bin/my_new_program
671    ```
672
673These templates have much of your preliminary work done for you and will help
674us all follow a similar structure.
675
676- Features:
677    - Help text and arg parsing started for you.
678    - Support for "stock" parameters like "quiet", "debug", "test_mode".
679    - "exit_function" and "signal_handler" defined.
680    - "validate_parms" function pre-created.
681    - "main" function follows conventional startup sequence:
682
683        ```
684            if not gen_get_options(parser, stock_list):
685                return False
686
687            if not validate_parms():
688                return False
689
690            qprint_pgm_header()
691
692            # Your code here.
693        ```
694