Skip to content

Commit

Permalink
test to check multiplexer
Browse files Browse the repository at this point in the history
  • Loading branch information
dmachard committed Dec 24, 2023
1 parent 5fa2e49 commit d6b628e
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 2 deletions.
2 changes: 0 additions & 2 deletions config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


################################################
# global configuration
################################################
Expand Down
104 changes: 104 additions & 0 deletions pkgconfig/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pkgconfig

import (
"fmt"
"io"
"os"
"reflect"
Expand Down Expand Up @@ -139,6 +140,109 @@ func CheckConfig(userConfigPath string) error {
}
}

// detect bad keyword position
err = checkKeywordsPosition(userConfigMap, defaultConfigMap, defaultConfigMap, "")
if err != nil {
return err
}
return nil
}

func checkKeywordsPosition(nextUserCfg, nextDefCfg map[string]interface{}, defaultConf map[string]interface{}, sectionName string) error {
for k, v := range nextUserCfg {
// Check if the key is present in the default config
if _, ok := nextDefCfg[k]; !ok {
if sectionName == "" {
return errors.Errorf("invalid key `%s` at root", k)
}
return errors.Errorf("invalid key `%s` in section `%s`", k, sectionName)
}

// If the value is a map, recursively check for invalid keywords
// Recursive call ?
val := reflect.ValueOf(v)
if val.Kind() == reflect.Map {
nextSectionName := fmt.Sprintf("%s.%s", sectionName, k)
if err := checkKeywordsPosition(v.(map[string]interface{}), nextDefCfg[k].(map[string]interface{}), defaultConf, nextSectionName); err != nil {
return err
}
}

// If the value is a slice and we are in the multiplexer part
// Multiplixer part is dynamic, we need specific function to check it
if val.Kind() == reflect.Slice && sectionName == ".multiplexer" {
if err := checkMultiplexerConfig(val, nextDefCfg[k].([]interface{}), defaultConf, k); err != nil {
return err
}
}

}
return nil
}

func checkMultiplexerConfig(currentVal reflect.Value, currentRef []interface{}, defaultConf map[string]interface{}, k string) error {
refLoggers := defaultConf[KeyLoggers].(map[string]interface{})
refCollectors := defaultConf[KeyCollectors].(map[string]interface{})
refTransforms := defaultConf["collectors-transformers"].(map[string]interface{})

// iter over the slice
for pos, item := range currentVal.Interface().([]interface{}) {
valReflect := reflect.ValueOf(item)
refItem := currentRef[0].(map[string]interface{})
if valReflect.Kind() == reflect.Map {
for _, key := range valReflect.MapKeys() {
strKey := key.Interface().(string)
mapVal := valReflect.MapIndex(key)

// First, check in the initial configuration reference.
// If not found, then look in the logger and collector references.
if _, ok := refItem[strKey]; !ok {
// we are in routes section ?
if !(k == KeyCollectors || k == KeyLoggers) {
return errors.Errorf("invalid `%s` in `%s` list at position %d", strKey, k, pos)
}

// Check if the key exists in neither loggers nor collectors
loggerExists := refLoggers[strKey] != nil
collectorExists := refCollectors[strKey] != nil
if !loggerExists && !collectorExists {
return errors.Errorf("invalid `%s` in `%s` list at position %d", strKey, k, pos)
}

// check logger
if k == KeyLoggers || k == KeyCollectors {
nextSectionName := fmt.Sprintf("%s[%d].%s", k, pos, strKey)
refMap := refLoggers
if k == KeyCollectors {
refMap = refCollectors
}

// Type assertion to check if the value is a map
if value, ok := mapVal.Interface().(map[string]interface{}); ok {
if err := checkKeywordsPosition(value, refMap[strKey].(map[string]interface{}), defaultConf, nextSectionName); err != nil {
return err
}
} else {
return errors.Errorf("invalid `%s` value in `%s` list at position %d", strKey, k, pos)
}
}
}

// Check transforms section
// Type assertion to check if the value is a map
if strKey == "transforms" {
nextSectionName := fmt.Sprintf("%s.%s", k, strKey)
if value, ok := mapVal.Interface().(map[string]interface{}); ok {
if err := checkKeywordsPosition(value, refTransforms, defaultConf, nextSectionName); err != nil {
return err
}
} else {
return errors.Errorf("invalid `%s` value in `%s` list at position %d", strKey, k, pos)
}
}
}
}
}
return nil
}

