From 0f9bbcf5020498899aa3da7bf95b013041ef02f4 Mon Sep 17 00:00:00 2001 From: lyyyuna Date: Wed, 5 Aug 2020 19:55:07 +0800 Subject: [PATCH] add unit test for merge --- cmd/merge.go | 12 +- cmd/merge_test.go | 156 ++++++++++++++++++ tests/samples/merge_profile_samples/empty.voc | 0 .../samples/merge_profile_samples/overlap.voc | 3 + .../samples/merge_profile_samples/setmode.voc | 3 + 5 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 cmd/merge_test.go create mode 100644 tests/samples/merge_profile_samples/empty.voc create mode 100644 tests/samples/merge_profile_samples/overlap.voc create mode 100644 tests/samples/merge_profile_samples/setmode.voc diff --git a/cmd/merge.go b/cmd/merge.go index 50435e7..64e6495 100644 --- a/cmd/merge.go +++ b/cmd/merge.go @@ -17,7 +17,7 @@ package cmd import ( - "log" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "golang.org/x/tools/cover" @@ -34,7 +34,7 @@ same paths, then the contents of those source files were identical for the binar each file. `, Run: func(cmd *cobra.Command, args []string) { - run(cmd, args) + runMerge(args, outputMergeProfile) }, } @@ -46,9 +46,10 @@ func init() { rootCmd.AddCommand(mergeCmd) } -func run(cmd *cobra.Command, args []string) { +func runMerge(args []string, output string) { if len(args) == 0 { log.Fatalln("Expected at least one coverage file.") + return } profiles := make([][]*cover.Profile, len(args)) @@ -56,6 +57,7 @@ func run(cmd *cobra.Command, args []string) { profile, err := util.LoadProfile(path) if err != nil { log.Fatalf("failed to open %s: %v", path, err) + return } profiles = append(profiles, profile) } @@ -63,10 +65,12 @@ func run(cmd *cobra.Command, args []string) { merged, err := cov.MergeMultipleProfiles(profiles) if err != nil { log.Fatalf("failed to merge files: %v", err) + return } - err = util.DumpProfile(outputMergeProfile, merged) + err = util.DumpProfile(output, merged) if err != nil { log.Fatalln(err) + return } } diff --git a/cmd/merge_test.go b/cmd/merge_test.go new file mode 100644 index 0000000..ee35d79 --- /dev/null +++ b/cmd/merge_test.go @@ -0,0 +1,156 @@ +/* + Copyright 2020 Qiniu Cloud (qiniu.com) + + 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 cmd + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" +) + +// use a variable to record if the tested function has failed +// so unittest can only be exectued sequential +var fatal = false +var fatalStr string + +type TestLogHook struct{} + +func (h *TestLogHook) Levels() []log.Level { + return []log.Level{log.FatalLevel} +} + +func (h *TestLogHook) Fire(e *log.Entry) error { + fatalStr = e.Message + return nil +} + +func TestMain(m *testing.M) { + // setup + originalExitFunc := log.StandardLogger().ExitFunc + defer func() { + log.StandardLogger().ExitFunc = originalExitFunc + log.StandardLogger().Hooks = make(log.LevelHooks) + }() + + // replace exit function, so log.Fatal wont exit + log.StandardLogger().ExitFunc = func(int) { fatal = true } + // add hook, so fatal string will be recorded + log.StandardLogger().Hooks.Add(&TestLogHook{}) + + code := m.Run() + + os.Exit(code) +} + +func TestMergeNormalProfiles(t *testing.T) { + profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") + profileB := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/b.voc") + mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") + + runMerge([]string{profileA, profileB}, mergeprofile) + + contents, err := ioutil.ReadFile(mergeprofile) + assert.NoError(t, err) + assert.Contains(t, string(contents), "qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 60") + assert.Contains(t, string(contents), "qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 2") + assert.Equal(t, fatal, false) +} + +// test with no profiles +func TestMergeWithNoProfiles(t *testing.T) { + mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") + + // clear fatal string in setup + fatalStr = "" + fatal = false + + runMerge([]string{}, mergeprofile) + + // there is fatal + assert.Equal(t, fatal, true) + assert.Equal(t, fatalStr, "Expected at least one coverage file.") +} + +// pass a non-existed profile to runMerge +func TestWithWrongProfileName(t *testing.T) { + profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/notexist.voc") + mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") + + // clear fatal string in setup + fatalStr = "" + fatal = false + + runMerge([]string{profileA}, mergeprofile) + + // there is fatal + assert.Equal(t, fatal, true) + assert.Contains(t, fatalStr, "failed to open") +} + +// merge two different modes' profiles should fail +func TestMergeTwoDifferentModeProfile(t *testing.T) { + profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") + profileSet := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/setmode.voc") + mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") + + // clear fatal string in setup + fatalStr = "" + fatal = false + + runMerge([]string{profileA, profileSet}, mergeprofile) + + // there is fatal + assert.Equal(t, fatal, true) + assert.Contains(t, fatalStr, "mode for qiniu.com/kodo/apiserver/server/main.go mismatches") +} + +// merge two overlaped profiles should fail +func TestMergeTwoOverLapProfile(t *testing.T) { + profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") + profileOverlap := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/overlap.voc") + mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") + + // clear fatal string in setup + fatalStr = "" + fatal = false + + runMerge([]string{profileA, profileOverlap}, mergeprofile) + + // there is fatal + assert.Equal(t, fatal, true) + assert.Contains(t, fatalStr, "coverage block mismatch") +} + +// merge empty file should fail +func TestMergeEmptyProfile(t *testing.T) { + profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/empty.voc") + mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") + + // clear fatal string in setup + fatalStr = "" + fatal = false + + runMerge([]string{profileA}, mergeprofile) + + // there is fatal + assert.Equal(t, fatal, true) + assert.Contains(t, fatalStr, "failed to dump profile") +} diff --git a/tests/samples/merge_profile_samples/empty.voc b/tests/samples/merge_profile_samples/empty.voc new file mode 100644 index 0000000..e69de29 diff --git a/tests/samples/merge_profile_samples/overlap.voc b/tests/samples/merge_profile_samples/overlap.voc new file mode 100644 index 0000000..cc87489 --- /dev/null +++ b/tests/samples/merge_profile_samples/overlap.voc @@ -0,0 +1,3 @@ +mode: atomic +qiniu.com/kodo/apiserver/server/main.go:32.49,33.12 1 30 +qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/setmode.voc b/tests/samples/merge_profile_samples/setmode.voc new file mode 100644 index 0000000..8ea14ce --- /dev/null +++ b/tests/samples/merge_profile_samples/setmode.voc @@ -0,0 +1,3 @@ +mode: set +qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 +qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file