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