diff --git a/helper/resource/error.go b/helper/resource/error.go index 7762a2d251..07fcce58e3 100644 --- a/helper/resource/error.go +++ b/helper/resource/error.go @@ -40,15 +40,26 @@ func (e *UnexpectedStateError) Error() string { // TimeoutError is returned when WaitForState times out type TimeoutError struct { LastError error + LastState string ExpectedState []string } func (e *TimeoutError) Error() string { + expectedState := "resource to be gone" + if len(e.ExpectedState) > 0 { + expectedState = fmt.Sprintf("state to become '%s'", strings.Join(e.ExpectedState, ", ")) + } + + lastState := "" + if e.LastState != "" { + lastState = fmt.Sprintf(" (last state: '%s')", e.LastState) + } + if e.LastError != nil { - return fmt.Sprintf("timeout while waiting for state to become '%s': %s", - strings.Join(e.ExpectedState, ", "), e.LastError) + return fmt.Sprintf("timeout while waiting for %s%s: %s", + expectedState, lastState, e.LastError) } - return fmt.Sprintf("timeout while waiting for state to become '%s'", - strings.Join(e.ExpectedState, ", ")) + return fmt.Sprintf("timeout while waiting for %s%s", + expectedState, lastState) } diff --git a/helper/resource/state.go b/helper/resource/state.go index f6a2f1e5ca..e9bd26a920 100644 --- a/helper/resource/state.go +++ b/helper/resource/state.go @@ -63,6 +63,7 @@ func (conf *StateChangeConf) WaitForState() (interface{}, error) { var result interface{} var resulterr error + var currentState string doneCh := make(chan struct{}) go func() { @@ -98,7 +99,6 @@ func (conf *StateChangeConf) WaitForState() (interface{}, error) { } } - var currentState string result, currentState, err = conf.Refresh() if err != nil { resulterr = err @@ -168,6 +168,7 @@ func (conf *StateChangeConf) WaitForState() (interface{}, error) { case <-time.After(conf.Timeout): return nil, &TimeoutError{ LastError: resulterr, + LastState: currentState, ExpectedState: conf.Target, } } diff --git a/helper/resource/state_test.go b/helper/resource/state_test.go index 27f6edf625..9da049e9f1 100644 --- a/helper/resource/state_test.go +++ b/helper/resource/state_test.go @@ -75,7 +75,8 @@ func TestWaitForState_inconsistent_positive(t *testing.T) { Pending: []string{"replicating"}, Target: []string{"done"}, Refresh: InconsistentStateRefreshFunc(), - Timeout: 10 * time.Second, + Timeout: 90 * time.Millisecond, + PollInterval: 10 * time.Millisecond, ContinuousTargetOccurence: 3, } @@ -95,14 +96,19 @@ func TestWaitForState_inconsistent_negative(t *testing.T) { Pending: []string{"replicating"}, Target: []string{"done"}, Refresh: InconsistentStateRefreshFunc(), - Timeout: 10 * time.Second, + Timeout: 90 * time.Millisecond, + PollInterval: 10 * time.Millisecond, ContinuousTargetOccurence: 4, } _, err := conf.WaitForState() - if err == nil && err.Error() != "timeout while waiting for state to become 'done'" { - t.Fatalf("err: %s", err) + if err == nil { + t.Fatal("Expected timeout error. No error returned.") + } + expectedErr := "timeout while waiting for state to become 'done' (last state: 'done')" + if err.Error() != expectedErr { + t.Fatalf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err.Error()) } } @@ -116,8 +122,13 @@ func TestWaitForState_timeout(t *testing.T) { obj, err := conf.WaitForState() - if err == nil && err.Error() != "timeout while waiting for state to become 'running'" { - t.Fatalf("err: %s", err) + if err == nil { + t.Fatal("Expected timeout error. No error returned.") + } + + expectedErr := "timeout while waiting for state to become 'running'" + if err.Error() != expectedErr { + t.Fatalf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err.Error()) } if obj != nil { @@ -162,6 +173,28 @@ func TestWaitForState_successEmpty(t *testing.T) { } } +func TestWaitForState_failureEmpty(t *testing.T) { + conf := &StateChangeConf{ + Pending: []string{"pending", "incomplete"}, + Target: []string{}, + NotFoundChecks: 1, + Refresh: func() (interface{}, string, error) { + return 42, "pending", nil + }, + PollInterval: 10 * time.Millisecond, + Timeout: 100 * time.Millisecond, + } + + _, err := conf.WaitForState() + if err == nil { + t.Fatal("Expected timeout error. Got none.") + } + expectedErr := "timeout while waiting for resource to be gone (last state: 'pending')" + if err.Error() != expectedErr { + t.Fatalf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err.Error()) + } +} + func TestWaitForState_failure(t *testing.T) { conf := &StateChangeConf{ Pending: []string{"pending", "incomplete"}, @@ -171,8 +204,12 @@ func TestWaitForState_failure(t *testing.T) { } obj, err := conf.WaitForState() - if err == nil && err.Error() != "failed" { - t.Fatalf("err: %s", err) + if err == nil { + t.Fatal("Expected error. No error returned.") + } + expectedErr := "failed" + if err.Error() != expectedErr { + t.Fatalf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err.Error()) } if obj != nil { t.Fatalf("should not return obj")