Expand Down
89 changes: 89 additions & 0 deletions pkgconfig/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,92 @@ multiplexer:
t.Errorf("Expected error %v, but got %v", expectedError, err)
}
}

// Keywork exist but not at the good position
func TestConfig_CheckConfig_BadKeywordPosition(t *testing.T) {
userConfigFile, err := os.CreateTemp("", "user-config.yaml")
if err != nil {
t.Fatal("Error creating temporary file:", err)
}
defer os.Remove(userConfigFile.Name())
defer userConfigFile.Close()

userConfigContent := `
global:
trace: false
logger: bad-position
`
err = os.WriteFile(userConfigFile.Name(), []byte(userConfigContent), 0644)
if err != nil {
t.Fatal("Error writing to user configuration file:", err)
}
if err := CheckConfig(userConfigFile.Name()); err == nil {
t.Errorf("Expected error, but got %v", err)
}
}

// Valid multiplexer configuration
func TestConfig_CheckMultiplexerConfig_Valid(t *testing.T) {
userConfigFile, err := os.CreateTemp("", "user-config.yaml")
if err != nil {
t.Fatal("Error creating temporary file:", err)
}
defer os.Remove(userConfigFile.Name())
defer userConfigFile.Close()

userConfigContent := `
multiplexer:
collectors:
- name: tap
dnstap:
listen-ip: 0.0.0.0
listen-port: 6000
transforms:
normalize:
qname-lowercase: false
loggers:
- name: console
stdout:
mode: text
routes:
- from: [ tap ]
to: [ console ]
`
err = os.WriteFile(userConfigFile.Name(), []byte(userConfigContent), 0644)
if err != nil {
t.Fatal("Error writing to user configuration file:", err)
}
if err := CheckConfig(userConfigFile.Name()); err != nil {
t.Errorf("failed: Unexpected error: %v", err)
}
}

// Invalid multiplexer configuration
func TestConfig_CheckMultiplexerConfig_Invalid(t *testing.T) {
userConfigFile, err := os.CreateTemp("", "user-config.yaml")
if err != nil {
t.Fatal("Error creating temporary file:", err)
}
defer os.Remove(userConfigFile.Name())
defer userConfigFile.Close()

userConfigContent := `
global:
trace: false
multiplexer:
- name: block
dnstap:
listen-ip: 0.0.0.0
transforms:
normalize:
qname-lowercase: true
`

err = os.WriteFile(userConfigFile.Name(), []byte(userConfigContent), 0644)
if err != nil {
t.Fatal("Error writing to user configuration file:", err)
}
if err := CheckConfig(userConfigFile.Name()); err == nil {
t.Errorf("Expected error, but got %v", err)
}
}
3 changes: 3 additions & 0 deletions pkgconfig/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const (
AnyIP = "0.0.0.0"
HTTPOK = "HTTP/1.1 200 OK\r\n\r\n"

KeyCollectors = "collectors"
KeyLoggers = "loggers"

ValidDomain = "dnscollector.dev."
BadDomainLabel = "ultramegaverytoolonglabel-ultramegaverytoolonglabel-ultramegaverytoolonglabel.dnscollector.dev."
badLongLabel = "ultramegaverytoolonglabel-ultramegaverytoolonglabel-"
Expand Down

0 comments on commit d6b628e

Please sign in to comment.