From 9a85401dd8a6309770cb5cb1ab14215437024c7f Mon Sep 17 00:00:00 2001 From: matheusalcantarazup <84723211+matheusalcantarazup@users.noreply.github.com> Date: Wed, 27 Oct 2021 16:54:45 -0300 Subject: [PATCH] workflow: execute unit tests on Windows (#717) Previously some unit tests was implemented to execute and validate scenarios only for Linux based machines. This commit fix these tests to execute on Windows. Note that the goal of this commit is only to fix these tests and make them work on Windows, we still need to make some improvements on some of these tests to have a better assertiveness. This commit also change the configuration of Test workflow to add windows-latest as a new runner. Signed-off-by: Matheus Alcantara --- .github/workflows/test.yml | 11 +++++- config/config_test.go | 5 ++- internal/services/docker/docker_api_test.go | 12 ++++-- .../formatters/csharp/scs/formatter_test.go | 37 +++++++++--------- internal/services/formatters/service_test.go | 14 ++++--- internal/services/git/git_test.go | 4 +- internal/usecases/cli/cli_test.go | 38 ++++++++++++------- 7 files changed, 76 insertions(+), 45 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index afd2320f3..fd456190f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,14 @@ on: [ "pull_request" ] permissions: read-all jobs: test: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + go-version: + - 1.17 + os: + - ubuntu-latest + - windows-latest if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - uses: actions/checkout@v2 @@ -26,6 +33,6 @@ jobs: fetch-depth: 0 - uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: ${{ matrix.go-version }} - name: test run: make test diff --git a/config/config_test.go b/config/config_test.go index 6c062de23..03af8e1f5 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -20,6 +20,7 @@ import ( "os" "path" "path/filepath" + "strings" "testing" "github.com/ZupIT/horusec-devkit/pkg/enums/vulnerability" @@ -451,7 +452,7 @@ func TestConfig_Bytes(t *testing.T) { "cert_path": "cert-path", "repository_name": "my-project", "print_output_type": "sonarqube", - "json_output_file_path": "/tmp/output-sonarqube.json", + "json_output_file_path": "` + filepath.Join(os.TempDir(), "output-sonarqube.json") + `", "project_path": "./horusec-manager", "custom_rules_path": "test", "container_bind_project_path": "./my-path", @@ -591,6 +592,8 @@ func TestConfig_Bytes(t *testing.T) { }, "version": "{{VERSION_NOT_FOUND}}" }` + // Add scape slashes when running on Windows. + expectedOutput = strings.ReplaceAll(expectedOutput, `\`, `\\`) assert.Equal(t, expectedOutput, string(cfg.Bytes())) }) t.Run("Should have the predefined schema", func(t *testing.T) { diff --git a/internal/services/docker/docker_api_test.go b/internal/services/docker/docker_api_test.go index a408de6ec..d688ab995 100644 --- a/internal/services/docker/docker_api_test.go +++ b/internal/services/docker/docker_api_test.go @@ -24,9 +24,12 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/errdefs" "github.com/google/uuid" "github.com/stretchr/testify/assert" + errorsenum "github.com/ZupIT/horusec/internal/enums/errors" + cliConfig "github.com/ZupIT/horusec/config" dockerEntities "github.com/ZupIT/horusec/internal/entities/docker" "github.com/ZupIT/horusec/internal/services/docker/client" @@ -61,7 +64,7 @@ const ( ) func TestDockerAPI_CreateLanguageAnalysisContainer(t *testing.T) { - t.Run("Should return return error when ImagePath is empty", func(t *testing.T) { + t.Run("Should return error when DefaultImage is empty", func(t *testing.T) { api := New(client.NewDockerClient(), &cliConfig.Config{}, uuid.New()) _, err := api.CreateLanguageAnalysisContainer(&dockerEntities.AnalysisData{ DefaultImage: "", @@ -69,9 +72,10 @@ func TestDockerAPI_CreateLanguageAnalysisContainer(t *testing.T) { }) assert.Error(t, err) + assert.ErrorIs(t, err, errorsenum.ErrImageTagCmdRequired) }) - t.Run("Should return return error when cmd is empty", func(t *testing.T) { + t.Run("Should return error when cmd is empty", func(t *testing.T) { api := New(client.NewDockerClient(), &cliConfig.Config{}, uuid.New()) _, err := api.CreateLanguageAnalysisContainer(&dockerEntities.AnalysisData{ DefaultImage: "image", @@ -79,6 +83,7 @@ func TestDockerAPI_CreateLanguageAnalysisContainer(t *testing.T) { }) assert.Error(t, err) + assert.ErrorIs(t, err, errorsenum.ErrImageTagCmdRequired) }) t.Run("Should return error when pull image aleatory", func(t *testing.T) { @@ -88,6 +93,7 @@ func TestDockerAPI_CreateLanguageAnalysisContainer(t *testing.T) { CMD: "command", }) + assert.True(t, errdefs.IsInvalidParameter(err), "Expected error ErrInvalidParameter") assert.Error(t, err) }) @@ -99,7 +105,7 @@ func TestDockerAPI_CreateLanguageAnalysisContainer(t *testing.T) { }) assert.Error(t, err) - assert.Contains(t, err.Error(), "Error response from daemon: invalid mount config for type \"bind\": bind source path does not exist:") + assert.True(t, errdefs.IsInvalidParameter(err), "Expected error ErrInvalidParameter") }) t.Run("Should return error when list image to check if exist", func(t *testing.T) { diff --git a/internal/services/formatters/csharp/scs/formatter_test.go b/internal/services/formatters/csharp/scs/formatter_test.go index 595c05719..07f2bf4db 100644 --- a/internal/services/formatters/csharp/scs/formatter_test.go +++ b/internal/services/formatters/csharp/scs/formatter_test.go @@ -17,9 +17,11 @@ package scs import ( "errors" "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" analysisEntities "github.com/ZupIT/horusec-devkit/pkg/entities/analysis" @@ -31,26 +33,26 @@ import ( "github.com/ZupIT/horusec/internal/services/formatters/csharp/scs/enums" ) -func createSlnFile() error { - path, _ := os.Getwd() +func createSlnFile(t *testing.T) { + wd, _ := os.Getwd() - if err := os.MkdirAll(path+"/.horusec/00000000-0000-0000-0000-000000000000", 0755); err != nil { - return err - } + dir := filepath.Join(wd, ".horusec", "00000000-0000-0000-0000-000000000000") + err := os.MkdirAll(dir, 0755) + require.Nil(t, err, "Expected nil error to create sln directory: %v", err) - _, err := os.Create(path + "/.horusec/00000000-0000-0000-0000-000000000000/test.sln") - return err -} + f, err := os.Create(filepath.Join(dir, "test.sln")) + require.Nil(t, err, "Expected nil error to create sln file: %v", err) -func removeSlnFile() error { - path, _ := os.Getwd() + t.Cleanup(func() { + assert.NoError(t, f.Close(), "Expected nil error to close sln file") + assert.NoError(t, os.RemoveAll(dir), "Expected nil error to remove sln directory") + }) - return os.RemoveAll(path + "/.horusec") } func TestParseOutput(t *testing.T) { t.Run("should return 4 vulnerabilities with no errors", func(t *testing.T) { - assert.NoError(t, createSlnFile()) + createSlnFile(t) dockerAPIControllerMock := &docker.Mock{} dockerAPIControllerMock.On("SetAnalysisID") @@ -104,11 +106,10 @@ func TestParseOutput(t *testing.T) { formatter.StartAnalysis("") assert.Len(t, analysis.AnalysisVulnerabilities, 4) - assert.NoError(t, removeSlnFile()) }) t.Run("should return error when unmarshalling output", func(t *testing.T) { - assert.NoError(t, createSlnFile()) + createSlnFile(t) analysis := &analysisEntities.Analysis{} dockerAPIControllerMock := &docker.Mock{} @@ -126,11 +127,10 @@ func TestParseOutput(t *testing.T) { formatter.StartAnalysis("") assert.NotEmpty(t, analysis.Errors) - assert.NoError(t, removeSlnFile()) }) t.Run("should return build error", func(t *testing.T) { - assert.NoError(t, createSlnFile()) + createSlnFile(t) analysis := &analysisEntities.Analysis{} dockerAPIControllerMock := &docker.Mock{} @@ -148,7 +148,6 @@ func TestParseOutput(t *testing.T) { formatter.StartAnalysis("") assert.NotEmpty(t, analysis.Errors) - assert.NoError(t, removeSlnFile()) }) t.Run("should return error not found solution file", func(t *testing.T) { @@ -168,7 +167,7 @@ func TestParseOutput(t *testing.T) { }) t.Run("should return error executing container", func(t *testing.T) { - assert.NoError(t, createSlnFile()) + createSlnFile(t) analysis := &analysisEntities.Analysis{} dockerAPIControllerMock := &docker.Mock{} @@ -184,8 +183,6 @@ func TestParseOutput(t *testing.T) { formatter.StartAnalysis("") assert.NotEmpty(t, analysis.Errors) - - assert.NoError(t, removeSlnFile()) }) t.Run("should not execute tool because it's ignored", func(t *testing.T) { diff --git a/internal/services/formatters/service_test.go b/internal/services/formatters/service_test.go index 0360bf6b2..59f6bae59 100644 --- a/internal/services/formatters/service_test.go +++ b/internal/services/formatters/service_test.go @@ -17,6 +17,7 @@ package formatters import ( "errors" "fmt" + "path/filepath" "strconv" "testing" @@ -166,15 +167,18 @@ func TestGetCommitAuthor(t *testing.T) { func TestGetConfigProjectPath(t *testing.T) { t.Run("should success get project path", func(t *testing.T) { - cliConfig := &config.Config{} - cliConfig.ProjectPath = "test" + cliConfig := &config.Config{ + StartOptions: config.StartOptions{ + ProjectPath: "test", + }, + } - monitorController := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, cliConfig) + svc := NewFormatterService(&analysis.Analysis{}, &docker.Mock{}, cliConfig) - result := monitorController.GetConfigProjectPath() + result := svc.GetConfigProjectPath() assert.NotEmpty(t, result) - assert.Equal(t, "test/.horusec/00000000-0000-0000-0000-000000000000", result) + assert.Equal(t, filepath.Join("test", ".horusec", "00000000-0000-0000-0000-000000000000"), result) }) } diff --git a/internal/services/git/git_test.go b/internal/services/git/git_test.go index 83e722c1a..f1553e622 100644 --- a/internal/services/git/git_test.go +++ b/internal/services/git/git_test.go @@ -93,7 +93,9 @@ func TestGetCommitAuthor(t *testing.T) { require.Nil(t, err, "Expected nil error to create temp file: %v", err) t.Cleanup(func() { - require.Nil(t, os.Remove(tmp.Name()), "Expected nil error to delete temp file: %v", err) + assert.NoError(t, tmp.Close(), "Expected nil error to close temp file") + err := os.Remove(tmp.Name()) + require.Nil(t, err, "Expected nil error to delete temp file: %v", err) }) author := service.CommitAuthor("1-2", tmp.Name()) diff --git a/internal/usecases/cli/cli_test.go b/internal/usecases/cli/cli_test.go index 59c6452d6..c4192f0f1 100644 --- a/internal/usecases/cli/cli_test.go +++ b/internal/usecases/cli/cli_test.go @@ -15,9 +15,12 @@ package cli import ( + "errors" + "os" "testing" "github.com/ZupIT/horusec/internal/enums/outputtype" + validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/stretchr/testify/assert" @@ -129,23 +132,32 @@ func TestValidateConfigs(t *testing.T) { assert.NoError(t, err) }) t.Run("Should return error because not exists path in workdir", func(t *testing.T) { - cfg := &config.Config{} - cfg.WorkDir = &workdir.WorkDir{ - Go: []string{"NOT EXISTS PATH"}, - CSharp: []string{}, - Ruby: []string{}, - Python: []string{}, - Java: []string{}, - Kotlin: []string{}, - JavaScript: []string{}, - Leaks: []string{}, - HCL: []string{}, + cfg := &config.Config{ + StartOptions: config.StartOptions{ + WorkDir: &workdir.WorkDir{ + Go: []string{"NOT EXISTS PATH"}, + CSharp: []string{}, + Ruby: []string{}, + Python: []string{}, + Java: []string{}, + Kotlin: []string{}, + JavaScript: []string{}, + Leaks: []string{}, + HCL: []string{}, + }, + }, } err := useCases.ValidateConfig(cfg) assert.Error(t, err) - assert.Contains(t, err.Error(), "work_dir: stat ") - assert.Contains(t, err.Error(), "internal/usecases/cli/NOT EXISTS PATH: no such file or directory.") + + var vErrors validation.Errors + assert.True(t, errors.As(err, &vErrors), "Expected that error should be validiation.Errors") + + workDirErr, exists := vErrors["work_dir"] + assert.True(t, exists, "Expected error from work dir config") + + assert.ErrorIs(t, workDirErr, os.ErrNotExist) }) t.Run("Should return error because cert path is not valid", func(t *testing.T) { cfg := config.New()