2023-02-06 06:33:04 +00:00
package setup_test
import (
"fmt"
"os"
"os/exec"
"runtime"
"testing"
"github.com/lithammer/dedent"
"github.com/stretchr/testify/require"
2023-07-28 14:35:08 +00:00
"github.com/crowdsecurity/go-cs-lib/cstest"
2023-05-25 13:37:44 +00:00
2023-02-06 06:33:04 +00:00
"github.com/crowdsecurity/crowdsec/pkg/setup"
)
//nolint:dupword
var fakeSystemctlOutput = ` UNIT FILE STATE VENDOR PRESET
crowdsec - setup - detect . service enabled enabled
apache2 . service enabled enabled
apparmor . service enabled enabled
apport . service enabled enabled
atop . service enabled enabled
atopacct . service enabled enabled
finalrd . service enabled enabled
fwupd - refresh . service enabled enabled
fwupd . service enabled enabled
9 unit files listed . `
func fakeExecCommandNotFound ( command string , args ... string ) * exec . Cmd {
cs := [ ] string { "-test.run=TestSetupHelperProcess" , "--" , command }
cs = append ( cs , args ... )
cmd := exec . Command ( "this-command-does-not-exist" , cs ... )
cmd . Env = [ ] string { "GO_WANT_HELPER_PROCESS=1" }
return cmd
}
func fakeExecCommand ( command string , args ... string ) * exec . Cmd {
cs := [ ] string { "-test.run=TestSetupHelperProcess" , "--" , command }
cs = append ( cs , args ... )
//nolint:gosec
cmd := exec . Command ( os . Args [ 0 ] , cs ... )
cmd . Env = [ ] string { "GO_WANT_HELPER_PROCESS=1" }
return cmd
}
func TestSetupHelperProcess ( t * testing . T ) {
if os . Getenv ( "GO_WANT_HELPER_PROCESS" ) != "1" {
return
}
fmt . Fprint ( os . Stdout , fakeSystemctlOutput )
os . Exit ( 0 )
}
2023-09-29 10:58:35 +00:00
func tempYAML ( t * testing . T , content string ) os . File {
2023-02-06 06:33:04 +00:00
t . Helper ( )
require := require . New ( t )
file , err := os . CreateTemp ( "" , "" )
require . NoError ( err )
_ , err = file . WriteString ( dedent . Dedent ( content ) )
require . NoError ( err )
err = file . Close ( )
require . NoError ( err )
2023-09-29 10:58:35 +00:00
file , err = os . Open ( file . Name ( ) )
require . NoError ( err )
return * file
2023-02-06 06:33:04 +00:00
}
func TestPathExists ( t * testing . T ) {
t . Parallel ( )
type test struct {
path string
expected bool
}
tests := [ ] test {
{ "/this-should-not-exist" , false } ,
}
if runtime . GOOS == "windows" {
tests = append ( tests , test { ` C:\ ` , true } )
} else {
tests = append ( tests , test { "/tmp" , true } )
}
for _ , tc := range tests {
tc := tc
env := setup . NewExprEnvironment ( setup . DetectOptions { } , setup . ExprOS { } )
t . Run ( tc . path , func ( t * testing . T ) {
t . Parallel ( )
actual := env . PathExists ( tc . path )
require . Equal ( t , tc . expected , actual )
} )
}
}
func TestVersionCheck ( t * testing . T ) {
t . Parallel ( )
tests := [ ] struct {
version string
constraint string
expected bool
expectedErr string
} {
{ "1" , "=1" , true , "" } ,
{ "1" , "!=1" , false , "" } ,
{ "1" , "<=1" , true , "" } ,
{ "1" , ">1" , false , "" } ,
{ "1" , ">=1" , true , "" } ,
{ "1.0" , "<1.0" , false , "" } ,
2023-06-22 09:31:41 +00:00
{ "1" , "<1" , false , "" } ,
{ "1.3.5" , "1.3" , true , "" } ,
2023-02-06 06:33:04 +00:00
{ "1.0" , "<1.0" , false , "" } ,
{ "1.0" , "<=1.0" , true , "" } ,
{ "2" , ">1, <3" , true , "" } ,
{ "2" , "<=2, >=2.2" , false , "" } ,
{ "2.3" , "~2" , true , "" } ,
{ "2.3" , "=2" , true , "" } ,
2023-06-22 09:31:41 +00:00
{ "1.1.1" , "=1.1" , true , "" } ,
{ "1.1.1" , "1.1" , true , "" } ,
2023-02-06 06:33:04 +00:00
{ "1.1" , "!=1.1.1" , true , "" } ,
{ "1.1" , "~1.1.1" , false , "" } ,
{ "1.1.1" , "~1.1" , true , "" } ,
{ "1.1.3" , "~1.1" , true , "" } ,
{ "19.04" , "<19.10" , true , "" } ,
{ "19.04" , ">=19.10" , false , "" } ,
{ "19.04" , "=19.4" , true , "" } ,
{ "19.04" , "~19.4" , true , "" } ,
{ "1.2.3" , "~1.2" , true , "" } ,
2023-06-22 09:31:41 +00:00
{ "1.2.3" , "!=1.2" , false , "" } ,
2023-02-06 06:33:04 +00:00
{ "1.2.3" , "1.1.1 - 1.3.4" , true , "" } ,
{ "1.3.5" , "1.1.1 - 1.3.4" , false , "" } ,
{ "1.3.5" , "=1" , true , "" } ,
{ "1.3.5" , "1" , true , "" } ,
}
for _ , tc := range tests {
tc := tc
e := setup . ExprOS { RawVersion : tc . version }
t . Run ( fmt . Sprintf ( "Check(%s,%s)" , tc . version , tc . constraint ) , func ( t * testing . T ) {
t . Parallel ( )
actual , err := e . VersionCheck ( tc . constraint )
cstest . RequireErrorContains ( t , err , tc . expectedErr )
require . Equal ( t , tc . expected , actual )
} )
}
}
// This is not required for Masterminds/semver
/ *
func TestNormalizeVersion ( t * testing . T ) {
t . Parallel ( )
tests := [ ] struct {
version string
expected string
} {
{ "0" , "0" } ,
{ "2" , "2" } ,
{ "3.14" , "3.14" } ,
{ "1.0" , "1.0" } ,
{ "18.04" , "18.4" } ,
{ "0.0.0" , "0.0.0" } ,
{ "18.04.0" , "18.4.0" } ,
{ "18.0004.0" , "18.4.0" } ,
{ "21.04.2" , "21.4.2" } ,
{ "050" , "50" } ,
{ "trololo" , "trololo" } ,
{ "0001.002.03" , "1.2.3" } ,
{ "0001.002.03-trololo" , "0001.002.03-trololo" } ,
}
for _ , tc := range tests {
tc := tc
t . Run ( tc . version , func ( t * testing . T ) {
t . Parallel ( )
actual := setup . NormalizeVersion ( tc . version )
require . Equal ( t , tc . expected , actual )
} )
}
}
* /
func TestListSupported ( t * testing . T ) {
t . Parallel ( )
tests := [ ] struct {
name string
yml string
expected [ ] string
expectedErr string
} {
{
"list configured services" ,
`
version : 1.0
detect :
foo :
bar :
baz :
` ,
[ ] string { "foo" , "bar" , "baz" } ,
"" ,
} ,
{
"invalid yaml: blahblah" ,
"blahblah" ,
nil ,
"yaml: unmarshal errors:" ,
} ,
{
"invalid yaml: tabs are not allowed" ,
`
version : 1.0
detect :
foos :
` ,
nil ,
"yaml: line 4: found character that cannot start any token" ,
} ,
{
"invalid yaml: no version" ,
"{}" ,
nil ,
"missing version tag (must be 1.0)" ,
} ,
{
"invalid yaml: bad version" ,
"version: 2.0" ,
nil ,
2023-09-29 10:58:35 +00:00
"invalid version tag '2.0' (must be 1.0)" ,
2023-02-06 06:33:04 +00:00
} ,
}
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
t . Parallel ( )
f := tempYAML ( t , tc . yml )
2023-09-29 10:58:35 +00:00
defer os . Remove ( f . Name ( ) )
supported , err := setup . ListSupported ( & f )
2023-02-06 06:33:04 +00:00
cstest . RequireErrorContains ( t , err , tc . expectedErr )
require . ElementsMatch ( t , tc . expected , supported )
} )
}
}
func TestApplyRules ( t * testing . T ) {
t . Parallel ( )
require := require . New ( t )
tests := [ ] struct {
name string
rules [ ] string
expectedOk bool
expectedErr string
} {
{
"empty list is always true" , // XXX or false?
[ ] string { } ,
true ,
"" ,
} ,
{
"simple true expression" ,
[ ] string { "1+1==2" } ,
true ,
"" ,
} ,
{
"simple false expression" ,
[ ] string { "2+2==5" } ,
false ,
"" ,
} ,
{
"all expressions are true" ,
[ ] string { "1+2==3" , "1!=2" } ,
true ,
"" ,
} ,
{
"all expressions must be true" ,
[ ] string { "true" , "1==3" , "1!=2" } ,
false ,
"" ,
} ,
{
"each expression must be a boolan" ,
[ ] string { "true" , "\"notabool\"" } ,
false ,
"rule '\"notabool\"': type must be a boolean" ,
} ,
{
// we keep evaluating expressions to ensure that the
// file is formally correct, even if it can some time.
"each expression must be a boolan (no short circuit)" ,
[ ] string { "false" , "3" } ,
false ,
"rule '3': type must be a boolean" ,
} ,
{
"unknown variable" ,
[ ] string { "false" , "doesnotexist" } ,
false ,
"rule 'doesnotexist': cannot fetch doesnotexist from" ,
} ,
{
"unknown expression" ,
[ ] string { "false" , "doesnotexist()" } ,
false ,
2023-03-09 15:56:11 +00:00
"rule 'doesnotexist()': cannot fetch doesnotexist from" ,
2023-02-06 06:33:04 +00:00
} ,
}
env := setup . ExprEnvironment { }
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
t . Parallel ( )
svc := setup . Service { When : tc . rules }
_ , actualOk , err := setup . ApplyRules ( svc , env ) //nolint:typecheck,nolintlint // exported only for tests
cstest . RequireErrorContains ( t , err , tc . expectedErr )
require . Equal ( tc . expectedOk , actualOk )
} )
}
}
// XXX TODO: TestApplyRules with journalctl default
func TestUnitFound ( t * testing . T ) {
require := require . New ( t )
setup . ExecCommand = fakeExecCommand
defer func ( ) { setup . ExecCommand = exec . Command } ( )
env := setup . NewExprEnvironment ( setup . DetectOptions { } , setup . ExprOS { } )
installed , err := env . UnitFound ( "crowdsec-setup-detect.service" )
require . NoError ( err )
2024-01-05 14:26:13 +00:00
require . True ( installed )
2023-02-06 06:33:04 +00:00
}
// TODO apply rules to filter a list of Service structs
// func testFilterWithRules(t *testing.T) {
// }
func TestDetectSimpleRule ( t * testing . T ) {
require := require . New ( t )
setup . ExecCommand = fakeExecCommand
f := tempYAML ( t , `
version : 1.0
detect :
good :
when :
- true
bad :
when :
- false
ugly :
` )
2023-09-29 10:58:35 +00:00
defer os . Remove ( f . Name ( ) )
2023-02-06 06:33:04 +00:00
2023-09-29 10:58:35 +00:00
detected , err := setup . Detect ( & f , setup . DetectOptions { } )
2023-02-06 06:33:04 +00:00
require . NoError ( err )
expected := [ ] setup . ServiceSetup {
{ DetectedService : "good" } ,
{ DetectedService : "ugly" } ,
}
require . ElementsMatch ( expected , detected . Setup )
}
func TestDetectUnitError ( t * testing . T ) {
if runtime . GOOS == "windows" {
t . Skip ( "skipping on windows" )
}
require := require . New ( t )
setup . ExecCommand = fakeExecCommandNotFound
defer func ( ) { setup . ExecCommand = exec . Command } ( )
tests := [ ] struct {
name string
config string
expected setup . Setup
expectedErr string
} {
{
"error is reported if systemctl does not exist" ,
`
version : 1.0
detect :
wizard :
when :
- UnitFound ( "crowdsec-setup-detect.service" ) ` ,
setup . Setup { [ ] setup . ServiceSetup { } } ,
` while looking for service wizard: rule 'UnitFound("crowdsec-setup-detect.service")': ` +
` running systemctl: exec: "this-command-does-not-exist": executable file not found in $PATH ` ,
} ,
}
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
f := tempYAML ( t , tc . config )
2023-09-29 10:58:35 +00:00
defer os . Remove ( f . Name ( ) )
2023-02-06 06:33:04 +00:00
2023-09-29 10:58:35 +00:00
detected , err := setup . Detect ( & f , setup . DetectOptions { } )
2023-02-06 06:33:04 +00:00
cstest . RequireErrorContains ( t , err , tc . expectedErr )
require . Equal ( tc . expected , detected )
} )
}
}
func TestDetectUnit ( t * testing . T ) {
require := require . New ( t )
setup . ExecCommand = fakeExecCommand
defer func ( ) { setup . ExecCommand = exec . Command } ( )
tests := [ ] struct {
name string
config string
expected setup . Setup
expectedErr string
} {
// {
// "detect a single unit, with default log filter",
// `
// version: 1.0
// detect:
// wizard:
// when:
// - UnitFound("crowdsec-setup-detect.service")
// datasource:
// labels:
// type: syslog
// sorcerer:
// when:
// - UnitFound("sorcerer.service")`,
// setup.Setup{
// Setup: []setup.ServiceSetup{
// {
// DetectedService: "wizard",
// DataSource: setup.DataSourceItem{
// "Labels": map[string]string{"type": "syslog"},
// "JournalCTLFilter": []string{"_SYSTEMD_UNIT=crowdsec-setup-detect.service"},
// },
// },
// },
// },
// "",
// },
// {
// "detect a single unit, but type label is missing",
// `
// version: 1.0
// detect:
// wizard:
// when:
// - UnitFound("crowdsec-setup-detect.service")`,
// setup.Setup{},
// "missing type label for service wizard",
// },
{
"detect unit and pick up acquisistion filter" ,
`
version : 1.0
detect :
wizard :
when :
- UnitFound ( "crowdsec-setup-detect.service" )
datasource :
source : journalctl
labels :
type : syslog
journalctl_filter :
- _MY_CUSTOM_FILTER = something ` ,
setup . Setup {
Setup : [ ] setup . ServiceSetup {
{
DetectedService : "wizard" ,
DataSource : setup . DataSourceItem {
// XXX this should not be DataSourceItem ??
2023-03-09 15:56:11 +00:00
"source" : "journalctl" ,
2023-02-06 06:33:04 +00:00
"labels" : setup . DataSourceItem { "type" : "syslog" } ,
"journalctl_filter" : [ ] interface { } { "_MY_CUSTOM_FILTER=something" } ,
} ,
} ,
} ,
} ,
"" ,
} ,
}
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
f := tempYAML ( t , tc . config )
2023-09-29 10:58:35 +00:00
defer os . Remove ( f . Name ( ) )
2023-02-06 06:33:04 +00:00
2023-09-29 10:58:35 +00:00
detected , err := setup . Detect ( & f , setup . DetectOptions { } )
2023-02-06 06:33:04 +00:00
cstest . RequireErrorContains ( t , err , tc . expectedErr )
require . Equal ( tc . expected , detected )
} )
}
}
func TestDetectForcedUnit ( t * testing . T ) {
require := require . New ( t )
setup . ExecCommand = fakeExecCommand
defer func ( ) { setup . ExecCommand = exec . Command } ( )
f := tempYAML ( t , `
version : 1.0
detect :
wizard :
when :
- UnitFound ( "crowdsec-setup-forced.service" )
datasource :
source : journalctl
labels :
type : syslog
journalctl_filter :
- _SYSTEMD_UNIT = crowdsec - setup - forced . service
` )
2023-09-29 10:58:35 +00:00
defer os . Remove ( f . Name ( ) )
2023-02-06 06:33:04 +00:00
2023-09-29 10:58:35 +00:00
detected , err := setup . Detect ( & f , setup . DetectOptions { ForcedUnits : [ ] string { "crowdsec-setup-forced.service" } } )
2023-02-06 06:33:04 +00:00
require . NoError ( err )
expected := setup . Setup {
Setup : [ ] setup . ServiceSetup {
{
DetectedService : "wizard" ,
DataSource : setup . DataSourceItem {
"source" : "journalctl" ,
"labels" : setup . DataSourceItem { "type" : "syslog" } ,
"journalctl_filter" : [ ] interface { } { "_SYSTEMD_UNIT=crowdsec-setup-forced.service" } ,
} ,
} ,
} ,
}
require . Equal ( expected , detected )
}
func TestDetectForcedProcess ( t * testing . T ) {
if runtime . GOOS == "windows" {
// while looking for service wizard: rule 'ProcessRunning("foobar")': while looking up running processes: could not get Name: A device attached to the system is not functioning.
2024-01-05 14:26:13 +00:00
t . Skip ( "skipping on windows" )
2023-02-06 06:33:04 +00:00
}
require := require . New ( t )
setup . ExecCommand = fakeExecCommand
defer func ( ) { setup . ExecCommand = exec . Command } ( )
f := tempYAML ( t , `
version : 1.0
detect :
wizard :
when :
- ProcessRunning ( "foobar" )
` )
2023-09-29 10:58:35 +00:00
defer os . Remove ( f . Name ( ) )
2023-02-06 06:33:04 +00:00
2023-09-29 10:58:35 +00:00
detected , err := setup . Detect ( & f , setup . DetectOptions { ForcedProcesses : [ ] string { "foobar" } } )
2023-02-06 06:33:04 +00:00
require . NoError ( err )
expected := setup . Setup {
Setup : [ ] setup . ServiceSetup {
{ DetectedService : "wizard" } ,
} ,
}
require . Equal ( expected , detected )
}
func TestDetectSkipService ( t * testing . T ) {
if runtime . GOOS == "windows" {
t . Skip ( "skipping on windows" )
}
require := require . New ( t )
setup . ExecCommand = fakeExecCommand
defer func ( ) { setup . ExecCommand = exec . Command } ( )
f := tempYAML ( t , `
version : 1.0
detect :
wizard :
when :
- ProcessRunning ( "foobar" )
` )
2023-09-29 10:58:35 +00:00
defer os . Remove ( f . Name ( ) )
2023-02-06 06:33:04 +00:00
2023-09-29 10:58:35 +00:00
detected , err := setup . Detect ( & f , setup . DetectOptions { ForcedProcesses : [ ] string { "foobar" } , SkipServices : [ ] string { "wizard" } } )
2023-02-06 06:33:04 +00:00
require . NoError ( err )
expected := setup . Setup { [ ] setup . ServiceSetup { } }
require . Equal ( expected , detected )
}
func TestDetectForcedOS ( t * testing . T ) {
require := require . New ( t )
setup . ExecCommand = fakeExecCommand
defer func ( ) { setup . ExecCommand = exec . Command } ( )
type test struct {
name string
config string
forced setup . ExprOS
expected setup . Setup
expectedErr string
}
tests := [ ] test {
{
"detect OS - force linux" ,
`
version : 1.0
detect :
linux :
when :
- OS . Family == "linux" ` ,
setup . ExprOS { Family : "linux" } ,
setup . Setup {
Setup : [ ] setup . ServiceSetup {
{ DetectedService : "linux" } ,
} ,
} ,
"" ,
} ,
{
"detect OS - force windows" ,
`
version : 1.0
detect :
windows :
when :
- OS . Family == "windows" ` ,
setup . ExprOS { Family : "windows" } ,
setup . Setup {
Setup : [ ] setup . ServiceSetup {
{ DetectedService : "windows" } ,
} ,
} ,
"" ,
} ,
{
"detect OS - ubuntu (no match)" ,
`
version : 1.0
detect :
linux :
when :
- OS . Family == "linux" && OS . ID == "ubuntu" ` ,
setup . ExprOS { Family : "linux" } ,
setup . Setup { [ ] setup . ServiceSetup { } } ,
"" ,
} ,
{
"detect OS - ubuntu (match)" ,
`
version : 1.0
detect :
linux :
when :
- OS . Family == "linux" && OS . ID == "ubuntu" ` ,
setup . ExprOS { Family : "linux" , ID : "ubuntu" } ,
setup . Setup {
Setup : [ ] setup . ServiceSetup {
{ DetectedService : "linux" } ,
} ,
} ,
"" ,
} ,
{
"detect OS - ubuntu (match with version)" ,
`
version : 1.0
detect :
linux :
when :
- OS . Family == "linux" && OS . ID == "ubuntu" && OS . VersionCheck ( "19.04" ) ` ,
setup . ExprOS { Family : "linux" , ID : "ubuntu" , RawVersion : "19.04" } ,
setup . Setup {
Setup : [ ] setup . ServiceSetup {
{ DetectedService : "linux" } ,
} ,
} ,
"" ,
} ,
{
"detect OS - ubuntu >= 20.04 (no match: no version detected)" ,
`
version : 1.0
detect :
linux :
when :
- OS . ID == "ubuntu" && OS . VersionCheck ( ">=20.04" ) ` ,
setup . ExprOS { Family : "linux" } ,
setup . Setup { [ ] setup . ServiceSetup { } } ,
"" ,
} ,
{
"detect OS - ubuntu >= 20.04 (no match: version is lower)" ,
`
version : 1.0
detect :
linux :
when :
- OS . ID == "ubuntu" && OS . VersionCheck ( ">=20.04" ) ` ,
setup . ExprOS { Family : "linux" , ID : "ubuntu" , RawVersion : "19.10" } ,
setup . Setup { [ ] setup . ServiceSetup { } } ,
"" ,
} ,
{
"detect OS - ubuntu >= 20.04 (match: same version)" ,
`
version : 1.0
detect :
linux :
when :
- OS . ID == "ubuntu" && OS . VersionCheck ( ">=20.04" ) ` ,
setup . ExprOS { Family : "linux" , ID : "ubuntu" , RawVersion : "20.04" } ,
setup . Setup {
Setup : [ ] setup . ServiceSetup {
{ DetectedService : "linux" } ,
} ,
} ,
"" ,
} ,
{
"detect OS - ubuntu >= 20.04 (match: version is higher)" ,
`
version : 1.0
detect :
linux :
when :
- OS . ID == "ubuntu" && OS . VersionCheck ( ">=20.04" ) ` ,
setup . ExprOS { Family : "linux" , ID : "ubuntu" , RawVersion : "22.04" } ,
setup . Setup {
Setup : [ ] setup . ServiceSetup {
{ DetectedService : "linux" } ,
} ,
} ,
"" ,
} ,
{
"detect OS - ubuntu < 20.04 (no match: no version detected)" ,
`
version : 1.0
detect :
linux :
when :
- OS . ID == "ubuntu" && OS . VersionCheck ( "<20.04" ) ` ,
setup . ExprOS { Family : "linux" } ,
setup . Setup { [ ] setup . ServiceSetup { } } ,
"" ,
} ,
{
"detect OS - ubuntu < 20.04 (no match: version is higher)" ,
`
version : 1.0
detect :
linux :
when :
- OS . ID == "ubuntu" && OS . VersionCheck ( "<20.04" ) ` ,
setup . ExprOS { Family : "linux" , ID : "ubuntu" , RawVersion : "20.10" } ,
setup . Setup { [ ] setup . ServiceSetup { } } ,
"" ,
} ,
{
"detect OS - ubuntu < 20.04 (no match: same version)" ,
`
version : 1.0
detect :
linux :
when :
- OS . ID == "ubuntu" && OS . VersionCheck ( "<20.04" ) ` ,
setup . ExprOS { Family : "linux" , ID : "ubuntu" , RawVersion : "20.04" } ,
setup . Setup { [ ] setup . ServiceSetup { } } ,
"" ,
} ,
{
"detect OS - ubuntu < 20.04 (match: version is lower)" ,
`
version : 1.0
detect :
linux :
when :
- OS . ID == "ubuntu"
- OS . VersionCheck ( "<20.04" ) ` ,
setup . ExprOS { Family : "linux" , ID : "ubuntu" , RawVersion : "19.10" } ,
setup . Setup {
Setup : [ ] setup . ServiceSetup {
{ DetectedService : "linux" } ,
} ,
} ,
"" ,
} ,
}
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
f := tempYAML ( t , tc . config )
2023-09-29 10:58:35 +00:00
defer os . Remove ( f . Name ( ) )
2023-02-06 06:33:04 +00:00
2023-09-29 10:58:35 +00:00
detected , err := setup . Detect ( & f , setup . DetectOptions { ForcedOS : tc . forced } )
2023-02-06 06:33:04 +00:00
cstest . RequireErrorContains ( t , err , tc . expectedErr )
require . Equal ( tc . expected , detected )
} )
}
}
func TestDetectDatasourceValidation ( t * testing . T ) {
// It could be a good idea to test UnmarshalConfig() separately in addition
// to Configure(), in each datasource. For now, we test these here.
require := require . New ( t )
setup . ExecCommand = fakeExecCommand
defer func ( ) { setup . ExecCommand = exec . Command } ( )
type test struct {
name string
config string
expected setup . Setup
expectedErr string
}
tests := [ ] test {
{
name : "source is empty" ,
config : `
version : 1.0
detect :
wizard :
datasource :
labels :
type : something ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for wizard: source is empty" ,
} , {
name : "source is unknown" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : wombat ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: unknown source 'wombat'" ,
} , {
name : "source is misplaced" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : file ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-09-29 10:58:35 +00:00
expectedErr : "yaml: unmarshal errors:\n line 6: field source not found in type setup.Service" ,
2023-02-06 06:33:04 +00:00
} , {
name : "source is mismatched" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : journalctl
filename : / path / to / file . log ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: cannot parse JournalCtlSource configuration: yaml: unmarshal errors:\n line 1: field filename not found in type journalctlacquisition.JournalCtlConfiguration" ,
} , {
name : "source file: required fields" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : file ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: no filename or filenames configuration provided" ,
} , {
name : "source journalctl: required fields" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : journalctl ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: journalctl_filter is required" ,
} , {
name : "source cloudwatch: required fields" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : cloudwatch ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: group_name is mandatory for CloudwatchSource" ,
} , {
name : "source syslog: all fields are optional" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : syslog ` ,
expected : setup . Setup {
Setup : [ ] setup . ServiceSetup {
{
2023-03-09 15:56:11 +00:00
DetectedService : "foobar" ,
DataSource : setup . DataSourceItem { "source" : "syslog" } ,
2023-02-06 06:33:04 +00:00
} ,
} ,
} ,
} , {
name : "source docker: required fields" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : docker ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: no containers names or containers ID configuration provided" ,
} , {
name : "source kinesis: required fields (enhanced fanout=false)" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : kinesis ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: stream_name is mandatory when use_enhanced_fanout is false" ,
} , {
name : "source kinesis: required fields (enhanced fanout=true)" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : kinesis
use_enhanced_fanout : true ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: stream_arn is mandatory when use_enhanced_fanout is true" ,
} , {
name : "source kafka: required fields" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : kafka ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: cannot create a kafka reader with an empty list of broker addresses" ,
2023-11-22 12:31:39 +00:00
} , {
name : "source loki: required fields" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : loki ` ,
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
expectedErr : "invalid datasource for foobar: loki query is mandatory" ,
2023-02-06 06:33:04 +00:00
} ,
}
if runtime . GOOS == "windows" {
tests = append ( tests , test {
name : "source wineventlog: required fields" ,
config : `
version : 1.0
detect :
foobar :
datasource :
source : wineventlog ` ,
2023-03-09 15:56:11 +00:00
expected : setup . Setup { Setup : [ ] setup . ServiceSetup { } } ,
2023-02-06 06:33:04 +00:00
expectedErr : "invalid datasource for foobar: event_channel or xpath_query must be set" ,
} )
}
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
2023-09-29 10:58:35 +00:00
f := tempYAML ( t , tc . config )
defer os . Remove ( f . Name ( ) )
detected , err := setup . Detect ( & f , setup . DetectOptions { } )
cstest . RequireErrorContains ( t , err , tc . expectedErr )
2023-02-06 06:33:04 +00:00
require . Equal ( tc . expected , detected )
} )
}
}