1.\" 2.\" This file and its contents are supplied under the terms of the 3.\" Common Development and Distribution License ("CDDL"), version 1.0. 4.\" You may only use this file in accordance with the terms of version 5.\" 1.0 of the CDDL. 6.\" 7.\" A full copy of the text of the CDDL should have accompanied this 8.\" source. A copy of the CDDL is also available via the Internet at 9.\" http://www.illumos.org/license/CDDL. 10.\" 11.\" 12.\" Copyright 2023 Oxide Computer Company 13.\" 14.Dd February 15, 2023 15.Dt KTEST_RESULT_PASS 9F 16.Os 17.Sh NAME 18.Nm KT_PASS , 19.Nm KT_FAIL , 20.Nm KT_ERROR , 21.Nm KT_SKIP , 22.Nm KT_ASSERT , 23.Nm KT_ASSERT0 , 24.Nm KT_ASSERT3S , 25.Nm KT_ASSERT3U , 26.Nm KT_ASSERT3P , 27.Nm KT_ASSERTG , 28.Nm KT_ASSERT0G , 29.Nm KT_ASSERT3SG , 30.Nm KT_ASSERT3UG , 31.Nm KT_ASSERT3PG , 32.Nm ktest_result_pass , 33.Nm ktest_result_fail , 34.Nm ktest_result_error , 35.Nm ktest_result_skip , 36.Nm ktest_msg_prepend , 37.Nm ktest_msg_clear 38.Nd set test result, assert test conditions, add failure context 39.Sh SYNOPSIS 40.In sys/ktest.h 41.Ft void 42.Fo ktest_result_pass 43.Fa "ktest_ctx_hdl_t *ctx" 44.Fa "int line" 45.Fc 46.Ft void 47.Fo ktest_result_fail 48.Fa "ktest_ctx_hdl_t *ctx" 49.Fa "int line" 50.Fa "const char *msg" 51.Fa "..." 52.Fc 53.Ft void 54.Fo ktest_result_error 55.Fa "ktest_ctx_hdl_t *ctx" 56.Fa "int line" 57.Fa "const char *msg" 58.Fa "..." 59.Fc 60.Ft void 61.Fo ktest_result_skip 62.Fa "ktest_ctx_hdl_t *ctx" 63.Fa "int line" 64.Fa "const char *msg" 65.Fa "..." 66.Fc 67.Ft void 68.Fo ktest_msg_prepend 69.Fa "ktest_ctx_hdl_t *ctx" 70.Fa "const char *msg" 71.Fa "..." 72.Fc 73.Ft void 74.Fo ktest_msg_clear 75.Fa "ktest_ctx_hdl_t *ctx" 76.Fc 77.Ft void 78.Fo KT_PASS 79.Fa "ktest_ctx_hdl_t *ctx" 80.Fc 81.Ft void 82.Fo KT_FAIL 83.Fa "ktest_ctx_hdl_t *ctx" 84.Fa "const char *msg" 85.Fa "..." 86.Fc 87.Ft void 88.Fo KT_ERROR 89.Fa "ktest_ctx_hdl_t *ctx" 90.Fa "const char *msg" 91.Fa "..." 92.Fc 93.Ft void 94.Fo KT_SKIP 95.Fa "ktest_ctx_hdl_t *ctx" 96.Fa "const char *msg" 97.Fa "..." 98.Fc 99.Ft void 100.Fo KT_ASSERT 101.Fa "exp" 102.Fa "ktest_ctx_hdl_t *ctx" 103.Fc 104.Ft void 105.Fo KT_ASSERT0 106.Fa "exp" 107.Fa "ktest_ctx_hdl_t *ctx" 108.Fc 109.Ft void 110.Fo KT_ASSERT3S 111.Fa "int64_t left" 112.Fa "op" 113.Fa "int64_t right" 114.Fa "ktest_ctx_hdl_t *ctx" 115.Fc 116.Ft void 117.Fo KT_ASSERT3U 118.Fa "uint64_t left" 119.Fa "op" 120.Fa "uint64_t right" 121.Fa "ktest_ctx_hdl_t *ctx" 122.Fc 123.Ft void 124.Fo KT_ASSERT3P 125.Fa "uintptr_t left" 126.Fa "op" 127.Fa "uintptr_t right" 128.Fa "ktest_ctx_hdl_t *ctx" 129.Fc 130.Ft void 131.Fo KT_ASSERTG 132.Fa "exp" 133.Fa "ktest_ctx_hdl_t *ctx" 134.Fa "label" 135.Fc 136.Ft void 137.Fo KT_ASSERT0G 138.Fa "exp" 139.Fa "ktest_ctx_hdl_t *ctx" 140.Fa "label" 141.Fc 142.Ft void 143.Fo KT_ASSERT3SG 144.Fa "int64_t left" 145.Fa "op" 146.Fa "int64_t right" 147.Fa "ktest_ctx_hdl_t *ctx" 148.Fa "label" 149.Fc 150.Ft void 151.Fo KT_ASSERT3UG 152.Fa "uint64_t left" 153.Fa "op" 154.Fa "uint64_t right" 155.Fa "ktest_ctx_hdl_t *ctx" 156.Fa "label" 157.Fc 158.Ft void 159.Fo KT_ASSERT3PG 160.Fa "uintptr_t left" 161.Fa "op" 162.Fa "uintptr_t right" 163.Fa "ktest_ctx_hdl_t *ctx" 164.Fa "label" 165.Fc 166.Sh INTERFACE LEVEL 167.Sy Volatile - 168This interface is still evolving in illumos. 169API and ABI stability is not guaranteed. 170.Sh PARAMETERS 171.Bl -tag -width Fa 172.It Fa ctx 173A handle to the test context. 174This handle is passed as argument to the test function by the ktest facility. 175.It Fa exp 176A test condition expression. 177.It Fa left 178The left side value of the test condition. 179This may be an expression. 180.It Fa right 181The right side value of the test condition. 182This may be an expression. 183.It Fa op 184The operator used to compare the 185.Fa left 186and 187.Fa right 188side values. 189.It Fa label 190The source code label to jump to if the test condition is false. 191.It Fa line 192The source line number where the result is set. 193This should always be the 194.Sy __LINE__ 195macro. 196.It Fa msg 197A message giving additional context on why a test did not pass. 198.El 199.Sh DESCRIPTION 200These functions and macros are used to set the result of a test function. 201.Ss Result Macros 202These are convenience macros for setting the test result, providing an 203alternative to the verbose result functions. 204In general, you should only need to use the 205.Fn KT_PASS 206and 207.Fn KT_SKIP 208macros. 209For most test assertions it's more convenient to use the "KTest ASSERT 210Macros" described below. 211These macros do not cause a 212.Sy return . 213.Bl -tag -width 2m 214.It Fn KT_PASS 215Set a passing result. 216.It Fn KT_FAIL 217Set a failure result along with the failure message. 218.It Fn KT_ERROR 219Set an error result along with the error message. 220.It Fn KT_SKIP 221Set a skip result along with the skip message. 222.El 223.Ss KTest ASSERT Macros 224These macros evaluate their test condition expression and verify it's true. 225They take care of building a failure message based on the expression 226and calling the 227.Fn ktest_result_fail 228function with the appropriate line number. 229They provide a convenient way to express test conditions and 230automatically build failure messages on the caller's behalf. 231They are essentially the same as the traditional 232.Sy ASSERT3 233family of macros with three exceptions: 234.Bl -enum 235.It 236They all require the additional 237.Fa ctx 238argument in order to set the failure result when the assert trips. 239.It 240They do not panic but instead build a failure message, call 241.Fn ktest_result_fail , 242and cause an immediate return of the test function. 243.It 244The "goto" variations of these macros provide the ability to cleanup 245test state instead of returning immediately. 246.El 247.Pp 248There are two variations of these macros. 249.Bl -tag -width 6m 250.It Sy KT_ASSERT* 251Essentially the same as the traditional 252.Sy ASSERT3 253family of macros, with the exception that they all take the 254.Fa ctx 255as an additional argument. 256This assert returns from the test function. 257.It Sy KT_ASSERT*G 258Assert the condition or 259.Sy goto 260.Fa label . 261.El 262.Ss KTest Error ASSERT Macros 263These macros are the same as the 264.Fn KT_ASSERT* 265macros with the only exception being that they call the 266.Fn ktest_result_error 267function to indicate an error condition. 268These macros use the same names as the 269.Fn KT_ASSERT* 270macros but prefixed with the character 'E', like so: 271.Fn KT_EASSERT* . 272This is a convenience for checking conditions which are indicative of 273a test error rather than failure. 274For example, for most tests a failure to acquire memory is considered 275an error, not a test failure. 276In that case one could use the following assert to raise a test error. 277.Bd -literal 278 mblk_t *mp = allocb(len, 0); 279 KT_EASSERT(mp != NULL, ctx); 280.Ed 281.Ss Additional Message Context 282Sometimes the failure message generated by the 283.Fn KT_ASSERT* 284macros is not enough. 285You may find the need to prepend additional information to the message 286to disambiguate the reason for failure. 287For example, you might find yourself asserting an invariant against an 288array of values and in order to disambiguate the failure you need to 289know the index of the value which tripped the assert. 290The 291.Fn ktest_msg_prepend 292function provides this ability. 293.Bl -tag -width 4m 294.It Nm ktest_msg_prepend 295Append the given format string to the failure message. 296This overwrites the prepended string of any previous call making it 297more convenient to use in a 298.Sy for 299loop. 300.It Nm ktest_msg_clear 301Clear the prepend buffer. 302This is equivalent to 303.Sy ktest_msg_prepend("") . 304.El 305.Ss Multiple Results 306Given the nature of ktest's design it is trivial to accidentally write 307a test that can produce multiple results for a given execution of its 308code. 309For example, placing the 310.Nm KT_PASS 311call in a cleanup label would overwrite a failure result with a pass 312result. 313This is the unavoidable nature of ktest's implementation: unlike 314typical testing frameworks we are executing in kernel context and it 315would be annoying if test failure was reported by way of host panic. 316.Pp 317To avoid incorrect test results the ktest facility itself checks for 318this scenario. 319For each call to the result API, ktest first checks if a result has 320already been set. 321If no result is present, then it stores the result along with its line 322number. 323However, if a result already exists, it generates an error result 324describing the line number of the overriding result along with the 325line number of the original result. 326.Sh EXAMPLES 327.Ss Test Without Cleanup 328This example shows the basic skeleton of a contrived test for a fictional 329.Ft object_t 330type. 331As there is no allocation or resource acquisition, there is no need 332for cleanup. 333.Bd -literal 334void 335no_cleanup_test(ktest_ctx_hdl_t *ctx) 336{ 337 object_t obj; 338 339 obj.obj_value = 7777; 340 obj.obj_state = OBJ_STATE_FIRST; 341 342 if (!check_for_condition_x()) { 343 KT_SKIP(ctx, "condition X was not met"); 344 return; 345 } 346 347 KT_ASSERT3U(obj.obj_state, ==, OBJ_STATE_FIRST, ctx); 348 next_state(&obj); 349 KT_ASSERT3U(obj.obj_state, ==, OBJ_STATE_SECOND, ctx); 350 351 <... more obj manipulation and assertions ...> 352 353 KT_PASS(ctx); 354} 355.Ed 356.Ss Test With Cleanup 357It's more likely that your test will require some amount of allocation and 358thus will need to make use of the 359.Fn KT_ASSERTG* 360macros. 361In this scenario 362.Fn KT_PASS 363must come before the 364.Sy cleanup 365label. 366Calling it after the 367.Sy cleanup 368label produces a multiple-result bug when one of the assertions trips. 369The ktest facility automatically catches this type of bug as explained 370in the "Multiple Results" section. 371.Bd -literal 372void 373test_with_cleanup(ktest_ctx_hdl_t *ctx) 374{ 375 mblk_t *mp = allocb(74, 0); 376 377 /* 378 * Failure to allocate is an error, not a test failure. 379 */ 380 KT_EASSERT(mp != NULL, ctx); 381 382 /* 383 * If any of these assertions trips, a failure result is set 384 * and execution jumps to the 'cleanup' label. 385 */ 386 KT_ASSERT3UG(msgsize(mp), ==, 0, ctx, cleanup); 387 KT_ASSERT3PG(mp->b_rptr, ==, mp->b_wptr, ctx, cleanup); 388 KT_ASSERT3PG(mp->b_next, ==, NULL, ctx, cleanup); 389 KT_ASSERT3PG(mp->b_cont, ==, NULL, ctx, cleanup); 390 391 /* 392 * All assertions passed; mark the test a success and let 393 * execution fall into the 'cleanup' label. 394 */ 395 KT_PASS(ctx); 396 397cleanup: 398 freeb(mp); 399} 400.Ed 401.Ss Additional Failure Context 402This example shows how to prepend additional context to the failure 403message. 404The 405.Fn ktest_msg_clear 406call after the loop is important; otherwise any subsequent assert failure 407would pick up the prepended message from the last iteration of the loop. 408.Bd -literal 409for (uint_t i = 0; i < num_objs; i++) { 410 obj_t *obj = &objs[i]; 411 412 ktest_msg_prepend(ctx, "objs[%d]: ", i); 413 KT_ASSERT3U(obj->o_state, ==, EXPECTED_STATE, ctx); 414} 415 416ktest_msg_clear(ctx); 417.Ed 418