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