github.com/pachyderm/pachyderm@v1.13.4/src/client/pkg/require/require.go (about) 1 package require 2 3 import ( 4 "fmt" 5 "reflect" 6 "regexp" 7 "runtime/debug" 8 "testing" 9 "time" 10 11 "github.com/pachyderm/pachyderm/src/client/pkg/errors" 12 ) 13 14 // Matches checks that a string matches a regular-expression. 15 func Matches(tb testing.TB, expectedMatch string, actual string, msgAndArgs ...interface{}) { 16 tb.Helper() 17 r, err := regexp.Compile(expectedMatch) 18 if err != nil { 19 fatal(tb, msgAndArgs, "Match string provided (%v) is invalid", expectedMatch) 20 } 21 if !r.MatchString(actual) { 22 fatal(tb, msgAndArgs, "Actual string (%v) does not match pattern (%v)", actual, expectedMatch) 23 } 24 } 25 26 // OneOfMatches checks whether one element of a slice matches a regular-expression. 27 func OneOfMatches(tb testing.TB, expectedMatch string, actuals []string, msgAndArgs ...interface{}) { 28 tb.Helper() 29 r, err := regexp.Compile(expectedMatch) 30 if err != nil { 31 fatal(tb, msgAndArgs, "Match string provided (%v) is invalid", expectedMatch) 32 } 33 for _, actual := range actuals { 34 if r.MatchString(actual) { 35 return 36 } 37 } 38 fatal(tb, msgAndArgs, "None of actual strings (%v) match pattern (%v)", actuals, expectedMatch) 39 40 } 41 42 // Equal checks the equality of two values 43 func Equal(tb testing.TB, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { 44 tb.Helper() 45 if err := EqualOrErr(expected, actual); err != nil { 46 fatal(tb, msgAndArgs, err.Error()) 47 } 48 } 49 50 // EqualOrErr checks equality of two values and returns an error if they're not equal 51 func EqualOrErr(expected interface{}, actual interface{}) error { 52 eV, aV := reflect.ValueOf(expected), reflect.ValueOf(actual) 53 if eV.Type() != aV.Type() { 54 return errors.Errorf("Not equal: %T(%#v) (expected)\n"+ 55 " != %T(%#v) (actual)", expected, expected, actual, actual) 56 } 57 if !reflect.DeepEqual(expected, actual) { 58 return errors.Errorf( 59 "Not equal: %#v (expected)\n"+ 60 " != %#v (actual)", expected, actual) 61 } 62 return nil 63 } 64 65 // NotEqual checks inequality of two values. 66 func NotEqual(tb testing.TB, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { 67 tb.Helper() 68 if reflect.DeepEqual(expected, actual) { 69 fatal( 70 tb, 71 msgAndArgs, 72 "Equal: %#v (expected)\n"+ 73 " == %#v (actual)", expected, actual) 74 } 75 } 76 77 // ElementsEqualOrErr returns nil if the elements of the slice "expecteds" are 78 // exactly the elements of the slice "actuals", ignoring order (i.e. 79 // setwise-equal), and an error otherwise. 80 // 81 // Unlike other require.* functions, this returns an error, so that if the 82 // caller is polling e.g. ListCommit or ListAdmins, they can wrap 83 // ElementsEqualOrErr in a retry loop. 84 // 85 // Also, like ElementsEqual, treat 'nil' and the empty slice as equivalent (for 86 // convenience) 87 func ElementsEqualOrErr(expecteds interface{}, actuals interface{}) error { 88 es := reflect.ValueOf(expecteds) 89 as := reflect.ValueOf(actuals) 90 91 // If either slice is empty, check that both are empty 92 esIsEmpty := expecteds == nil || es.IsNil() || (es.Kind() == reflect.Slice && es.Len() == 0) 93 asIsEmpty := actuals == nil || as.IsNil() || (as.Kind() == reflect.Slice && as.Len() == 0) 94 if esIsEmpty && asIsEmpty { 95 return nil 96 } else if esIsEmpty { 97 return errors.Errorf("expected 0 elements, but got %d: %v", as.Len(), actuals) 98 } else if asIsEmpty { 99 return errors.Errorf("expected %d elements, but got 0\n expected: %v", es.Len(), expecteds) 100 } 101 102 // Both slices are nonempty--compare elements 103 if es.Kind() != reflect.Slice { 104 return errors.Errorf("\"expecteds\" must be a slice, but was %s", es.Type().String()) 105 } 106 if as.Kind() != reflect.Slice { 107 return errors.Errorf("\"actuals\" must be a slice, but was %s", as.Type().String()) 108 } 109 110 // Make sure expecteds and actuals are slices of the same type, modulo 111 // pointers (*T ~= T in this function) 112 esArePtrs := es.Type().Elem().Kind() == reflect.Ptr 113 asArePtrs := as.Type().Elem().Kind() == reflect.Ptr 114 esElemType, asElemType := es.Type().Elem(), as.Type().Elem() 115 if esArePtrs { 116 esElemType = es.Type().Elem().Elem() 117 } 118 if asArePtrs { 119 asElemType = as.Type().Elem().Elem() 120 } 121 if esElemType != asElemType { 122 return errors.Errorf("expected []%s but got []%s", es.Type().Elem(), as.Type().Elem()) 123 } 124 125 if es.Len() != as.Len() { 126 // slight abuse of error: contains newlines so final output prints well 127 return errors.Errorf("expected %d elements, but got %d\n expected: %v\n actual: %v", 128 es.Len(), as.Len(), expecteds, actuals) 129 } 130 131 // Count up elements of expecteds 132 intType := reflect.TypeOf(int64(0)) 133 expectedCt := reflect.MakeMap(reflect.MapOf(esElemType, intType)) 134 for i := 0; i < es.Len(); i++ { 135 v := es.Index(i) 136 if esArePtrs { 137 v = v.Elem() 138 } 139 if !expectedCt.MapIndex(v).IsValid() { 140 expectedCt.SetMapIndex(v, reflect.ValueOf(int64(1))) 141 } else { 142 newCt := expectedCt.MapIndex(v).Int() + 1 143 expectedCt.SetMapIndex(v, reflect.ValueOf(newCt)) 144 } 145 } 146 147 // Count up elements of actuals 148 actualCt := reflect.MakeMap(reflect.MapOf(asElemType, intType)) 149 for i := 0; i < as.Len(); i++ { 150 v := as.Index(i) 151 if asArePtrs { 152 v = v.Elem() 153 } 154 if !actualCt.MapIndex(v).IsValid() { 155 actualCt.SetMapIndex(v, reflect.ValueOf(int64(1))) 156 } else { 157 newCt := actualCt.MapIndex(v).Int() + 1 158 actualCt.SetMapIndex(v, reflect.ValueOf(newCt)) 159 } 160 } 161 for _, key := range expectedCt.MapKeys() { 162 ec := expectedCt.MapIndex(key) 163 ac := actualCt.MapIndex(key) 164 if !ec.IsValid() || !ac.IsValid() || ec.Int() != ac.Int() { 165 ecInt, acInt := int64(0), int64(0) 166 if ec.IsValid() { 167 ecInt = ec.Int() 168 } 169 if ac.IsValid() { 170 acInt = ac.Int() 171 } 172 // slight abuse of error: contains newlines so final output prints well 173 return errors.Errorf("expected %d copies of %v, but got %d copies\n expected: %v\n actual: %v", ecInt, key, acInt, expecteds, actuals) 174 } 175 } 176 return nil 177 } 178 179 // ImagesEqual is similar to 'ElementsEqualUnderFn', but it applies 'f' to both 180 // 'expecteds' and 'actuals'. This is useful for doing before/after 181 // comparisons. This can also compare 'T' and '*T' , but 'f' should expect 182 // interfaces wrapping the underlying types of 'expecteds' (e.g. if 'expecteds' 183 // has type []*T and 'actuals' has type []T, then 'f' should cast its argument 184 // to '*T') 185 // 186 // Like ElementsEqual, treat 'nil' and the empty slice as equivalent (for 187 // convenience) 188 func ImagesEqual(tb testing.TB, expecteds interface{}, actuals interface{}, f func(interface{}) interface{}, msgAndArgs ...interface{}) { 189 tb.Helper() 190 as := reflect.ValueOf(actuals) 191 es := reflect.ValueOf(expecteds) 192 193 // Check if 'actuals' is empty; if so, just pass nil (no need to transform) 194 if actuals != nil && !as.IsNil() && as.Kind() != reflect.Slice { 195 fatal(tb, msgAndArgs, fmt.Sprintf("\"actuals\" must be a slice, but was %s", as.Type().String())) 196 } else if actuals == nil || as.IsNil() || as.Len() == 0 { 197 // Just pass 'nil' for 'actuals' 198 if err := ElementsEqualOrErr(expecteds, nil); err != nil { 199 fatal(tb, msgAndArgs, err.Error()) 200 } 201 return 202 } 203 204 // Check if 'expecteds' is empty: if so, return an error (since 'actuals' is 205 // not empty) 206 if expecteds != nil && !es.IsNil() && es.Kind() != reflect.Slice { 207 fatal(tb, msgAndArgs, fmt.Sprintf("\"expecteds\" must be a slice, but was %s", as.Type().String())) 208 } else if expecteds == nil || es.IsNil() || es.Len() == 0 { 209 fatal(tb, msgAndArgs, fmt.Sprintf("expected 0 distinct elements, but got %d\n elements (before function is applied): %v", as.Len(), actuals)) 210 } 211 212 // Make sure expecteds and actuals are slices of the same type, modulo 213 // pointers (*T ~= T in this function). This is better than some kind of 214 // opaque reflection error from calling 'f' on mismatched types. 215 esArePtrs := es.Type().Elem().Kind() == reflect.Ptr 216 asArePtrs := as.Type().Elem().Kind() == reflect.Ptr 217 esUnderlyingType, asUnderlyingType := es.Type().Elem(), as.Type().Elem() 218 if esArePtrs { 219 esUnderlyingType = es.Type().Elem().Elem() 220 } 221 if asArePtrs { 222 asUnderlyingType = as.Type().Elem().Elem() 223 } 224 if esUnderlyingType != asUnderlyingType { 225 fatal(tb, msgAndArgs, "expected []%s but got []%s", esUnderlyingType, asUnderlyingType) 226 } 227 228 if es.Len() != as.Len() { 229 // slight abuse of error: contains newlines so final output prints well 230 fatal(tb, msgAndArgs, "expected %d elements, but got %d\n expected: %v\n actual: %v", 231 es.Len(), as.Len(), expecteds, actuals) 232 } 233 234 // apply 'f' to both 'es' and 'as'. Make 'es[i]' have the same underlying 235 // type as 'as[i]' (may need to take address or dereference elements) so 'f' 236 // can apply to both. 237 newExpecteds, newActuals := make([]interface{}, 0, as.Len()), make([]interface{}, 0, as.Len()) 238 for i := 0; i < es.Len(); i++ { 239 switch { 240 case asArePtrs && !esArePtrs: 241 newExpecteds = append(newExpecteds, f(es.Index(i).Addr().Interface())) 242 case !asArePtrs && esArePtrs: 243 newExpecteds = append(newExpecteds, f(es.Index(i).Elem().Interface())) 244 default: 245 newExpecteds = append(newExpecteds, f(es.Index(i).Interface())) 246 } 247 } 248 for i := 0; i < as.Len(); i++ { 249 newActuals = append(newActuals, f(as.Index(i).Interface())) 250 } 251 if err := ElementsEqualOrErr(newExpecteds, newActuals); err != nil { 252 fatal(tb, msgAndArgs, err.Error()) 253 } 254 } 255 256 // ElementsEqualUnderFn checks that the elements of the slice 'expecteds' are 257 // the same as the elements of the slice 'actuals' under 'f', ignoring order 258 // (i.e. 'expecteds' and 'map(f, actuals)' are setwise-equal, but respecting 259 // duplicates). This is useful for cases where ElementsEqual doesn't quite work, 260 // e.g. because the type in 'expecteds'/'actuals' contains a pointer, or 261 // 'actuals' contains superfluous data which you wish to discard. 262 // 263 // Like ElementsEqual, treat 'nil' and the empty slice as equivalent (for 264 // convenience) 265 func ElementsEqualUnderFn(tb testing.TB, expecteds interface{}, actuals interface{}, f func(interface{}) interface{}, msgAndArgs ...interface{}) { 266 tb.Helper() 267 as := reflect.ValueOf(actuals) 268 es := reflect.ValueOf(expecteds) 269 270 // Check if 'actuals' is empty; if so, just pass nil (no need to transform) 271 if actuals != nil && !as.IsNil() && as.Kind() != reflect.Slice { 272 fatal(tb, msgAndArgs, fmt.Sprintf("\"actuals\" must be a slice, but was %s", as.Type().String())) 273 } else if actuals == nil || as.IsNil() || as.Len() == 0 { 274 // Just pass 'nil' for 'actuals' 275 if err := ElementsEqualOrErr(expecteds, nil); err != nil { 276 fatal(tb, msgAndArgs, err.Error()) 277 } 278 return 279 } 280 281 // Check if 'expecteds' is empty: if so, return an error (since 'actuals' is 282 // not empty) 283 if expecteds != nil && !es.IsNil() && es.Kind() != reflect.Slice { 284 fatal(tb, msgAndArgs, fmt.Sprintf("\"expecteds\" must be a slice, but was %s", as.Type().String())) 285 } else if expecteds == nil || es.IsNil() || es.Len() == 0 { 286 fatal(tb, msgAndArgs, fmt.Sprintf("expected 0 distinct elements, but got %d\n elements (before function is applied): %v", as.Len(), actuals)) 287 } 288 289 // Neither 'expecteds' nor 'actuals' is empty--apply 'f' to 'actuals' 290 newActuals := reflect.MakeSlice(reflect.SliceOf(es.Type().Elem()), as.Len(), as.Len()) 291 for i := 0; i < as.Len(); i++ { 292 newActuals.Index(i).Set(reflect.ValueOf(f(as.Index(i).Interface()))) 293 } 294 if err := ElementsEqualOrErr(expecteds, newActuals.Interface()); err != nil { 295 fatal(tb, msgAndArgs, err.Error()) 296 } 297 } 298 299 // ElementsEqual checks that the elements of the slice "expecteds" are 300 // exactly the elements of the slice "actuals", ignoring order (i.e. 301 // setwise-equal, but respecting duplicates). 302 // 303 // Note that if the elements of 'expecteds' and 'actuals' are pointers, 304 // ElementsEqual will unwrap the pointers before comparing them, so that the 305 // output of e.g. ListCommit(), which returns []*pfs.Commit can easily be 306 // verfied. 307 // 308 // Also, treat 'nil' and the empty slice as equivalent, so that callers can 309 // pass 'nil' for 'expecteds'. 310 func ElementsEqual(tb testing.TB, expecteds interface{}, actuals interface{}, msgAndArgs ...interface{}) { 311 tb.Helper() 312 if err := ElementsEqualOrErr(expecteds, actuals); err != nil { 313 fatal(tb, msgAndArgs, err.Error()) 314 } 315 } 316 317 // oneOfEquals is a helper function for EqualOneOf, OneOfEquals and NoneEquals, that simply 318 // returns a bool indicating whether 'elem' is in 'slice'. 'sliceName' is used for errors 319 func oneOfEquals(sliceName string, slice interface{}, elem interface{}) (bool, error) { 320 e := reflect.ValueOf(elem) 321 sl := reflect.ValueOf(slice) 322 if slice == nil || sl.IsNil() { 323 sl = reflect.MakeSlice(reflect.SliceOf(e.Type()), 0, 0) 324 } 325 if sl.Kind() != reflect.Slice { 326 return false, errors.Errorf("\"%s\" must a be a slice, but instead was %s", sliceName, sl.Type().String()) 327 } 328 if e.Type() != sl.Type().Elem() { 329 return false, nil 330 } 331 arePtrs := e.Kind() == reflect.Ptr 332 for i := 0; i < sl.Len(); i++ { 333 if !arePtrs && reflect.DeepEqual(e.Interface(), sl.Index(i).Interface()) { 334 return true, nil 335 } else if arePtrs && reflect.DeepEqual(e.Elem().Interface(), sl.Index(i).Elem().Interface()) { 336 return true, nil 337 } 338 } 339 return false, nil 340 } 341 342 // EqualOneOf checks if a value is equal to one of the elements of a slice. Note 343 // that if expecteds and actual are a slice of pointers and a pointer 344 // respectively, then the pointers are unwrapped before comparison (so this 345 // functions works for e.g. *pfs.Commit and []*pfs.Commit) 346 func EqualOneOf(tb testing.TB, expecteds interface{}, actual interface{}, msgAndArgs ...interface{}) { 347 tb.Helper() 348 equal, err := oneOfEquals("expecteds", expecteds, actual) 349 if err != nil { 350 fatal(tb, msgAndArgs, err.Error()) 351 } 352 if !equal { 353 fatal( 354 tb, 355 msgAndArgs, 356 "None of : %#v (expecteds)\n"+ 357 " == %#v (actual)", expecteds, actual) 358 } 359 } 360 361 // OneOfEquals checks whether one element of a slice equals a value. Like 362 // EqualsOneOf, OneOfEquals unwraps pointers 363 func OneOfEquals(tb testing.TB, expected interface{}, actuals interface{}, msgAndArgs ...interface{}) { 364 tb.Helper() 365 equal, err := oneOfEquals("actuals", actuals, expected) 366 if err != nil { 367 fatal(tb, msgAndArgs, err.Error()) 368 } 369 if !equal { 370 fatal(tb, msgAndArgs, 371 "Not equal : %#v (expected)\n"+ 372 " one of != %#v (actuals)", expected, actuals) 373 } 374 } 375 376 // NoneEquals checks one element of a slice equals a value. Like 377 // EqualsOneOf, NoneEquals unwraps pointers. 378 func NoneEquals(tb testing.TB, expected interface{}, actuals interface{}, msgAndArgs ...interface{}) { 379 tb.Helper() 380 equal, err := oneOfEquals("actuals", actuals, expected) 381 if err != nil { 382 fatal(tb, msgAndArgs, err.Error()) 383 } 384 if equal { 385 fatal(tb, msgAndArgs, 386 "Equal : %#v (expected)\n == one of %#v (actuals)", expected, actuals) 387 } 388 } 389 390 // NoError checks for no error. 391 func NoError(tb testing.TB, err error, msgAndArgs ...interface{}) { 392 tb.Helper() 393 if err != nil { 394 fatal(tb, msgAndArgs, "No error is expected but got %v", err) 395 } 396 } 397 398 // NoErrorWithinT checks that 'f' finishes within time 't' and does not emit an 399 // error 400 func NoErrorWithinT(tb testing.TB, t time.Duration, f func() error, msgAndArgs ...interface{}) { 401 tb.Helper() 402 errCh := make(chan error) 403 go func() { 404 // This goro will leak if the timeout is exceeded, but it's okay because the 405 // test is failing anyway 406 errCh <- f() 407 }() 408 select { 409 case err := <-errCh: 410 if err != nil { 411 fatal(tb, msgAndArgs, "No error is expected but got %v", err) 412 } 413 case <-time.After(t): 414 fatal(tb, msgAndArgs, "operation did not finish within %s", t.String()) 415 } 416 } 417 418 // NoErrorWithinTRetry checks that 'f' finishes within time 't' and does not 419 // emit an error. Unlike NoErrorWithinT if f does error, it will retry it. 420 func NoErrorWithinTRetry(tb testing.TB, t time.Duration, f func() error, msgAndArgs ...interface{}) { 421 tb.Helper() 422 doneCh := make(chan struct{}) 423 timeout := false 424 var err error 425 go func() { 426 for !timeout { 427 if err = f(); err == nil { 428 close(doneCh) 429 break 430 } 431 } 432 }() 433 select { 434 case <-doneCh: 435 case <-time.After(t): 436 timeout = true 437 fatal(tb, msgAndArgs, "operation did not finish within %s - last error: %v", t.String(), err) 438 } 439 } 440 441 // YesError checks for an error. 442 func YesError(tb testing.TB, err error, msgAndArgs ...interface{}) { 443 tb.Helper() 444 if err == nil { 445 fatal(tb, msgAndArgs, "Error is expected but got %v", err) 446 } 447 } 448 449 // NotNil checks a value is non-nil. 450 func NotNil(tb testing.TB, object interface{}, msgAndArgs ...interface{}) { 451 tb.Helper() 452 success := true 453 454 if object == nil { 455 success = false 456 } else { 457 value := reflect.ValueOf(object) 458 kind := value.Kind() 459 if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() { 460 success = false 461 } 462 } 463 464 if !success { 465 fatal(tb, msgAndArgs, "Expected value not to be nil.") 466 } 467 } 468 469 // Nil checks a value is nil. 470 func Nil(tb testing.TB, object interface{}, msgAndArgs ...interface{}) { 471 tb.Helper() 472 if object == nil { 473 return 474 } 475 value := reflect.ValueOf(object) 476 kind := value.Kind() 477 if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() { 478 return 479 } 480 481 fatal(tb, msgAndArgs, "Expected value to be nil, but was %v", object) 482 } 483 484 // True checks a value is true. 485 func True(tb testing.TB, value bool, msgAndArgs ...interface{}) { 486 tb.Helper() 487 if !value { 488 fatal(tb, msgAndArgs, "Should be true.") 489 } 490 } 491 492 // False checks a value is false. 493 func False(tb testing.TB, value bool, msgAndArgs ...interface{}) { 494 tb.Helper() 495 if value { 496 fatal(tb, msgAndArgs, "Should be false.") 497 } 498 } 499 500 // YesPanic checks that the callback panics. 501 func YesPanic(tb testing.TB, cb func(), msgAndArgs ...interface{}) { 502 defer func() { 503 r := recover() 504 if r == nil { 505 fatal(tb, msgAndArgs, "Should have panicked.") 506 } 507 }() 508 509 cb() 510 } 511 512 func logMessage(tb testing.TB, msgAndArgs []interface{}) { 513 tb.Helper() 514 if len(msgAndArgs) == 1 { 515 tb.Logf(msgAndArgs[0].(string)) 516 } 517 if len(msgAndArgs) > 1 { 518 tb.Logf(msgAndArgs[0].(string), msgAndArgs[1:]...) 519 } 520 } 521 522 func fatal(tb testing.TB, userMsgAndArgs []interface{}, msgFmt string, msgArgs ...interface{}) { 523 tb.Helper() 524 logMessage(tb, userMsgAndArgs) 525 tb.Logf(msgFmt, msgArgs...) 526 if len(msgArgs) > 0 { 527 err, ok := msgArgs[0].(error) 528 if ok { 529 errors.ForEachStackFrame(err, func(frame errors.Frame) { 530 tb.Logf("%+v\n", frame) 531 }) 532 } 533 } 534 tb.Fatalf("current stack:\n%s", string(debug.Stack())) 535 }