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