diff --git a/builder/docker/communicator_test.go b/builder/docker/communicator_test.go index bdfaef996..14bcdf496 100644 --- a/builder/docker/communicator_test.go +++ b/builder/docker/communicator_test.go @@ -67,11 +67,10 @@ func TestUploadDownload(t *testing.T) { hooks := map[string][]packer.Hook{} hooks[packer.HookProvision] = []packer.Hook{ &packer.ProvisionHook{ - Provisioners: []packer.Provisioner{ - upload, - download, + Provisioners: []*packer.HookedProvisioner{ + {upload, nil, ""}, + {download, nil, ""}, }, - ProvisionerTypes: []string{"", ""}, }, } hook := &packer.DispatchHook{Mapping: hooks} @@ -157,12 +156,11 @@ func TestLargeDownload(t *testing.T) { hooks := map[string][]packer.Hook{} hooks[packer.HookProvision] = []packer.Hook{ &packer.ProvisionHook{ - Provisioners: []packer.Provisioner{ - shell, - downloadCupcake, - downloadBigcake, + Provisioners: []*packer.HookedProvisioner{ + {shell, nil, ""}, + {downloadCupcake, nil, ""}, + {downloadBigcake, nil, ""}, }, - ProvisionerTypes: []string{"", "", ""}, }, } hook := &packer.DispatchHook{Mapping: hooks} @@ -203,8 +201,8 @@ func TestLargeDownload(t *testing.T) { // or ui output to do this because we use /dev/urandom to create the file. // if sha256.Sum256(inputFile) != sha256.Sum256(outputFile) { - // t.Fatalf("Input and output files do not match\n"+ - // "Input:\n%s\nOutput:\n%s\n", inputFile, outputFile) + // t.Fatalf("Input and output files do not match\n"+ + // "Input:\n%s\nOutput:\n%s\n", inputFile, outputFile) // } } @@ -267,13 +265,12 @@ func TestFixUploadOwner(t *testing.T) { hooks := map[string][]packer.Hook{} hooks[packer.HookProvision] = []packer.Hook{ &packer.ProvisionHook{ - Provisioners: []packer.Provisioner{ - fileProvisioner, - dirProvisioner, - shellProvisioner, - verifyProvisioner, + Provisioners: []*packer.HookedProvisioner{ + {fileProvisioner, nil, ""}, + {dirProvisioner, nil, ""}, + {shellProvisioner, nil, ""}, + {verifyProvisioner, nil, ""}, }, - ProvisionerTypes: []string{"", "", "", ""}, }, } hook := &packer.DispatchHook{Mapping: hooks} diff --git a/packer/build.go b/packer/build.go index 996c9a331..1187e49d7 100644 --- a/packer/build.go +++ b/packer/build.go @@ -194,11 +194,17 @@ func (b *coreBuild) Run(originalUi Ui, cache Cache) ([]Artifact, error) { // Add a hook for the provisioners if we have provisioners if len(b.provisioners) > 0 { - provisioners := make([]Provisioner, len(b.provisioners)) - provisionerTypes := make([]string, len(b.provisioners)) + hookedProvisioners := make([]*HookedProvisioner, len(b.provisioners)) for i, p := range b.provisioners { - provisioners[i] = p.provisioner - provisionerTypes[i] = p.pType + var pConfig interface{} + if len(p.config) > 0 { + pConfig = p.config[0] + } + hookedProvisioners[i] = &HookedProvisioner{ + p.provisioner, + pConfig, + p.pType, + } } if _, ok := hooks[HookProvision]; !ok { @@ -206,8 +212,7 @@ func (b *coreBuild) Run(originalUi Ui, cache Cache) ([]Artifact, error) { } hooks[HookProvision] = append(hooks[HookProvision], &ProvisionHook{ - Provisioners: provisioners, - ProvisionerTypes: provisionerTypes, + Provisioners: hookedProvisioners, }) } @@ -221,7 +226,7 @@ func (b *coreBuild) Run(originalUi Ui, cache Cache) ([]Artifact, error) { } log.Printf("Running builder: %s", b.builderType) - ts := CheckpointReporter.AddSpan(b.builderType, "builder") + ts := CheckpointReporter.AddSpan(b.builderType, "builder", b.builderConfig) builderArtifact, err := b.builder.Run(builderUi, hook, cache) ts.End(err) if err != nil { @@ -248,7 +253,7 @@ PostProcessorRunSeqLoop: } builderUi.Say(fmt.Sprintf("Running post-processor: %s", corePP.processorType)) - ts := CheckpointReporter.AddSpan(corePP.processorType, "post-processor") + ts := CheckpointReporter.AddSpan(corePP.processorType, "post-processor", corePP.config) artifact, keep, err := corePP.processor.PostProcess(ppUi, priorArtifact) ts.End(err) if err != nil { diff --git a/packer/provisioner.go b/packer/provisioner.go index 639e8b1a8..a754f7544 100644 --- a/packer/provisioner.go +++ b/packer/provisioner.go @@ -26,12 +26,18 @@ type Provisioner interface { Cancel() } +// A HookedProvisioner represents a provisioner and information describing it +type HookedProvisioner struct { + Provisioner Provisioner + Config interface{} + TypeName string +} + // A Hook implementation that runs the given provisioners. type ProvisionHook struct { // The provisioners to run as part of the hook. These should already // be prepared (by calling Prepare) at some earlier stage. - Provisioners []Provisioner - ProvisionerTypes []string + Provisioners []*HookedProvisioner lock sync.Mutex runningProvisioner Provisioner @@ -58,13 +64,15 @@ func (h *ProvisionHook) Run(name string, ui Ui, comm Communicator, data interfac h.runningProvisioner = nil }() - for i, p := range h.Provisioners { + for _, p := range h.Provisioners { h.lock.Lock() - h.runningProvisioner = p + h.runningProvisioner = p.Provisioner h.lock.Unlock() - ts := CheckpointReporter.AddSpan(h.ProvisionerTypes[i], "provisioner") - err := p.Provision(ui, comm) + ts := CheckpointReporter.AddSpan(p.TypeName, "provisioner", p.Config) + + err := p.Provisioner.Provision(ui, comm) + ts.End(err) if err != nil { return err diff --git a/packer/provisioner_test.go b/packer/provisioner_test.go index f303bc7d2..97304d2a5 100644 --- a/packer/provisioner_test.go +++ b/packer/provisioner_test.go @@ -23,8 +23,10 @@ func TestProvisionHook(t *testing.T) { var data interface{} = nil hook := &ProvisionHook{ - Provisioners: []Provisioner{pA, pB}, - ProvisionerTypes: []string{"", ""}, + Provisioners: []*HookedProvisioner{ + {pA, nil, ""}, + {pB, nil, ""}, + }, } hook.Run("foo", ui, comm, data) @@ -47,8 +49,10 @@ func TestProvisionHook_nilComm(t *testing.T) { var data interface{} = nil hook := &ProvisionHook{ - Provisioners: []Provisioner{pA, pB}, - ProvisionerTypes: []string{"", ""}, + Provisioners: []*HookedProvisioner{ + {pA, nil, ""}, + {pB, nil, ""}, + }, } err := hook.Run("foo", ui, comm, data) @@ -74,8 +78,9 @@ func TestProvisionHook_cancel(t *testing.T) { } hook := &ProvisionHook{ - Provisioners: []Provisioner{p}, - ProvisionerTypes: []string{""}, + Provisioners: []*HookedProvisioner{ + {p, nil, ""}, + }, } finished := make(chan struct{}) diff --git a/packer/telemetry.go b/packer/telemetry.go index 7224de582..a58b1c701 100644 --- a/packer/telemetry.go +++ b/packer/telemetry.go @@ -5,13 +5,14 @@ import ( "log" "os" "path/filepath" + "sort" "time" checkpoint "github.com/hashicorp/go-checkpoint" packerVersion "github.com/hashicorp/packer/version" ) -const TelemetryVersion string = "beta/packer/4" +const TelemetryVersion string = "beta/packer/5" const TelemetryPanicVersion string = "beta/packer_panic/4" var CheckpointReporter *CheckpointTelemetry @@ -85,15 +86,17 @@ func (c *CheckpointTelemetry) ReportPanic(m string) error { return checkpoint.Report(ctx, panicParams) } -func (c *CheckpointTelemetry) AddSpan(name, pluginType string) *TelemetrySpan { +func (c *CheckpointTelemetry) AddSpan(name, pluginType string, options interface{}) *TelemetrySpan { if c == nil { return nil } log.Printf("[INFO] (telemetry) Starting %s %s", pluginType, name) + ts := &TelemetrySpan{ Name: name, - Type: pluginType, + Options: flattenConfigKeys(options), StartTime: time.Now().UTC(), + Type: pluginType, } c.spans = append(c.spans, ts) return ts @@ -116,8 +119,10 @@ func (c *CheckpointTelemetry) Finalize(command string, errCode int, err error) e extra.Error = err.Error() } params.Payload = extra + // b, _ := json.MarshalIndent(params, "", " ") + // log.Println(string(b)) - ctx, cancel := context.WithTimeout(context.Background(), 1500*time.Millisecond) + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() log.Printf("[INFO] (telemetry) Finalizing.") @@ -125,11 +130,12 @@ func (c *CheckpointTelemetry) Finalize(command string, errCode int, err error) e } type TelemetrySpan struct { - Name string `json:"name"` - Type string `json:"type"` - StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` Error string `json:"error"` + Name string `json:"name"` + Options []string `json:"options"` + StartTime time.Time `json:"start_time"` + Type string `json:"type"` } func (s *TelemetrySpan) End(err error) { @@ -143,3 +149,27 @@ func (s *TelemetrySpan) End(err error) { log.Printf("[INFO] (telemetry) found error: %s", err.Error()) } } + +func flattenConfigKeys(options interface{}) []string { + var flatten func(string, interface{}) []string + + flatten = func(prefix string, options interface{}) (strOpts []string) { + if m, ok := options.(map[string]interface{}); ok { + for k, v := range m { + if prefix != "" { + k = prefix + "/" + k + } + if n, ok := v.(map[string]interface{}); ok { + strOpts = append(strOpts, flatten(k, n)...) + } else { + strOpts = append(strOpts, k) + } + } + } + return + } + + flattened := flatten("", options) + sort.Strings(flattened) + return flattened +} diff --git a/packer/telemetry_test.go b/packer/telemetry_test.go new file mode 100644 index 000000000..c4192f61f --- /dev/null +++ b/packer/telemetry_test.go @@ -0,0 +1,32 @@ +package packer + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFlattenConfigKeys_nil(t *testing.T) { + f := flattenConfigKeys(nil) + assert.Zero(t, f, "Expected empty list.") +} + +func TestFlattenConfigKeys_nested(t *testing.T) { + inp := make(map[string]interface{}) + inp["A"] = "" + inp["B"] = []string{} + + c := make(map[string]interface{}) + c["X"] = "" + d := make(map[string]interface{}) + d["a"] = "" + + c["Y"] = d + inp["C"] = c + + assert.Equal(t, + []string{"A", "B", "C/X", "C/Y/a"}, + flattenConfigKeys(inp), + "Input didn't flatten correctly.", + ) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go index 29b71d176..e6a796046 100644 --- a/vendor/github.com/stretchr/testify/assert/assertion_forward.go +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -1,345 +1,386 @@ /* * CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen * THIS FILE MUST NOT BE EDITED BY HAND - */ +*/ package assert import ( + http "net/http" url "net/url" time "time" ) + // Condition uses a Comparison to assert a complex condition. func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { return Condition(a.t, comp, msgAndArgs...) } + // Contains asserts that the specified string, list(array, slice...) or map contains the // specified substring or element. -// +// // a.Contains("Hello World", "World", "But 'Hello World' does contain 'World'") // a.Contains(["Hello", "World"], "World", "But ["Hello", "World"] does contain 'World'") // a.Contains({"Hello": "World"}, "Hello", "But {'Hello': 'World'} does contain 'Hello'") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { return Contains(a.t, s, contains, msgAndArgs...) } + // Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either // a slice or a channel with len == 0. -// +// // a.Empty(obj) -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { return Empty(a.t, object, msgAndArgs...) } + // Equal asserts that two objects are equal. -// +// // a.Equal(123, 123, "123 and 123 should be equal") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { return Equal(a.t, expected, actual, msgAndArgs...) } + // EqualError asserts that a function returned an error (i.e. not `nil`) // and that it is equal to the provided error. -// +// // actualObj, err := SomeFunction() -// a.EqualError(err, expectedErrorString, "An error was expected") -// +// if assert.Error(t, err, "An error was expected") { +// assert.Equal(t, err, expectedError) +// } +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { return EqualError(a.t, theError, errString, msgAndArgs...) } + // EqualValues asserts that two objects are equal or convertable to the same types // and equal. -// +// // a.EqualValues(uint32(123), int32(123), "123 and 123 should be equal") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { return EqualValues(a.t, expected, actual, msgAndArgs...) } + // Error asserts that a function returned an error (i.e. not `nil`). -// +// // actualObj, err := SomeFunction() // if a.Error(err, "An error was expected") { // assert.Equal(t, err, expectedError) // } -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { return Error(a.t, err, msgAndArgs...) } + // Exactly asserts that two objects are equal is value and type. -// +// // a.Exactly(int32(123), int64(123), "123 and 123 should NOT be equal") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { return Exactly(a.t, expected, actual, msgAndArgs...) } + // Fail reports a failure through func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool { return Fail(a.t, failureMessage, msgAndArgs...) } + // FailNow fails test func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool { return FailNow(a.t, failureMessage, msgAndArgs...) } + // False asserts that the specified value is false. -// +// // a.False(myBool, "myBool should be false") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { return False(a.t, value, msgAndArgs...) } + // HTTPBodyContains asserts that a specified handler returns a // body that contains a string. -// +// // a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool { return HTTPBodyContains(a.t, handler, method, url, values, str) } + // HTTPBodyNotContains asserts that a specified handler returns a // body that does not contain a string. -// +// // a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool { return HTTPBodyNotContains(a.t, handler, method, url, values, str) } + // HTTPError asserts that a specified handler returns an error status code. -// +// // a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) bool { return HTTPError(a.t, handler, method, url, values) } + // HTTPRedirect asserts that a specified handler returns a redirect status code. -// +// // a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) bool { return HTTPRedirect(a.t, handler, method, url, values) } + // HTTPSuccess asserts that a specified handler returns a success status code. -// +// // a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) bool { return HTTPSuccess(a.t, handler, method, url, values) } + // Implements asserts that an object is implemented by the specified interface. -// +// // a.Implements((*MyInterface)(nil), new(MyObject), "MyObject") func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { return Implements(a.t, interfaceObject, object, msgAndArgs...) } + // InDelta asserts that the two numerals are within delta of each other. -// +// // a.InDelta(math.Pi, (22 / 7.0), 0.01) -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { return InDelta(a.t, expected, actual, delta, msgAndArgs...) } + // InDeltaSlice is the same as InDelta, except it compares two slices. func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) } + // InEpsilon asserts that expected and actual have a relative error less than epsilon -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) } -// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. -func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { - return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) + +// InEpsilonSlice is the same as InEpsilon, except it compares two slices. +func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + return InEpsilonSlice(a.t, expected, actual, delta, msgAndArgs...) } + // IsType asserts that the specified objects are of the same type. func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { return IsType(a.t, expectedType, object, msgAndArgs...) } + // JSONEq asserts that two JSON strings are equivalent. -// +// // a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { return JSONEq(a.t, expected, actual, msgAndArgs...) } + // Len asserts that the specified object has specific length. // Len also fails if the object has a type that len() not accept. -// +// // a.Len(mySlice, 3, "The size of slice is not 3") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { return Len(a.t, object, length, msgAndArgs...) } + // Nil asserts that the specified object is nil. -// +// // a.Nil(err, "err should be nothing") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { return Nil(a.t, object, msgAndArgs...) } + // NoError asserts that a function returned no error (i.e. `nil`). -// +// // actualObj, err := SomeFunction() // if a.NoError(err) { // assert.Equal(t, actualObj, expectedObj) // } -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { return NoError(a.t, err, msgAndArgs...) } + // NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the // specified substring or element. -// +// // a.NotContains("Hello World", "Earth", "But 'Hello World' does NOT contain 'Earth'") // a.NotContains(["Hello", "World"], "Earth", "But ['Hello', 'World'] does NOT contain 'Earth'") // a.NotContains({"Hello": "World"}, "Earth", "But {'Hello': 'World'} does NOT contain 'Earth'") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { return NotContains(a.t, s, contains, msgAndArgs...) } + // NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either // a slice or a channel with len == 0. -// +// // if a.NotEmpty(obj) { // assert.Equal(t, "two", obj[1]) // } -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { return NotEmpty(a.t, object, msgAndArgs...) } + // NotEqual asserts that the specified values are NOT equal. -// +// // a.NotEqual(obj1, obj2, "two objects shouldn't be equal") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { return NotEqual(a.t, expected, actual, msgAndArgs...) } + // NotNil asserts that the specified object is not nil. -// +// // a.NotNil(err, "err should be something") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { return NotNil(a.t, object, msgAndArgs...) } + // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. -// +// // a.NotPanics(func(){ // RemainCalm() // }, "Calling RemainCalm() should NOT panic") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { return NotPanics(a.t, f, msgAndArgs...) } + // NotRegexp asserts that a specified regexp does not match a string. -// +// // a.NotRegexp(regexp.MustCompile("starts"), "it's starting") // a.NotRegexp("^start", "it's not starting") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { return NotRegexp(a.t, rx, str, msgAndArgs...) } + // NotZero asserts that i is not the zero value for its type and returns the truth. func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { return NotZero(a.t, i, msgAndArgs...) } + // Panics asserts that the code inside the specified PanicTestFunc panics. -// +// // a.Panics(func(){ // GoCrazy() // }, "Calling GoCrazy() should panic") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { return Panics(a.t, f, msgAndArgs...) } + // Regexp asserts that a specified regexp matches a string. -// +// // a.Regexp(regexp.MustCompile("start"), "it's starting") // a.Regexp("start...$", "it's not starting") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { return Regexp(a.t, rx, str, msgAndArgs...) } + // True asserts that the specified value is true. -// +// // a.True(myBool, "myBool should be true") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { return True(a.t, value, msgAndArgs...) } + // WithinDuration asserts that the two times are within duration delta of each other. -// +// // a.WithinDuration(time.Now(), time.Now(), 10*time.Second, "The difference should not be more than 10s") -// +// // Returns whether the assertion was successful (true) or not (false). func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { return WithinDuration(a.t, expected, actual, delta, msgAndArgs...) } + // Zero asserts that i is the zero value for its type and returns the truth. func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { return Zero(a.t, i, msgAndArgs...) diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index 835084ffc..348d5f1bc 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -18,10 +18,6 @@ import ( "github.com/pmezard/go-difflib/difflib" ) -func init() { - spew.Config.SortKeys = true -} - // TestingT is an interface wrapper around *testing.T type TestingT interface { Errorf(format string, args ...interface{}) @@ -69,7 +65,7 @@ func ObjectsAreEqualValues(expected, actual interface{}) bool { /* CallerInfo is necessary because the assert functions use the testing object internally, causing it to print the file:line of the assert method, rather than where -the problem actually occurred in calling code.*/ +the problem actually occured in calling code.*/ // CallerInfo returns an array of strings containing the file and line number // of each stack frame leading from the current test to the assert call that @@ -86,9 +82,7 @@ func CallerInfo() []string { for i := 0; ; i++ { pc, file, line, ok = runtime.Caller(i) if !ok { - // The breaks below failed to terminate the loop, and we ran off the - // end of the call stack. - break + return nil } // This is a huge edge case, but it will panic if this is the case, see #180 @@ -96,21 +90,6 @@ func CallerInfo() []string { break } - f := runtime.FuncForPC(pc) - if f == nil { - break - } - name = f.Name() - - // testing.tRunner is the standard library function that calls - // tests. Subtests are called directly by tRunner, without going through - // the Test/Benchmark/Example function that contains the t.Run calls, so - // with subtests we should break when we hit tRunner, without adding it - // to the list of callers. - if name == "testing.tRunner" { - break - } - parts := strings.Split(file, "/") dir := parts[len(parts)-2] file = parts[len(parts)-1] @@ -118,6 +97,11 @@ func CallerInfo() []string { callers = append(callers, fmt.Sprintf("%s:%d", file, line)) } + f := runtime.FuncForPC(pc) + if f == nil { + break + } + name = f.Name() // Drop the package segments := strings.Split(name, ".") name = segments[len(segments)-1] @@ -278,48 +262,14 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) if !ObjectsAreEqual(expected, actual) { diff := diff(expected, actual) - expected, actual = formatUnequalValues(expected, actual) - return Fail(t, fmt.Sprintf("Not equal: \n"+ - "expected: %s\n"+ - "received: %s%s", expected, actual, diff), msgAndArgs...) + return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ + " != %#v (actual)%s", expected, actual, diff), msgAndArgs...) } return true } -// formatUnequalValues takes two values of arbitrary types and returns string -// representations appropriate to be presented to the user. -// -// If the values are not of like type, the returned strings will be prefixed -// with the type name, and the value will be enclosed in parenthesis similar -// to a type conversion in the Go grammar. -func formatUnequalValues(expected, actual interface{}) (e string, a string) { - aType := reflect.TypeOf(expected) - bType := reflect.TypeOf(actual) - - if aType != bType && isNumericType(aType) && isNumericType(bType) { - return fmt.Sprintf("%v(%#v)", aType, expected), - fmt.Sprintf("%v(%#v)", bType, actual) - } - - return fmt.Sprintf("%#v", expected), - fmt.Sprintf("%#v", actual) -} - -func isNumericType(t reflect.Type) bool { - switch t.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return true - case reflect.Float32, reflect.Float64: - return true - } - - return false -} - // EqualValues asserts that two objects are equal or convertable to the same types // and equal. // @@ -329,11 +279,8 @@ func isNumericType(t reflect.Type) bool { func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { if !ObjectsAreEqualValues(expected, actual) { - diff := diff(expected, actual) - expected, actual = formatUnequalValues(expected, actual) - return Fail(t, fmt.Sprintf("Not equal: \n"+ - "expected: %s\n"+ - "received: %s%s", expected, actual, diff), msgAndArgs...) + return Fail(t, fmt.Sprintf("Not equal: %#v (expected)\n"+ + " != %#v (actual)", expected, actual), msgAndArgs...) } return true @@ -886,7 +833,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m // Returns whether the assertion was successful (true) or not (false). func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { if err != nil { - return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) + return Fail(t, fmt.Sprintf("Received unexpected error %q", err), msgAndArgs...) } return true @@ -902,8 +849,9 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { // Returns whether the assertion was successful (true) or not (false). func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { + message := messageFromMsgAndArgs(msgAndArgs...) if err == nil { - return Fail(t, "An error is expected but got nil.", msgAndArgs...) + return Fail(t, "An error is expected but got nil. %s", message) } return true @@ -913,22 +861,20 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { // and that it is equal to the provided error. // // actualObj, err := SomeFunction() -// assert.EqualError(t, err, expectedErrorString, "An error was expected") +// if assert.Error(t, err, "An error was expected") { +// assert.Equal(t, err, expectedError) +// } // // Returns whether the assertion was successful (true) or not (false). func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { - if !Error(t, theError, msgAndArgs...) { + + message := messageFromMsgAndArgs(msgAndArgs...) + if !NotNil(t, theError, "An error is expected but got nil. %s", message) { return false } - expected := errString - actual := theError.Error() - // don't need to use deep equals here, we know they are both strings - if expected != actual { - return Fail(t, fmt.Sprintf("Error message not equal:\n"+ - "expected: %q\n"+ - "received: %q", expected, actual), msgAndArgs...) - } - return true + s := "An error with value \"%s\" is expected but got \"%s\". %s" + return Equal(t, errString, theError.Error(), + s, errString, theError.Error(), message) } // matchRegexp return true if a specified regexp matches a string. @@ -1043,6 +989,7 @@ func diff(expected interface{}, actual interface{}) string { return "" } + spew.Config.SortKeys = true e := spew.Sdump(expected) a := spew.Sdump(actual) diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go index fa7ab89b1..e1b9442b5 100644 --- a/vendor/github.com/stretchr/testify/assert/http_assertions.go +++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go @@ -99,7 +99,7 @@ func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url strin contains := strings.Contains(body, fmt.Sprint(str)) if contains { - Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) + Fail(t, "Expected response body for %s to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body) } return !contains diff --git a/vendor/vendor.json b/vendor/vendor.json index a8db37219..3778555c7 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1057,10 +1057,11 @@ "revisionTime": "2017-03-21T23:07:31Z" }, { - "checksumSHA1": "Q2V7Zs3diLmLfmfbiuLpSxETSuY=", + "checksumSHA1": "iydUphwYqZRq3WhstEdGsbvBAKs=", "comment": "v1.1.4-4-g976c720", "path": "github.com/stretchr/testify/assert", - "revision": "976c720a22c8eb4eb6a0b4348ad85ad12491a506" + "revision": "d77da356e56a7428ad25149ca77381849a6a5232", + "revisionTime": "2016-06-15T09:26:46Z" }, { "checksumSHA1": "GQ9bu6PuydK3Yor1JgtVKUfEJm8=",