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