Преглед изворни кода

warn if no acquisition files are found, acquisition_test refactoring, tests (#1816)

mmetc пре 2 година
родитељ
комит
2b7e3ff1e7

+ 1 - 1
cmd/crowdsec/main.go

@@ -153,7 +153,7 @@ func LoadAcquisition(cConfig *csconfig.Config) error {
 	} else {
 		dataSources, err = acquisition.LoadAcquisitionFromFile(cConfig.Crowdsec)
 		if err != nil {
-			return errors.Wrap(err, "while loading acquisition configuration")
+			return err
 		}
 	}
 

+ 1 - 0
config/config.yaml

@@ -18,6 +18,7 @@ config_paths:
   plugin_dir: /usr/local/lib/crowdsec/plugins/
 crowdsec_service:
   acquisition_path: /etc/crowdsec/acquis.yaml
+  acquisition_dir: /etc/crowdsec/acquis.d
   parser_routines: 1
 cscli:
   output: human

+ 1 - 1
pkg/acquisition/acquisition.go

@@ -175,7 +175,7 @@ func LoadAcquisitionFromFile(config *csconfig.CrowdsecServiceCfg) ([]DataSource,
 		log.Infof("loading acquisition file : %s", acquisFile)
 		yamlFile, err := os.Open(acquisFile)
 		if err != nil {
-			return nil, errors.Wrapf(err, "can't open %s", acquisFile)
+			return nil, err
 		}
 		dec := yaml.NewDecoder(yamlFile)
 		dec.SetStrict(true)

+ 73 - 79
pkg/acquisition/acquisition_test.go

@@ -9,9 +9,10 @@ import (
 	"github.com/pkg/errors"
 	"github.com/prometheus/client_golang/prometheus"
 	log "github.com/sirupsen/logrus"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	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"
@@ -89,128 +90,123 @@ func TestDataSourceConfigure(t *testing.T) {
 	appendMockSource()
 	tests := []struct {
 		TestName      string
-		RawBytes      []byte
+		String        string
 		ExpectedError string
 	}{
 		{
 			TestName: "basic_valid_config",
-			RawBytes: []byte(`
+			String: `
 mode: cat
 labels:
   test: foobar
 log_level: info
 source: mock
 toto: test_value1
-`),
+`,
 		},
 		{
 			TestName: "basic_debug_config",
-			RawBytes: []byte(`
+			String: `
 mode: cat
 labels:
   test: foobar
 log_level: debug
 source: mock
 toto: test_value1
-`),
+`,
 		},
 		{
 			TestName: "basic_tailmode_config",
-			RawBytes: []byte(`
+			String: `
 mode: tail
 labels:
   test: foobar
 log_level: debug
 source: mock
 toto: test_value1
-`),
+`,
 		},
 		{
 			TestName: "bad_mode_config",
-			RawBytes: []byte(`
+			String: `
 mode: ratata
 labels:
   test: foobar
 log_level: debug
 source: mock
 toto: test_value1
-`),
+`,
 			ExpectedError: "failed to configure datasource mock: mode ratata is not supported",
 		},
 		{
 			TestName: "bad_type_config",
-			RawBytes: []byte(`
+			String: `
 mode: cat
 labels:
   test: foobar
 log_level: debug
 source: tutu
-`),
+`,
 			ExpectedError: "cannot find source tutu",
 		},
 		{
 			TestName: "mismatch_config",
-			RawBytes: []byte(`
+			String: `
 mode: cat
 labels:
   test: foobar
 log_level: debug
 source: mock
 wowo: ajsajasjas
-`),
+`,
 			ExpectedError: "field wowo not found in type acquisition.MockSource",
 		},
 		{
 			TestName: "cant_run_error",
-			RawBytes: []byte(`
+			String: `
 mode: cat
 labels:
   test: foobar
 log_level: debug
 source: mock_cant_run
 wowo: ajsajasjas
-`),
+`,
 			ExpectedError: "datasource mock_cant_run cannot be run: can't run bro",
 		},
 	}
 
-	for _, test := range tests {
-		common := configuration.DataSourceCommonCfg{}
-		yaml.Unmarshal(test.RawBytes, &common)
-		ds, err := DataSourceConfigure(common)
-		if test.ExpectedError != "" {
-			if err == nil {
-				t.Fatalf("expected error %s, got none", test.ExpectedError)
+	for _, tc := range tests {
+		tc := tc
+		t.Run(tc.TestName, func(t *testing.T) {
+			common := configuration.DataSourceCommonCfg{}
+			yaml.Unmarshal([]byte(tc.String), &common)
+			ds, err := DataSourceConfigure(common)
+			cstest.RequireErrorContains(t, err, tc.ExpectedError)
+			if tc.ExpectedError == "" {
+				return
 			}
-			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)
-		}
 
-		switch test.TestName {
-		case "basic_valid_config":
-			mock := (*ds).Dump().(*MockSource)
-			assert.Equal(t, mock.Toto, "test_value1")
-			assert.Equal(t, mock.Mode, "cat")
-			assert.Equal(t, mock.logger.Logger.Level, log.InfoLevel)
-			assert.DeepEqual(t, mock.Labels, map[string]string{"test": "foobar"})
-		case "basic_debug_config":
-			mock := (*ds).Dump().(*MockSource)
-			assert.Equal(t, mock.Toto, "test_value1")
-			assert.Equal(t, mock.Mode, "cat")
-			assert.Equal(t, mock.logger.Logger.Level, log.DebugLevel)
-			assert.DeepEqual(t, mock.Labels, map[string]string{"test": "foobar"})
-		case "basic_tailmode_config":
-			mock := (*ds).Dump().(*MockSource)
-			assert.Equal(t, mock.Toto, "test_value1")
-			assert.Equal(t, mock.Mode, "tail")
-			assert.Equal(t, mock.logger.Logger.Level, log.DebugLevel)
-			assert.DeepEqual(t, mock.Labels, map[string]string{"test": "foobar"})
-		}
+			switch tc.TestName {
+			case "basic_valid_config":
+				mock := (*ds).Dump().(*MockSource)
+				assert.Equal(t, mock.Toto, "test_value1")
+				assert.Equal(t, mock.Mode, "cat")
+				assert.Equal(t, mock.logger.Logger.Level, log.InfoLevel)
+				assert.Equal(t, mock.Labels, map[string]string{"test": "foobar"})
+			case "basic_debug_config":
+				mock := (*ds).Dump().(*MockSource)
+				assert.Equal(t, mock.Toto, "test_value1")
+				assert.Equal(t, mock.Mode, "cat")
+				assert.Equal(t, mock.logger.Logger.Level, log.DebugLevel)
+				assert.Equal(t, mock.Labels, map[string]string{"test": "foobar"})
+			case "basic_tailmode_config":
+				mock := (*ds).Dump().(*MockSource)
+				assert.Equal(t, mock.Toto, "test_value1")
+				assert.Equal(t, mock.Mode, "tail")
+				assert.Equal(t, mock.logger.Logger.Level, log.DebugLevel)
+				assert.Equal(t, mock.Labels, map[string]string{"test": "foobar"})
+			}
+		})
 	}
 }
 
@@ -227,7 +223,7 @@ func TestLoadAcquisitionFromFile(t *testing.T) {
 			Config: csconfig.CrowdsecServiceCfg{
 				AcquisitionFiles: []string{"does_not_exist"},
 			},
-			ExpectedError: cstest.FileNotFoundMessage,
+			ExpectedError: "open does_not_exist: " + cstest.FileNotFoundMessage,
 			ExpectedLen:   0,
 		},
 		{
@@ -281,13 +277,17 @@ func TestLoadAcquisitionFromFile(t *testing.T) {
 			ExpectedError: "while configuring datasource of type file from test_files/bad_filetype.yaml",
 		},
 	}
-	for _, test := range tests {
-		dss, err := LoadAcquisitionFromFile(&test.Config)
-		cstest.RequireErrorContains(t, err, test.ExpectedError)
+	for _, tc := range tests {
+		tc := tc
+		t.Run(tc.TestName, func(t *testing.T) {
+			dss, err := LoadAcquisitionFromFile(&tc.Config)
+			cstest.RequireErrorContains(t, err, tc.ExpectedError)
+			if tc.ExpectedError != "" {
+				return
+			}
 
-		if len(dss) != test.ExpectedLen {
-			t.Fatalf("%s : expected %d datasources got %d", test.TestName, test.ExpectedLen, len(dss))
-		}
+			assert.Len(t, dss, tc.ExpectedLen)
+		})
 
 	}
 }
@@ -398,9 +398,8 @@ READLOOP:
 			break READLOOP
 		}
 	}
-	if count != 10 {
-		t.Fatalf("expected 10 results, got %d", count)
-	}
+
+	assert.Equal(t, 10, count)
 }
 
 func TestStartAcquisitionTail(t *testing.T) {
@@ -426,14 +425,12 @@ READLOOP:
 			break READLOOP
 		}
 	}
-	if count != 10 {
-		t.Fatalf("expected 10 results, got %d", count)
-	}
+
+	assert.Equal(t, 10, count)
+
 	acquisTomb.Kill(nil)
 	time.Sleep(1 * time.Second)
-	if acquisTomb.Err() != nil {
-		t.Fatalf("unexpected tomb error %s (should be dead)", acquisTomb.Err())
-	}
+	require.NoError(t, acquisTomb.Err(), "tomb is not dead")
 }
 
 type MockTailError struct {
@@ -473,14 +470,10 @@ READLOOP:
 			break READLOOP
 		}
 	}
-	if count != 10 {
-		t.Fatalf("expected 10 results, got %d", count)
-	}
+	assert.Equal(t, 10, count)
 	//acquisTomb.Kill(nil)
 	time.Sleep(1 * time.Second)
-	if acquisTomb.Err().Error() != "got error (tomb)" {
-		t.Fatalf("didn't got expected error, got '%s'", acquisTomb.Err().Error())
-	}
+	cstest.RequireErrorContains(t, acquisTomb.Err(), "got error (tomb)")
 }
 
 type MockSourceByDSN struct {
@@ -541,12 +534,13 @@ func TestConfigureByDSN(t *testing.T) {
 		AcquisitionSources = append(AcquisitionSources, mock)
 	}
 
-	for _, test := range tests {
-		srcs, err := LoadAcquisitionFromDSN(test.dsn, map[string]string{"type": "test_label"})
-		cstest.AssertErrorContains(t, err, test.ExpectedError)
+	for _, tc := range tests {
+		tc := tc
+		t.Run(tc.dsn, func(t *testing.T) {
+			srcs, err := LoadAcquisitionFromDSN(tc.dsn, map[string]string{"type": "test_label"})
+			cstest.RequireErrorContains(t, err, tc.ExpectedError)
 
-		if len(srcs) != test.ExpectedResLen {
-			t.Fatalf("expected %d results, got %d", test.ExpectedResLen, len(srcs))
-		}
+			assert.Len(t, srcs, tc.ExpectedResLen)
+		})
 	}
 }

+ 35 - 13
pkg/csconfig/crowdsec_service.go

@@ -5,12 +5,13 @@ import (
 	"os"
 	"path/filepath"
 
-	"github.com/crowdsecurity/crowdsec/pkg/types"
 	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
+
+	"github.com/crowdsecurity/crowdsec/pkg/types"
 )
 
-/*Configurations needed for crowdsec to load parser/scenarios/... + acquisition*/
+// CrowdsecServiceCfg contains the location of parsers/scenarios/... and acquisition files
 type CrowdsecServiceCfg struct {
 	Enable              *bool  `yaml:"enable"`
 	AcquisitionFilePath string `yaml:"acquisition_path,omitempty"`
@@ -21,10 +22,10 @@ type CrowdsecServiceCfg struct {
 	BucketsRoutinesCount int               `yaml:"buckets_routines"`
 	OutputRoutinesCount  int               `yaml:"output_routines"`
 	SimulationConfig     *SimulationConfig `yaml:"-"`
-	LintOnly             bool              `yaml:"-"`                          //if set to true, exit after loading configs
-	BucketStateFile      string            `yaml:"state_input_file,omitempty"` //if we need to unserialize buckets at start
-	BucketStateDumpDir   string            `yaml:"state_output_dir,omitempty"` //if we need to unserialize buckets on shutdown
-	BucketsGCEnabled     bool              `yaml:"-"`                          //we need to garbage collect buckets when in forensic mode
+	LintOnly             bool              `yaml:"-"`                          // if set to true, exit after loading configs
+	BucketStateFile      string            `yaml:"state_input_file,omitempty"` // if we need to unserialize buckets at start
+	BucketStateDumpDir   string            `yaml:"state_output_dir,omitempty"` // if we need to unserialize buckets on shutdown
+	BucketsGCEnabled     bool              `yaml:"-"`                          // we need to garbage collect buckets when in forensic mode
 
 	HubDir             string `yaml:"-"`
 	DataDir            string `yaml:"-"`
@@ -35,8 +36,9 @@ type CrowdsecServiceCfg struct {
 
 func (c *Config) LoadCrowdsec() error {
 	var err error
+
 	// Configuration paths are dependency to load crowdsec configuration
-	if err := c.LoadConfigurationPaths(); err != nil {
+	if err = c.LoadConfigurationPaths(); err != nil {
 		return err
 	}
 
@@ -57,19 +59,27 @@ func (c *Config) LoadCrowdsec() error {
 		return nil
 	}
 
+	if c.Crowdsec.AcquisitionFiles == nil {
+		c.Crowdsec.AcquisitionFiles = []string{}
+	}
+
 	if c.Crowdsec.AcquisitionFilePath != "" {
-		log.Debugf("non-empty acquisition file path %s", c.Crowdsec.AcquisitionFilePath)
-		if _, err := os.Stat(c.Crowdsec.AcquisitionFilePath); err != nil {
-			return errors.Wrapf(err, "while checking acquisition path %s", c.Crowdsec.AcquisitionFilePath)
+		log.Debugf("non-empty acquisition_path %s", c.Crowdsec.AcquisitionFilePath)
+		if _, err = os.Stat(c.Crowdsec.AcquisitionFilePath); err != nil {
+			return fmt.Errorf("while checking acquisition_path: %w", err)
 		}
 		c.Crowdsec.AcquisitionFiles = append(c.Crowdsec.AcquisitionFiles, c.Crowdsec.AcquisitionFilePath)
 	}
+
 	if c.Crowdsec.AcquisitionDirPath != "" {
 		c.Crowdsec.AcquisitionDirPath, err = filepath.Abs(c.Crowdsec.AcquisitionDirPath)
 		if err != nil {
 			return errors.Wrapf(err, "can't get absolute path of '%s'", c.Crowdsec.AcquisitionDirPath)
 		}
-		files, err := filepath.Glob(c.Crowdsec.AcquisitionDirPath + "/*.yaml")
+
+		var files []string
+
+		files, err = filepath.Glob(c.Crowdsec.AcquisitionDirPath + "/*.yaml")
 		if err != nil {
 			return errors.Wrap(err, "while globbing acquis_dir")
 		}
@@ -81,10 +91,16 @@ func (c *Config) LoadCrowdsec() error {
 		}
 		c.Crowdsec.AcquisitionFiles = append(c.Crowdsec.AcquisitionFiles, files...)
 	}
+
 	if c.Crowdsec.AcquisitionDirPath == "" && c.Crowdsec.AcquisitionFilePath == "" {
-		log.Warning("no acquisition_path nor acquisition_dir")
+		log.Warning("no acquisition_path or acquisition_dir specified")
+	}
+
+	if len(c.Crowdsec.AcquisitionFiles) == 0 {
+		log.Warning("no acquisition file found")
 	}
-	if err := c.LoadSimulation(); err != nil {
+
+	if err = c.LoadSimulation(); err != nil {
 		return errors.Wrap(err, "load error (simulation)")
 	}
 
@@ -92,6 +108,7 @@ func (c *Config) LoadCrowdsec() error {
 	c.Crowdsec.DataDir = c.ConfigPaths.DataDir
 	c.Crowdsec.HubDir = c.ConfigPaths.HubDir
 	c.Crowdsec.HubIndexFile = c.ConfigPaths.HubIndexFile
+
 	if c.Crowdsec.ParserRoutinesCount <= 0 {
 		c.Crowdsec.ParserRoutinesCount = 1
 	}
@@ -107,6 +124,7 @@ func (c *Config) LoadCrowdsec() error {
 	var crowdsecCleanup = []*string{
 		&c.Crowdsec.AcquisitionFilePath,
 	}
+
 	for _, k := range crowdsecCleanup {
 		if *k == "" {
 			continue
@@ -116,6 +134,8 @@ func (c *Config) LoadCrowdsec() error {
 			return errors.Wrapf(err, "failed to get absolute path of '%s'", *k)
 		}
 	}
+
+	// Convert relative paths to absolute paths
 	for i, file := range c.Crowdsec.AcquisitionFiles {
 		f, err := filepath.Abs(file)
 		if err != nil {
@@ -127,8 +147,10 @@ func (c *Config) LoadCrowdsec() error {
 	if err := c.LoadAPIClient(); err != nil {
 		return fmt.Errorf("loading api client: %s", err)
 	}
+
 	if err := c.LoadHub(); err != nil {
 		return errors.Wrap(err, "while loading hub")
 	}
+
 	return nil
 }

+ 34 - 56
pkg/csconfig/crowdsec_service_test.go

@@ -3,59 +3,45 @@ package csconfig
 import (
 	"fmt"
 	"path/filepath"
-	"strings"
 	"testing"
 
+	"github.com/crowdsecurity/crowdsec/pkg/cstest"
 	"github.com/crowdsecurity/crowdsec/pkg/types"
-	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestLoadCrowdsec(t *testing.T) {
 	falseBoolPtr := false
 	acquisFullPath, err := filepath.Abs("./tests/acquis.yaml")
-	if err != nil {
-		t.Fatalf(err.Error())
-	}
+	require.NoError(t, err)
 
 	acquisInDirFullPath, err := filepath.Abs("./tests/acquis/acquis.yaml")
-	if err != nil {
-		t.Fatalf(err.Error())
-	}
+	require.NoError(t, err)
 
 	acquisDirFullPath, err := filepath.Abs("./tests/acquis")
-	if err != nil {
-		t.Fatalf(err.Error())
-	}
+	require.NoError(t, err)
 
 	hubFullPath, err := filepath.Abs("./hub")
-	if err != nil {
-		t.Fatalf(err.Error())
-	}
+	require.NoError(t, err)
 
 	dataFullPath, err := filepath.Abs("./data")
-	if err != nil {
-		t.Fatalf(err.Error())
-	}
+	require.NoError(t, err)
 
 	configDirFullPath, err := filepath.Abs("./tests")
-	if err != nil {
-		t.Fatalf(err.Error())
-	}
+	require.NoError(t, err)
 
 	hubIndexFileFullPath, err := filepath.Abs("./hub/.index.json")
-	if err != nil {
-		t.Fatalf(err.Error())
-	}
+	require.NoError(t, err)
 
 	tests := []struct {
 		name           string
-		Input          *Config
+		input          *Config
 		expectedResult *CrowdsecServiceCfg
-		err            string
+		expectedErr    string
 	}{
 		{
 			name: "basic valid configuration",
-			Input: &Config{
+			input: &Config{
 				ConfigPaths: &ConfigurationPaths{
 					ConfigDir: "./tests",
 					DataDir:   "./data",
@@ -91,7 +77,7 @@ func TestLoadCrowdsec(t *testing.T) {
 		},
 		{
 			name: "basic valid configuration with acquisition dir",
-			Input: &Config{
+			input: &Config{
 				ConfigPaths: &ConfigurationPaths{
 					ConfigDir: "./tests",
 					DataDir:   "./data",
@@ -128,7 +114,7 @@ func TestLoadCrowdsec(t *testing.T) {
 		},
 		{
 			name: "no acquisition file and dir",
-			Input: &Config{
+			input: &Config{
 				ConfigPaths: &ConfigurationPaths{
 					ConfigDir: "./tests",
 					DataDir:   "./data",
@@ -143,13 +129,17 @@ func TestLoadCrowdsec(t *testing.T) {
 			},
 			expectedResult: &CrowdsecServiceCfg{
 				Enable:               types.BoolPtr(true),
-				BucketsRoutinesCount: 1,
-				ParserRoutinesCount:  1,
-				OutputRoutinesCount:  1,
+				AcquisitionDirPath:   "",
+				AcquisitionFilePath:  "",
 				ConfigDir:            configDirFullPath,
 				HubIndexFile:         hubIndexFileFullPath,
 				DataDir:              dataFullPath,
 				HubDir:               hubFullPath,
+				BucketsRoutinesCount: 1,
+				ParserRoutinesCount:  1,
+				OutputRoutinesCount:  1,
+				AcquisitionFiles:     []string{},
+				SimulationFilePath:   "",
 				SimulationConfig: &SimulationConfig{
 					Simulation: &falseBoolPtr,
 				},
@@ -157,7 +147,7 @@ func TestLoadCrowdsec(t *testing.T) {
 		},
 		{
 			name: "non existing acquisition file",
-			Input: &Config{
+			input: &Config{
 				ConfigPaths: &ConfigurationPaths{
 					ConfigDir: "./tests",
 					DataDir:   "./data",
@@ -172,17 +162,11 @@ func TestLoadCrowdsec(t *testing.T) {
 					AcquisitionFilePath: "./tests/acquis_not_exist.yaml",
 				},
 			},
-			expectedResult: &CrowdsecServiceCfg{
-				Enable:               types.BoolPtr(true),
-				AcquisitionFilePath:  "./tests/acquis_not_exist.yaml",
-				BucketsRoutinesCount: 0,
-				ParserRoutinesCount:  0,
-				OutputRoutinesCount:  0,
-			},
+			expectedErr: cstest.FileNotFoundMessage,
 		},
 		{
 			name: "agent disabled",
-			Input: &Config{
+			input: &Config{
 				ConfigPaths: &ConfigurationPaths{
 					ConfigDir: "./tests",
 					DataDir:   "./data",
@@ -193,23 +177,17 @@ func TestLoadCrowdsec(t *testing.T) {
 		},
 	}
 
-	for idx, test := range tests {
-		fmt.Printf("TEST '%s'\n", test.name)
-		err := test.Input.LoadCrowdsec()
-		if err == nil && test.err != "" {
-			t.Fatalf("%d/%d expected error, didn't get it", idx, len(tests))
-		} else if test.err != "" {
-			if !strings.HasPrefix(fmt.Sprintf("%s", err), test.err) {
-				t.Fatalf("%d/%d expected '%s' got '%s'", idx, len(tests),
-					test.err,
-					fmt.Sprintf("%s", err))
+	for _, tc := range tests {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			fmt.Printf("TEST '%s'\n", tc.name)
+			err := tc.input.LoadCrowdsec()
+			cstest.RequireErrorContains(t, err, tc.expectedErr)
+			if tc.expectedErr != "" {
+				return
 			}
-		}
-
-		isOk := assert.Equal(t, test.expectedResult, test.Input.Crowdsec)
-		if !isOk {
-			t.Fatalf("test '%s' failed", test.name)
-		}
 
+			require.Equal(t, tc.expectedResult, tc.input.Crowdsec)
+		})
 	}
 }

+ 48 - 0
tests/bats/01_crowdsec.bats

@@ -129,3 +129,51 @@ teardown() {
     run -0 ./instance-crowdsec stop
 }
 
+@test "crowdsec (error if the acquisition_path file is defined but missing)" {
+    ACQUIS_YAML=$(config_get '.crowdsec_service.acquisition_path')
+    rm -f "$ACQUIS_YAML"
+
+    run -1 --separate-stderr timeout 2s "${CROWDSEC}"
+    assert_stderr_line --partial "acquis.yaml: no such file or directory"
+}
+
+@test "crowdsec (error if acquisition_path is not defined and acquisition_dir is empty)" {
+    ACQUIS_YAML=$(config_get '.crowdsec_service.acquisition_path')
+    rm -f "$ACQUIS_YAML"
+    config_set '.crowdsec_service.acquisition_path=""'
+
+    ACQUIS_DIR=$(config_get '.crowdsec_service.acquisition_dir')
+    rm -f "$ACQUIS_DIR"
+
+    config_set '.common.log_media="stdout"'
+    run -124 --separate-stderr timeout 2s "${CROWDSEC}"
+    # check warning
+    assert_stderr_line --partial "no acquisition file found"
+}
+
+@test "crowdsec (error if acquisition_path and acquisition_dir are not defined)" {
+    ACQUIS_YAML=$(config_get '.crowdsec_service.acquisition_path')
+    rm -f "$ACQUIS_YAML"
+    config_set '.crowdsec_service.acquisition_path=""'
+
+    ACQUIS_DIR=$(config_get '.crowdsec_service.acquisition_dir')
+    rm -f "$ACQUIS_DIR"
+    config_set '.crowdsec_service.acquisition_dir=""'
+
+    config_set '.common.log_media="stdout"'
+    run -124 --separate-stderr timeout 2s "${CROWDSEC}"
+    # check warning
+    assert_stderr_line --partial "no acquisition_path or acquisition_dir specified"
+}
+
+@test "crowdsec (no error if acquisition_path is empty string but acquisition_dir is not empty)" {
+    ACQUIS_YAML=$(config_get '.crowdsec_service.acquisition_path')
+    rm -f "$ACQUIS_YAML"
+    config_set '.crowdsec_service.acquisition_path=""'
+
+    ACQUIS_DIR=$(config_get '.crowdsec_service.acquisition_dir')
+    mkdir -p "$ACQUIS_DIR"
+    touch "$ACQUIS_DIR"/foo.yaml
+
+    run -124 --separate-stderr timeout 2s "${CROWDSEC}"
+}

+ 6 - 3
tests/lib/config/config-local

@@ -38,6 +38,8 @@ DATA_DIR="${LOCAL_DIR}/${REL_DATA_DIR}"
 export DATA_DIR
 CONFIG_DIR="${LOCAL_DIR}/${REL_CONFIG_DIR}"
 export CONFIG_DIR
+HUB_DIR="${CONFIG_DIR}/hub"
+export HUB_DIR
 
 if [[ $(uname) == "OpenBSD" ]]; then
     TAR=gtar
@@ -81,11 +83,12 @@ config_generate() {
     .config_paths.config_dir=strenv(CONFIG_DIR) |
     .config_paths.data_dir=strenv(DATA_DIR) |
     .config_paths.simulation_path=strenv(CONFIG_DIR)+"/simulation.yaml" |
-    .config_paths.hub_dir=strenv(CONFIG_DIR)+"/hub/" |
-    .config_paths.index_path=strenv(CONFIG_DIR)+"/hub/.index.json" |
-    .config_paths.notification_dir=strenv(CONFIG_DIR)+"/notifications/" |
+    .config_paths.hub_dir=strenv(HUB_DIR) |
+    .config_paths.index_path=strenv(HUB_DIR)+"/.index.json" |
+    .config_paths.notification_dir=strenv(CONFIG_DIR)+"/notifications" |
     .config_paths.plugin_dir=strenv(PLUGIN_DIR) |
     .crowdsec_service.acquisition_path=strenv(CONFIG_DIR)+"/acquis.yaml" |
+    .crowdsec_service.acquisition_dir=strenv(CONFIG_DIR)+"/acquis.d" |
     .db_config.db_path=strenv(DATA_DIR)+"/crowdsec.db" |
     .db_config.use_wal=true |
     .api.client.credentials_path=strenv(CONFIG_DIR)+"/local_api_credentials.yaml" |