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