diff --git a/cmd/performance/cmd/mkcmp.go b/cmd/performance/cmd/mkcmp.go index 91e887907c..d146bb9bed 100644 --- a/cmd/performance/cmd/mkcmp.go +++ b/cmd/performance/cmd/mkcmp.go @@ -39,7 +39,7 @@ var rootCmd = &cobra.Command{ if err != nil { return err } - return performance.CompareMinikubeStart(context.Background(), binaries) + return performance.CompareMinikubeStart(context.Background(), os.Stdout, binaries) }, } diff --git a/pkg/minikube/performance/start.go b/pkg/minikube/performance/start.go index 1fdb7cab37..7cd8ece6b5 100644 --- a/pkg/minikube/performance/start.go +++ b/pkg/minikube/performance/start.go @@ -19,6 +19,7 @@ package performance import ( "context" "fmt" + "io" "log" "os" "os/exec" @@ -27,12 +28,24 @@ import ( "github.com/pkg/errors" ) -const ( +var ( runs = 1 + // For testing + collectTimeMinikubeStart = timeMinikubeStart ) // CompareMinikubeStart compares the time to run `minikube start` between two minikube binaries -func CompareMinikubeStart(ctx context.Context, binaries []*Binary) error { +func CompareMinikubeStart(ctx context.Context, out io.Writer, binaries []*Binary) error { + durations, err := collectTimes(ctx, binaries) + if err != nil { + return err + } + + fmt.Fprintf(out, "Old binary: %v\nNew binary: %v\nAverage Old: %f\nAverage New: %f\n", durations[0], durations[1], average(durations[0]), average(durations[1])) + return nil +} + +func collectTimes(ctx context.Context, binaries []*Binary) ([][]float64, error) { durations := make([][]float64, len(binaries)) for i := range durations { durations[i] = make([]float64, runs) @@ -41,17 +54,15 @@ func CompareMinikubeStart(ctx context.Context, binaries []*Binary) error { for r := 0; r < runs; r++ { log.Printf("Executing run %d...", r) for index, binary := range binaries { - duration, err := timeMinikubeStart(ctx, binary) + duration, err := collectTimeMinikubeStart(ctx, binary) if err != nil { - return errors.Wrapf(err, "timing run %d with %s", r, binary.path) + return nil, errors.Wrapf(err, "timing run %d with %s", r, binary.path) } durations[index][r] = duration } } - fmt.Printf("Old binary: %v\nNew binary: %v\nAverage Old: %f\nAverage New: %f\n", durations[0], durations[1], average(durations[0]), average(durations[1])) - - return nil + return durations, nil } func average(array []float64) float64 { diff --git a/pkg/minikube/performance/start_test.go b/pkg/minikube/performance/start_test.go new file mode 100644 index 0000000000..1b36bb85d0 --- /dev/null +++ b/pkg/minikube/performance/start_test.go @@ -0,0 +1,130 @@ +/* +Copyright 2017 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package performance + +import ( + "bytes" + "context" + "reflect" + "testing" +) + +func mockCollectTimeMinikubeStart(durations []float64) func(ctx context.Context, binary *Binary) (float64, error) { + index := 0 + return func(context.Context, *Binary) (float64, error) { + duration := durations[index] + index = index + 1 + return duration, nil + } +} + +func TestCompareMinikubeStartOutput(t *testing.T) { + tests := []struct { + description string + durations []float64 + expected string + }{ + { + description: "standard run", + durations: []float64{4.5, 6}, + expected: "Old binary: [4.5]\nNew binary: [6]\nAverage Old: 4.500000\nAverage New: 6.000000\n", + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + originalCollectTimes := collectTimeMinikubeStart + collectTimeMinikubeStart = mockCollectTimeMinikubeStart(test.durations) + defer func() { collectTimeMinikubeStart = originalCollectTimes }() + + buf := bytes.NewBuffer([]byte{}) + err := CompareMinikubeStart(context.Background(), buf, []*Binary{{}, {}}) + if err != nil { + t.Fatalf("error comparing minikube start: %v", err) + } + + actual := buf.String() + if test.expected != actual { + t.Fatalf("actual output does not match expected output\nActual: %v\nExpected: %v", actual, test.expected) + } + }) + } +} + +func TestCollectTimes(t *testing.T) { + tests := []struct { + description string + durations []float64 + runs int + expected [][]float64 + }{ + { + description: "two runs", + durations: []float64{1, 2, 3, 4}, + runs: 2, + expected: [][]float64{ + {1, 3}, + {2, 4}, + }, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + originalCollectTimes := collectTimeMinikubeStart + collectTimeMinikubeStart = mockCollectTimeMinikubeStart(test.durations) + defer func() { collectTimeMinikubeStart = originalCollectTimes }() + + runs = test.runs + actual, err := collectTimes(context.Background(), []*Binary{{}, {}}) + if err != nil { + t.Fatalf("error collecting times: %v", err) + } + + if !reflect.DeepEqual(actual, test.expected) { + t.Fatalf("actual output does not match expected output\nActual: %v\nExpected: %v", actual, test.expected) + } + }) + } +} + +func TestAverage(t *testing.T) { + tests := []struct { + description string + nums []float64 + expected float64 + }{ + { + description: "one number", + nums: []float64{4}, + expected: 4, + }, { + description: "multiple numbers", + nums: []float64{1, 4}, + expected: 2.5, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + actual := average(test.nums) + if actual != test.expected { + t.Fatalf("actual output does not match expected output\nActual: %v\nExpected: %v", actual, test.expected) + } + }) + } +}