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