From ec0d2a5ed2327ba192b03ace08ecf2b7472ee2a4 Mon Sep 17 00:00:00 2001 From: mmetc <92726601+mmetc@users.noreply.github.com> Date: Mon, 17 Oct 2022 14:17:23 +0200 Subject: [PATCH] refactor broker_test.go, extract cstest/filenotfound*.go (#1815) --- pkg/acquisition/acquisition_test.go | 25 +- pkg/csconfig/config_test.go | 39 +-- pkg/csconfig/simulation_test.go | 109 +++---- pkg/csplugin/broker_test.go | 421 ++++++++++++++-------------- pkg/csplugin/broker_win_test.go | 10 +- pkg/cstest/filenotfound_unix.go | 5 + pkg/cstest/filenotfound_windows.go | 5 + 7 files changed, 274 insertions(+), 340 deletions(-) create mode 100644 pkg/cstest/filenotfound_unix.go create mode 100644 pkg/cstest/filenotfound_windows.go diff --git a/pkg/acquisition/acquisition_test.go b/pkg/acquisition/acquisition_test.go index 7344fcb82..171196d2e 100644 --- a/pkg/acquisition/acquisition_test.go +++ b/pkg/acquisition/acquisition_test.go @@ -6,16 +6,17 @@ import ( "testing" "time" - "github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration" - "github.com/crowdsecurity/crowdsec/pkg/csconfig" - "github.com/crowdsecurity/crowdsec/pkg/cstest" - "github.com/crowdsecurity/crowdsec/pkg/types" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" tomb "gopkg.in/tomb.v2" "gopkg.in/yaml.v2" "gotest.tools/v3/assert" + + "github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration" + "github.com/crowdsecurity/crowdsec/pkg/csconfig" + "github.com/crowdsecurity/crowdsec/pkg/cstest" + "github.com/crowdsecurity/crowdsec/pkg/types" ) type MockSource struct { @@ -226,7 +227,7 @@ func TestLoadAcquisitionFromFile(t *testing.T) { Config: csconfig.CrowdsecServiceCfg{ AcquisitionFiles: []string{"does_not_exist"}, }, - ExpectedError: "can't open does_not_exist", + ExpectedError: cstest.FileNotFoundMessage, ExpectedLen: 0, }, { @@ -282,18 +283,8 @@ func TestLoadAcquisitionFromFile(t *testing.T) { } for _, test := range tests { dss, err := LoadAcquisitionFromFile(&test.Config) - if test.ExpectedError != "" { - if err == nil { - t.Fatalf("expected error %s, got none", test.ExpectedError) - } - if !strings.Contains(err.Error(), test.ExpectedError) { - t.Fatalf("%s : expected error '%s' in '%s'", test.TestName, test.ExpectedError, err) - } - continue - } - if err != nil { - t.Fatalf("%s : unexpected error '%s'", test.TestName, err) - } + cstest.RequireErrorContains(t, err, test.ExpectedError) + if len(dss) != test.ExpectedLen { t.Fatalf("%s : expected %d datasources got %d", test.TestName, test.ExpectedLen, len(dss)) } diff --git a/pkg/csconfig/config_test.go b/pkg/csconfig/config_test.go index d49e25afb..7c3da496c 100644 --- a/pkg/csconfig/config_test.go +++ b/pkg/csconfig/config_test.go @@ -1,27 +1,20 @@ package csconfig import ( - "fmt" - "log" - "runtime" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/crowdsecurity/crowdsec/pkg/cstest" ) func TestNormalLoad(t *testing.T) { - _, err := NewConfig("./tests/config.yaml", false, false) - if err != nil { - t.Fatalf("unexpected error %s", err) - } + require.NoError(t, err) _, err = NewConfig("./tests/xxx.yaml", false, false) - if runtime.GOOS != "windows" { - assert.EqualError(t, err, "while reading yaml file: open ./tests/xxx.yaml: no such file or directory") - } else { - assert.EqualError(t, err, "while reading yaml file: open ./tests/xxx.yaml: The system cannot find the file specified.") - } + assert.EqualError(t, err, "while reading yaml file: open ./tests/xxx.yaml: "+cstest.FileNotFoundMessage) _, err = NewConfig("./tests/simulation.yaml", false, false) assert.EqualError(t, err, "./tests/simulation.yaml: yaml: unmarshal errors:\n line 1: field simulation not found in type csconfig.Config") @@ -31,29 +24,23 @@ func TestNewCrowdSecConfig(t *testing.T) { tests := []struct { name string expectedResult *Config - err string }{ { name: "new configuration: basic", expectedResult: &Config{}, - err: "", }, } - for _, test := range tests { - result := &Config{} - isOk := assert.Equal(t, test.expectedResult, result) - if !isOk { - t.Fatalf("TEST '%s': NOK", test.name) - } else { - fmt.Printf("TEST '%s': OK\n", test.name) - } + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + result := &Config{} + assert.Equal(t, tc.expectedResult, result) + }) } - } func TestDefaultConfig(t *testing.T) { x := NewDefaultConfig() - if err := x.Dump(); err != nil { - log.Fatal(err) - } + err := x.Dump() + require.NoError(t, err) } diff --git a/pkg/csconfig/simulation_test.go b/pkg/csconfig/simulation_test.go index a64c69a97..5256806d0 100644 --- a/pkg/csconfig/simulation_test.go +++ b/pkg/csconfig/simulation_test.go @@ -3,30 +3,26 @@ package csconfig import ( "fmt" "path/filepath" - "runtime" - "strings" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/crowdsecurity/crowdsec/pkg/cstest" ) func TestSimulationLoading(t *testing.T) { - testXXFullPath, err := filepath.Abs("./tests/xxx.yaml") - if err != nil { - panic(err) - } + require.NoError(t, err) badYamlFullPath, err := filepath.Abs("./tests/config.yaml") - if err != nil { - panic(err) - } + require.NoError(t, err) tests := []struct { name string Input *Config expectedResult *SimulationConfig - err string + expectedErr string }{ { name: "basic valid simulation", @@ -49,6 +45,18 @@ func TestSimulationLoading(t *testing.T) { }, Crowdsec: &CrowdsecServiceCfg{}, }, + expectedErr: "simulation.yaml: "+cstest.FileNotFoundMessage, + }, + { + name: "basic bad file name", + Input: &Config{ + ConfigPaths: &ConfigurationPaths{ + SimulationFilePath: "./tests/xxx.yaml", + DataDir: "./data", + }, + Crowdsec: &CrowdsecServiceCfg{}, + }, + expectedErr: fmt.Sprintf("while reading yaml file: open %s: %s", testXXFullPath, cstest.FileNotFoundMessage), }, { name: "basic bad file content", @@ -59,7 +67,7 @@ func TestSimulationLoading(t *testing.T) { }, Crowdsec: &CrowdsecServiceCfg{}, }, - err: fmt.Sprintf("while unmarshaling simulation file '%s' : yaml: unmarshal errors", badYamlFullPath), + expectedErr: fmt.Sprintf("while unmarshaling simulation file '%s' : yaml: unmarshal errors", badYamlFullPath), }, { name: "basic bad file content", @@ -70,66 +78,18 @@ func TestSimulationLoading(t *testing.T) { }, Crowdsec: &CrowdsecServiceCfg{}, }, - err: fmt.Sprintf("while unmarshaling simulation file '%s' : yaml: unmarshal errors", badYamlFullPath), + expectedErr: fmt.Sprintf("while unmarshaling simulation file '%s' : yaml: unmarshal errors", badYamlFullPath), }, } - if runtime.GOOS == "windows" { - tests = append(tests, struct { - name string - Input *Config - expectedResult *SimulationConfig - err string - }{ - name: "basic bad file name", - Input: &Config{ - ConfigPaths: &ConfigurationPaths{ - SimulationFilePath: "./tests/xxx.yaml", - DataDir: "./data", - }, - Crowdsec: &CrowdsecServiceCfg{}, - }, - err: fmt.Sprintf("while reading yaml file: open %s: The system cannot find the file specified.", testXXFullPath), - }) - } else { - tests = append(tests, struct { - name string - Input *Config - expectedResult *SimulationConfig - err string - }{ - name: "basic bad file name", - Input: &Config{ - ConfigPaths: &ConfigurationPaths{ - SimulationFilePath: "./tests/xxx.yaml", - DataDir: "./data", - }, - Crowdsec: &CrowdsecServiceCfg{}, - }, - err: fmt.Sprintf("while reading yaml file: open %s: no such file or directory", testXXFullPath), - }) - } + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + err := tc.Input.LoadSimulation() + cstest.RequireErrorContains(t, err, tc.expectedErr) - for idx, test := range tests { - err := test.Input.LoadSimulation() - if err == nil && test.err != "" { - fmt.Printf("TEST '%s': NOK\n", test.name) - t.Fatalf("%d/%d expected error, didn't get it", idx, len(tests)) - } - if test.err != "" { - if !strings.HasPrefix(fmt.Sprintf("%s", err), test.err) { - fmt.Printf("TEST '%s': NOK\n", test.name) - t.Fatalf("%d/%d expected '%s' got '%s'", idx, len(tests), - test.err, - fmt.Sprintf("%s", err)) - } - } - isOk := assert.Equal(t, test.expectedResult, test.Input.Crowdsec.SimulationConfig) - if !isOk { - t.Fatalf("TEST '%s': NOK\n", test.name) - } else { - fmt.Printf("TEST '%s': OK\n", test.name) - } + assert.Equal(t, tc.expectedResult, tc.Input.Crowdsec.SimulationConfig) + }) } } @@ -150,7 +110,6 @@ func TestIsSimulated(t *testing.T) { SimulationConfig *SimulationConfig Input string expectedResult bool - err string }{ { name: "No simulation except (in exclusion)", @@ -171,13 +130,11 @@ func TestIsSimulated(t *testing.T) { expectedResult: false, }, } - for _, test := range tests { - IsSimulated := test.SimulationConfig.IsSimulated(test.Input) - isOk := assert.Equal(t, test.expectedResult, IsSimulated) - if !isOk { - fmt.Printf("TEST: '%v' failed", test.name) - t.Fatal() - } + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + IsSimulated := tc.SimulationConfig.IsSimulated(tc.Input) + require.Equal(t, tc.expectedResult, IsSimulated) + }) } - } diff --git a/pkg/csplugin/broker_test.go b/pkg/csplugin/broker_test.go index 145b7c33d..b2e9a7d94 100644 --- a/pkg/csplugin/broker_test.go +++ b/pkg/csplugin/broker_test.go @@ -14,31 +14,32 @@ import ( "time" log "github.com/sirupsen/logrus" - - "github.com/crowdsecurity/crowdsec/pkg/csconfig" - "github.com/crowdsecurity/crowdsec/pkg/models" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "gopkg.in/tomb.v2" "gopkg.in/yaml.v2" + + "github.com/crowdsecurity/crowdsec/pkg/csconfig" + "github.com/crowdsecurity/crowdsec/pkg/cstest" + "github.com/crowdsecurity/crowdsec/pkg/models" ) var testPath string -func setPluginPermTo744() { - setPluginPermTo("744") +func setPluginPermTo744(t *testing.T) { + setPluginPermTo(t, "744") } -func setPluginPermTo722() { - setPluginPermTo("722") +func setPluginPermTo722(t *testing.T) { + setPluginPermTo(t, "722") } -func setPluginPermTo724() { - setPluginPermTo("724") +func setPluginPermTo724(t *testing.T) { + setPluginPermTo(t, "724") } func TestGetPluginNameAndTypeFromPath(t *testing.T) { - setUp() - defer tearDown() + setUp(t) + defer tearDown(t) type args struct { path string } @@ -47,7 +48,7 @@ func TestGetPluginNameAndTypeFromPath(t *testing.T) { args args want string want1 string - wantErr bool + expectedErr string }{ { name: "valid plugin name, single dash", @@ -56,16 +57,13 @@ func TestGetPluginNameAndTypeFromPath(t *testing.T) { }, want: "notification", want1: "gitter", - wantErr: false, }, { name: "invalid plugin name", args: args{ path: "./tests/gitter", }, - want: "", - want1: "", - wantErr: true, + expectedErr: "plugin name ./tests/gitter is invalid. Name should be like {type-name}", }, { name: "valid plugin name, multiple dash", @@ -74,30 +72,23 @@ func TestGetPluginNameAndTypeFromPath(t *testing.T) { }, want: "notification-instant", want1: "slack", - wantErr: false, }, } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - got, got1, err := getPluginTypeAndSubtypeFromPath(tt.args.path) - if (err != nil) != tt.wantErr { - t.Errorf("getPluginNameAndTypeFromPath() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("getPluginNameAndTypeFromPath() got = %v, want %v", got, tt.want) - } - if got1 != tt.want1 { - t.Errorf("getPluginNameAndTypeFromPath() got1 = %v, want %v", got1, tt.want1) - } + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + got, got1, err := getPluginTypeAndSubtypeFromPath(tc.args.path) + cstest.RequireErrorContains(t, err, tc.expectedErr) + + assert.Equal(t, tc.want, got) + assert.Equal(t, tc.want1, got1) }) } } func TestListFilesAtPath(t *testing.T) { - setUp() - defer tearDown() + setUp(t) + defer tearDown(t) type args struct { path string } @@ -105,7 +96,7 @@ func TestListFilesAtPath(t *testing.T) { name string args args want []string - wantErr bool + expectedErr string }{ { name: "valid directory", @@ -122,19 +113,17 @@ func TestListFilesAtPath(t *testing.T) { args: args{ path: "./foo/bar/", }, - wantErr: true, + expectedErr: "open ./foo/bar/: " + cstest.FileNotFoundMessage, }, } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - got, err := listFilesAtPath(tt.args.path) - if (err != nil) != tt.wantErr { - t.Errorf("listFilesAtPath() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("listFilesAtPath() = %v, want %v", got, tt.want) + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + got, err := listFilesAtPath(tc.args.path) + cstest.RequireErrorContains(t, err, tc.expectedErr) + + if !reflect.DeepEqual(got, tc.want) { + t.Errorf("listFilesAtPath() = %v, want %v", got, tc.want) } }) } @@ -147,49 +136,40 @@ func TestBrokerInit(t *testing.T) { tests := []struct { name string - action func() - errContains string - wantErr bool + action func(*testing.T) procCfg csconfig.PluginCfg + expectedErr string }{ { - name: "valid config", - action: setPluginPermTo744, - wantErr: false, + name: "valid config", + action: setPluginPermTo744, }, { name: "group writable binary", - wantErr: true, - errContains: "notification-dummy is world writable", + expectedErr: "notification-dummy is world writable", action: setPluginPermTo722, }, { name: "group writable binary", - wantErr: true, - errContains: "notification-dummy is group writable", + expectedErr: "notification-dummy is group writable", action: setPluginPermTo724, }, { name: "no plugin dir", - wantErr: true, - errContains: "no such file or directory", + expectedErr: cstest.FileNotFoundMessage, action: tearDown, }, { name: "no plugin binary", - wantErr: true, - errContains: "binary for plugin dummy_default not found", - action: func() { + expectedErr: "binary for plugin dummy_default not found", + action: func(t *testing.T) { err := os.Remove(path.Join(testPath, "notification-dummy")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) }, }, { name: "only specify user", - wantErr: true, - errContains: "both plugin user and group must be set", + expectedErr: "both plugin user and group must be set", procCfg: csconfig.PluginCfg{ User: "123445555551122toto", }, @@ -197,8 +177,7 @@ func TestBrokerInit(t *testing.T) { }, { name: "only specify group", - wantErr: true, - errContains: "both plugin user and group must be set", + expectedErr: "both plugin user and group must be set", procCfg: csconfig.PluginCfg{ Group: "123445555551122toto", }, @@ -206,8 +185,7 @@ func TestBrokerInit(t *testing.T) { }, { name: "Fails to run as root", - wantErr: true, - errContains: "operation not permitted", + expectedErr: "operation not permitted", procCfg: csconfig.PluginCfg{ User: "root", Group: "root", @@ -216,8 +194,7 @@ func TestBrokerInit(t *testing.T) { }, { name: "Invalid user and group", - wantErr: true, - errContains: "unknown user toto1234", + expectedErr: "unknown user toto1234", procCfg: csconfig.PluginCfg{ User: "toto1234", Group: "toto1234", @@ -226,8 +203,7 @@ func TestBrokerInit(t *testing.T) { }, { name: "Valid user and invalid group", - wantErr: true, - errContains: "unknown group toto1234", + expectedErr: "unknown group toto1234", procCfg: csconfig.PluginCfg{ User: "nobody", Group: "toto1234", @@ -236,30 +212,25 @@ func TestBrokerInit(t *testing.T) { }, } - for _, test := range tests { - test := test - t.Run(test.name, func(t *testing.T) { - defer tearDown() - buildDummyPlugin() - if test.action != nil { - test.action() + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + defer tearDown(t) + buildDummyPlugin(t) + if tc.action != nil { + tc.action(t) } pb := PluginBroker{} profiles := csconfig.NewDefaultConfig().API.Server.Profiles profiles = append(profiles, &csconfig.ProfileCfg{ Notifications: []string{"dummy_default"}, }) - err := pb.Init(&test.procCfg, profiles, &csconfig.ConfigurationPaths{ + err := pb.Init(&tc.procCfg, profiles, &csconfig.ConfigurationPaths{ PluginDir: testPath, NotificationDir: "./tests/notifications", }) defer pb.Kill() - if test.wantErr { - assert.ErrorContains(t, err, test.errContains) - } else { - assert.NoError(t, err) - } - + cstest.RequireErrorContains(t, err, tc.expectedErr) }) } } @@ -267,91 +238,95 @@ func TestBrokerInit(t *testing.T) { func readconfig(t *testing.T, path string) ([]byte, PluginConfig) { var config PluginConfig orig, err := os.ReadFile("tests/notifications/dummy.yaml") - if err != nil { - t.Fatalf("unable to read config file %s : %s", path, err) - } - if err := yaml.Unmarshal(orig, &config); err != nil { - t.Fatalf("unable to unmarshal config file : %s", err) - } + require.NoError(t, err,"unable to read config file %s", path) + + err = yaml.Unmarshal(orig, &config) + require.NoError(t, err,"unable to unmarshal config file") + return orig, config } func writeconfig(t *testing.T, config PluginConfig, path string) { data, err := yaml.Marshal(&config) - if err != nil { - t.Fatalf("unable to marshal config file : %s", err) - } - if err := os.WriteFile(path, data, 0644); err != nil { - t.Fatalf("unable to write config file %s : %s", path, err) - } + require.NoError(t, err,"unable to marshal config file") + + err = os.WriteFile(path, data, 0644) + require.NoError(t, err,"unable to write config file %s", path) } func TestBrokerNoThreshold(t *testing.T) { var alerts []models.Alert DefaultEmptyTicker = 50 * time.Millisecond - buildDummyPlugin() - setPluginPermTo744() - defer tearDown() - //init + buildDummyPlugin(t) + setPluginPermTo744(t) + defer tearDown(t) + + // init pluginCfg := csconfig.PluginCfg{} pb := PluginBroker{} profiles := csconfig.NewDefaultConfig().API.Server.Profiles profiles = append(profiles, &csconfig.ProfileCfg{ Notifications: []string{"dummy_default"}, }) - //default config + + // default config err := pb.Init(&pluginCfg, profiles, &csconfig.ConfigurationPaths{ PluginDir: testPath, NotificationDir: "./tests/notifications", }) + assert.NoError(t, err) tomb := tomb.Tomb{} + go pb.Run(&tomb) defer pb.Kill() - //send one item, it should be processed right now + + // send one item, it should be processed right now pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} time.Sleep(200 * time.Millisecond) - //we expect one now + + // we expect one now content, err := os.ReadFile("./out") - if err != nil { - log.Errorf("Error reading file: %s", err) - } + require.NoError(t, err, "Error reading file") + err = json.Unmarshal(content, &alerts) assert.NoError(t, err) - assert.Equal(t, 1, len(alerts)) - //remove it + assert.Len(t, alerts, 1) + + // remove it os.Remove("./out") - //and another one + + // and another one log.Printf("second send") pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} time.Sleep(200 * time.Millisecond) - //we expect one again, as we cleaned the file + + // we expect one again, as we cleaned the file content, err = os.ReadFile("./out") - if err != nil { - log.Errorf("Error reading file: %s", err) - } + require.NoError(t, err, "Error reading file") + err = json.Unmarshal(content, &alerts) log.Printf("content-> %s", content) assert.NoError(t, err) - assert.Equal(t, 1, len(alerts)) + assert.Len(t, alerts, 1) } func TestBrokerRunGroupAndTimeThreshold_TimeFirst(t *testing.T) { - //test grouping by "time" + // test grouping by "time" DefaultEmptyTicker = 50 * time.Millisecond - buildDummyPlugin() - setPluginPermTo744() - defer tearDown() + buildDummyPlugin(t) + setPluginPermTo744(t) + defer tearDown(t) - //init + // init pluginCfg := csconfig.PluginCfg{} pb := PluginBroker{} profiles := csconfig.NewDefaultConfig().API.Server.Profiles profiles = append(profiles, &csconfig.ProfileCfg{ Notifications: []string{"dummy_default"}, }) - //set groupwait and groupthreshold, should honor whichever comes first + // set groupwait and groupthreshold, should honor whichever comes first raw, cfg := readconfig(t, "tests/notifications/dummy.yaml") cfg.GroupThreshold = 4 cfg.GroupWait = 1 * time.Second @@ -362,42 +337,46 @@ func TestBrokerRunGroupAndTimeThreshold_TimeFirst(t *testing.T) { }) assert.NoError(t, err) tomb := tomb.Tomb{} + go pb.Run(&tomb) defer pb.Kill() - //send data + // send data pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} time.Sleep(500 * time.Millisecond) - //because of group threshold, we shouldn't have data yet + // because of group threshold, we shouldn't have data yet assert.NoFileExists(t, "./out") time.Sleep(1 * time.Second) - //after 1 seconds, we should have data + // after 1 seconds, we should have data content, err := os.ReadFile("./out") assert.NoError(t, err) + var alerts []models.Alert err = json.Unmarshal(content, &alerts) assert.NoError(t, err) - assert.Equal(t, 3, len(alerts)) - //restore config - if err := os.WriteFile("tests/notifications/dummy.yaml", raw, 0644); err != nil { - t.Fatalf("unable to write config file %s", err) - } + assert.Len(t, alerts, 3) + + // restore config + err = os.WriteFile("tests/notifications/dummy.yaml", raw, 0644) + require.NoError(t, err,"unable to write config file") } func TestBrokerRunGroupAndTimeThreshold_CountFirst(t *testing.T) { DefaultEmptyTicker = 50 * time.Millisecond - buildDummyPlugin() - setPluginPermTo744() - defer tearDown() - //init + buildDummyPlugin(t) + setPluginPermTo(t, "744") + defer tearDown(t) + + // init pluginCfg := csconfig.PluginCfg{} pb := PluginBroker{} profiles := csconfig.NewDefaultConfig().API.Server.Profiles profiles = append(profiles, &csconfig.ProfileCfg{ Notifications: []string{"dummy_default"}, }) - //set groupwait and groupthreshold, should honor whichever comes first + + // set groupwait and groupthreshold, should honor whichever comes first raw, cfg := readconfig(t, "tests/notifications/dummy.yaml") cfg.GroupThreshold = 4 cfg.GroupWait = 4 * time.Second @@ -408,46 +387,51 @@ func TestBrokerRunGroupAndTimeThreshold_CountFirst(t *testing.T) { }) assert.NoError(t, err) tomb := tomb.Tomb{} + go pb.Run(&tomb) defer pb.Kill() - //send data + + // send data pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} time.Sleep(100 * time.Millisecond) - //because of group threshold, we shouldn't have data yet + + // because of group threshold, we shouldn't have data yet assert.NoFileExists(t, "./out") pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} time.Sleep(100 * time.Millisecond) - //and now we should + + // and now we should content, err := os.ReadFile("./out") - if err != nil { - log.Errorf("Error reading file: %s", err) - } + require.NoError(t, err, "Error reading file") + var alerts []models.Alert err = json.Unmarshal(content, &alerts) assert.NoError(t, err) - assert.Equal(t, 4, len(alerts)) - //restore config - if err := os.WriteFile("tests/notifications/dummy.yaml", raw, 0644); err != nil { - t.Fatalf("unable to write config file %s", err) - } + assert.Len(t, alerts, 4) + + // restore config + err = os.WriteFile("tests/notifications/dummy.yaml", raw, 0644) + require.NoError(t, err,"unable to write config file") } func TestBrokerRunGroupThreshold(t *testing.T) { - //test grouping by "size" + // test grouping by "size" DefaultEmptyTicker = 50 * time.Millisecond - buildDummyPlugin() - setPluginPermTo744() - defer tearDown() - //init + buildDummyPlugin(t) + setPluginPermTo(t, "744") + defer tearDown(t) + + // init pluginCfg := csconfig.PluginCfg{} pb := PluginBroker{} profiles := csconfig.NewDefaultConfig().API.Server.Profiles profiles = append(profiles, &csconfig.ProfileCfg{ Notifications: []string{"dummy_default"}, }) - //set groupwait + + // set groupwait raw, cfg := readconfig(t, "tests/notifications/dummy.yaml") cfg.GroupThreshold = 4 writeconfig(t, cfg, "tests/notifications/dummy.yaml") @@ -455,49 +439,55 @@ func TestBrokerRunGroupThreshold(t *testing.T) { PluginDir: testPath, NotificationDir: "./tests/notifications", }) + assert.NoError(t, err) tomb := tomb.Tomb{} + go pb.Run(&tomb) defer pb.Kill() - //send data + + // send data pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} time.Sleep(100 * time.Millisecond) - //because of group threshold, we shouldn't have data yet + + // because of group threshold, we shouldn't have data yet assert.NoFileExists(t, "./out") pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} time.Sleep(100 * time.Millisecond) - //and now we should + + // and now we should content, err := os.ReadFile("./out") - if err != nil { - log.Errorf("Error reading file: %s", err) - } + require.NoError(t, err, "Error reading file") + var alerts []models.Alert err = json.Unmarshal(content, &alerts) assert.NoError(t, err) - assert.Equal(t, 4, len(alerts)) - //restore config - if err := os.WriteFile("tests/notifications/dummy.yaml", raw, 0644); err != nil { - t.Fatalf("unable to write config file %s", err) - } + assert.Len(t, alerts, 4) + + // restore config + err = os.WriteFile("tests/notifications/dummy.yaml", raw, 0644) + require.NoError(t, err, "unable to write config file") } func TestBrokerRunTimeThreshold(t *testing.T) { DefaultEmptyTicker = 50 * time.Millisecond - buildDummyPlugin() - setPluginPermTo744() - defer tearDown() - //init + buildDummyPlugin(t) + setPluginPermTo(t, "744") + defer tearDown(t) + + // init pluginCfg := csconfig.PluginCfg{} pb := PluginBroker{} profiles := csconfig.NewDefaultConfig().API.Server.Profiles profiles = append(profiles, &csconfig.ProfileCfg{ Notifications: []string{"dummy_default"}, }) - //set groupwait + + // set groupwait raw, cfg := readconfig(t, "tests/notifications/dummy.yaml") - cfg.GroupWait = time.Duration(1 * time.Second) //nolint:unconvert + cfg.GroupWait = 1 * time.Second writeconfig(t, cfg, "tests/notifications/dummy.yaml") err := pb.Init(&pluginCfg, profiles, &csconfig.ConfigurationPaths{ PluginDir: testPath, @@ -505,34 +495,37 @@ func TestBrokerRunTimeThreshold(t *testing.T) { }) assert.NoError(t, err) tomb := tomb.Tomb{} + go pb.Run(&tomb) defer pb.Kill() - //send data + + // send data pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} time.Sleep(200 * time.Millisecond) - //we shouldn't have data yet + + // we shouldn't have data yet assert.NoFileExists(t, "./out") time.Sleep(1 * time.Second) - //and now we should + + // and now we should content, err := os.ReadFile("./out") - if err != nil { - log.Errorf("Error reading file: %s", err) - } + require.NoError(t, err, "Error reading file") + var alerts []models.Alert err = json.Unmarshal(content, &alerts) assert.NoError(t, err) - assert.Equal(t, 1, len(alerts)) - //restore config - if err := os.WriteFile("tests/notifications/dummy.yaml", raw, 0644); err != nil { - t.Fatalf("unable to write config file %s", err) - } + assert.Len(t, alerts, 1) + + // restore config + err = os.WriteFile("tests/notifications/dummy.yaml", raw, 0644) + require.NoError(t, err, "unable to write config file %s", err) } func TestBrokerRunSimple(t *testing.T) { DefaultEmptyTicker = 50 * time.Millisecond - buildDummyPlugin() - setPluginPermTo744() - defer tearDown() + buildDummyPlugin(t) + setPluginPermTo(t, "744") + defer tearDown(t) pluginCfg := csconfig.PluginCfg{} pb := PluginBroker{} profiles := csconfig.NewDefaultConfig().API.Server.Profiles @@ -545,10 +538,12 @@ func TestBrokerRunSimple(t *testing.T) { }) assert.NoError(t, err) tomb := tomb.Tomb{} + go pb.Run(&tomb) defer pb.Kill() assert.NoFileExists(t, "./out") + defer os.Remove("./out") pb.PluginChannel <- ProfileAlert{ProfileID: uint(0), Alert: &models.Alert{}} @@ -556,62 +551,54 @@ func TestBrokerRunSimple(t *testing.T) { time.Sleep(time.Millisecond * 200) content, err := os.ReadFile("./out") - if err != nil { - log.Errorf("Error reading file: %s", err) - } + require.NoError(t, err, "Error reading file") + var alerts []models.Alert err = json.Unmarshal(content, &alerts) assert.NoError(t, err) - assert.Equal(t, 2, len(alerts)) + assert.Len(t, alerts, 2) } -func buildDummyPlugin() { +func buildDummyPlugin(t *testing.T) { dir, err := os.MkdirTemp("./tests", "cs_plugin_test") - if err != nil { - log.Fatal(err) - } + require.NoError(t, err) + cmd := exec.Command("go", "build", "-o", path.Join(dir, "notification-dummy"), "../../plugins/notifications/dummy/") - if err := cmd.Run(); err != nil { - log.Fatal(err) - } + err = cmd.Run() + require.NoError(t, err, "while building dummy plugin") + testPath = dir os.Remove("./out") } -func setPluginPermTo(perm string) { +func setPluginPermTo(t *testing.T, perm string) { if runtime.GOOS != "windows" { - if err := exec.Command("chmod", perm, path.Join(testPath, "notification-dummy")).Run(); err != nil { - log.Fatal(errors.Wrapf(err, "chmod 744 %s", path.Join(testPath, "notification-dummy"))) - } + err := exec.Command("chmod", perm, path.Join(testPath, "notification-dummy")).Run() + require.NoError(t, err, "chmod 744 %s", path.Join(testPath, "notification-dummy")) } } -func setUp() { +func setUp(t *testing.T) { dir, err := os.MkdirTemp("./", "cs_plugin_test") - if err != nil { - log.Fatal(err) - } + require.NoError(t, err) + f, err := os.Create(path.Join(dir, "slack")) - if err != nil { - log.Fatal(err) - } + require.NoError(t, err) + f.Close() f, err = os.Create(path.Join(dir, "notification-gitter")) - if err != nil { - log.Fatal(err) - } + require.NoError(t, err) + f.Close() err = os.Mkdir(path.Join(dir, "dummy_dir"), 0666) - if err != nil { - log.Fatal(err) - } + require.NoError(t, err) + testPath = dir } -func tearDown() { +func tearDown(t *testing.T) { err := os.RemoveAll(testPath) - if err != nil { - log.Fatal(err) - } + require.NoError(t, err) + os.Remove("./out") } diff --git a/pkg/csplugin/broker_win_test.go b/pkg/csplugin/broker_win_test.go index 9caf78d27..2595db3f3 100644 --- a/pkg/csplugin/broker_win_test.go +++ b/pkg/csplugin/broker_win_test.go @@ -12,11 +12,13 @@ import ( "testing" "time" - "github.com/crowdsecurity/crowdsec/pkg/csconfig" - "github.com/crowdsecurity/crowdsec/pkg/models" - "github.com/crowdsecurity/crowdsec/pkg/types" "github.com/stretchr/testify/assert" "gopkg.in/tomb.v2" + + "github.com/crowdsecurity/crowdsec/pkg/csconfig" + "github.com/crowdsecurity/crowdsec/pkg/cstest" + "github.com/crowdsecurity/crowdsec/pkg/models" + "github.com/crowdsecurity/crowdsec/pkg/types" ) /* @@ -145,7 +147,7 @@ func TestBrokerInit(t *testing.T) { { name: "no plugin dir", wantErr: true, - errContains: "The system cannot find the file specified.", + errContains: cstest.FileNotFoundMessage, action: tearDown, }, { diff --git a/pkg/cstest/filenotfound_unix.go b/pkg/cstest/filenotfound_unix.go new file mode 100644 index 000000000..a5a426dd8 --- /dev/null +++ b/pkg/cstest/filenotfound_unix.go @@ -0,0 +1,5 @@ +//go:build unix + +package cstest + +const FileNotFoundMessage = "no such file or directory" diff --git a/pkg/cstest/filenotfound_windows.go b/pkg/cstest/filenotfound_windows.go new file mode 100644 index 000000000..31816c014 --- /dev/null +++ b/pkg/cstest/filenotfound_windows.go @@ -0,0 +1,5 @@ +//go:build windows + +package cstest + +const FileNotFoundMessage = "The system cannot find the file specified."