mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 03:38:42 -07:00
Config reporting with line and error position
Signed-off-by: Waldemar Quevedo <wally@synadia.com>
This commit is contained in:
30
conf/lex.go
30
conf/lex.go
@@ -101,12 +101,19 @@ type lexer struct {
|
|||||||
// Used for processing escapable substrings in double-quoted and raw strings
|
// Used for processing escapable substrings in double-quoted and raw strings
|
||||||
stringParts []string
|
stringParts []string
|
||||||
stringStateFn stateFn
|
stringStateFn stateFn
|
||||||
|
|
||||||
|
// lstart is the start position of the current line.
|
||||||
|
lstart int
|
||||||
|
|
||||||
|
// ilstart is the start position of the line from the current item.
|
||||||
|
ilstart int
|
||||||
}
|
}
|
||||||
|
|
||||||
type item struct {
|
type item struct {
|
||||||
typ itemType
|
typ itemType
|
||||||
val string
|
val string
|
||||||
line int
|
line int
|
||||||
|
pos int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lx *lexer) nextItem() item {
|
func (lx *lexer) nextItem() item {
|
||||||
@@ -147,8 +154,13 @@ func (lx *lexer) pop() stateFn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (lx *lexer) emit(typ itemType) {
|
func (lx *lexer) emit(typ itemType) {
|
||||||
lx.items <- item{typ, strings.Join(lx.stringParts, "") + lx.input[lx.start:lx.pos], lx.line}
|
val := strings.Join(lx.stringParts, "") + lx.input[lx.start:lx.pos]
|
||||||
|
|
||||||
|
// Position of item in line where it started.
|
||||||
|
pos := lx.pos - lx.ilstart - len(val)
|
||||||
|
lx.items <- item{typ, val, lx.line, pos}
|
||||||
lx.start = lx.pos
|
lx.start = lx.pos
|
||||||
|
lx.ilstart = lx.lstart
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lx *lexer) emitString() {
|
func (lx *lexer) emitString() {
|
||||||
@@ -159,8 +171,11 @@ func (lx *lexer) emitString() {
|
|||||||
} else {
|
} else {
|
||||||
finalString = lx.input[lx.start:lx.pos]
|
finalString = lx.input[lx.start:lx.pos]
|
||||||
}
|
}
|
||||||
lx.items <- item{itemString, finalString, lx.line}
|
// Position of string in line where it started.
|
||||||
|
pos := lx.pos - lx.ilstart - len(finalString)
|
||||||
|
lx.items <- item{itemString, finalString, lx.line, pos}
|
||||||
lx.start = lx.pos
|
lx.start = lx.pos
|
||||||
|
lx.ilstart = lx.lstart
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lx *lexer) addCurrentStringPart(offset int) {
|
func (lx *lexer) addCurrentStringPart(offset int) {
|
||||||
@@ -186,15 +201,20 @@ func (lx *lexer) next() (r rune) {
|
|||||||
|
|
||||||
if lx.input[lx.pos] == '\n' {
|
if lx.input[lx.pos] == '\n' {
|
||||||
lx.line++
|
lx.line++
|
||||||
|
|
||||||
|
// Mark start position of current line.
|
||||||
|
lx.lstart = lx.pos
|
||||||
}
|
}
|
||||||
r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:])
|
r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:])
|
||||||
lx.pos += lx.width
|
lx.pos += lx.width
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore skips over the pending input before this point.
|
// ignore skips over the pending input before this point.
|
||||||
func (lx *lexer) ignore() {
|
func (lx *lexer) ignore() {
|
||||||
lx.start = lx.pos
|
lx.start = lx.pos
|
||||||
|
lx.ilstart = lx.lstart
|
||||||
}
|
}
|
||||||
|
|
||||||
// backup steps back one rune. Can be called only once per call of next.
|
// backup steps back one rune. Can be called only once per call of next.
|
||||||
@@ -221,10 +241,14 @@ func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
|
|||||||
values[i] = escapeSpecial(v)
|
values[i] = escapeSpecial(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Position of error in current line.
|
||||||
|
pos := lx.pos - lx.lstart
|
||||||
lx.items <- item{
|
lx.items <- item{
|
||||||
itemError,
|
itemError,
|
||||||
fmt.Sprintf(format, values...),
|
fmt.Sprintf(format, values...),
|
||||||
lx.line,
|
lx.line,
|
||||||
|
pos,
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1131,7 +1155,7 @@ func (itype itemType) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (item item) String() string {
|
func (item item) String() string {
|
||||||
return fmt.Sprintf("(%s, '%s', %d)", item.typ.String(), item.val, item.line)
|
return fmt.Sprintf("(%s, '%s', %d, %d)", item.typ.String(), item.val, item.line, item.pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func escapeSpecial(c rune) string {
|
func escapeSpecial(c rune) string {
|
||||||
|
|||||||
998
conf/lex_test.go
998
conf/lex_test.go
File diff suppressed because it is too large
Load Diff
@@ -49,6 +49,9 @@ type parser struct {
|
|||||||
// Keys stack
|
// Keys stack
|
||||||
keys []string
|
keys []string
|
||||||
|
|
||||||
|
// Keys stack as items
|
||||||
|
ikeys []item
|
||||||
|
|
||||||
// The config file path, empty by default.
|
// The config file path, empty by default.
|
||||||
fp string
|
fp string
|
||||||
|
|
||||||
@@ -118,12 +121,17 @@ func (t *token) SourceFile() string {
|
|||||||
return t.sourceFile
|
return t.sourceFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *token) Position() int {
|
||||||
|
return t.item.pos
|
||||||
|
}
|
||||||
|
|
||||||
func parse(data, fp string, pedantic bool) (p *parser, err error) {
|
func parse(data, fp string, pedantic bool) (p *parser, err error) {
|
||||||
p = &parser{
|
p = &parser{
|
||||||
mapping: make(map[string]interface{}),
|
mapping: make(map[string]interface{}),
|
||||||
lx: lex(data),
|
lx: lex(data),
|
||||||
ctxs: make([]interface{}, 0, 4),
|
ctxs: make([]interface{}, 0, 4),
|
||||||
keys: make([]string, 0, 4),
|
keys: make([]string, 0, 4),
|
||||||
|
ikeys: make([]item, 0, 4),
|
||||||
fp: filepath.Dir(fp),
|
fp: filepath.Dir(fp),
|
||||||
pedantic: pedantic,
|
pedantic: pedantic,
|
||||||
}
|
}
|
||||||
@@ -176,6 +184,20 @@ func (p *parser) popKey() string {
|
|||||||
return last
|
return last
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *parser) pushItemKey(key item) {
|
||||||
|
p.ikeys = append(p.ikeys, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) popItemKey() item {
|
||||||
|
if len(p.ikeys) == 0 {
|
||||||
|
panic("BUG in parser, item keys stack empty")
|
||||||
|
}
|
||||||
|
li := len(p.ikeys) - 1
|
||||||
|
last := p.ikeys[li]
|
||||||
|
p.ikeys = p.ikeys[0:li]
|
||||||
|
return last
|
||||||
|
}
|
||||||
|
|
||||||
func (p *parser) processItem(it item, fp string) error {
|
func (p *parser) processItem(it item, fp string) error {
|
||||||
setValue := func(it item, v interface{}) {
|
setValue := func(it item, v interface{}) {
|
||||||
if p.pedantic {
|
if p.pedantic {
|
||||||
@@ -189,7 +211,14 @@ func (p *parser) processItem(it item, fp string) error {
|
|||||||
case itemError:
|
case itemError:
|
||||||
return fmt.Errorf("Parse error on line %d: '%s'", it.line, it.val)
|
return fmt.Errorf("Parse error on line %d: '%s'", it.line, it.val)
|
||||||
case itemKey:
|
case itemKey:
|
||||||
|
// Keep track of the keys as items and strings,
|
||||||
|
// we do this in order to be able to still support
|
||||||
|
// includes without many breaking changes.
|
||||||
p.pushKey(it.val)
|
p.pushKey(it.val)
|
||||||
|
|
||||||
|
if p.pedantic {
|
||||||
|
p.pushItemKey(it)
|
||||||
|
}
|
||||||
case itemMapStart:
|
case itemMapStart:
|
||||||
newCtx := make(map[string]interface{})
|
newCtx := make(map[string]interface{})
|
||||||
p.pushContext(newCtx)
|
p.pushContext(newCtx)
|
||||||
@@ -297,6 +326,13 @@ func (p *parser) processItem(it item, fp string) error {
|
|||||||
}
|
}
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
p.pushKey(k)
|
p.pushKey(k)
|
||||||
|
|
||||||
|
if p.pedantic {
|
||||||
|
switch tk := v.(type) {
|
||||||
|
case *token:
|
||||||
|
p.pushItemKey(tk.item)
|
||||||
|
}
|
||||||
|
}
|
||||||
p.setValue(v)
|
p.setValue(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,7 +392,21 @@ func (p *parser) setValue(val interface{}) {
|
|||||||
// Map processing
|
// Map processing
|
||||||
if ctx, ok := p.ctx.(map[string]interface{}); ok {
|
if ctx, ok := p.ctx.(map[string]interface{}); ok {
|
||||||
key := p.popKey()
|
key := p.popKey()
|
||||||
// FIXME(dlc), make sure to error if redefining same key?
|
|
||||||
ctx[key] = val
|
if p.pedantic {
|
||||||
|
it := p.popItemKey()
|
||||||
|
|
||||||
|
// Change the position to the beginning of the key
|
||||||
|
// since more useful when reporting errors.
|
||||||
|
switch v := val.(type) {
|
||||||
|
case *token:
|
||||||
|
v.item.pos = it.pos
|
||||||
|
v.item.line = it.line
|
||||||
|
ctx[key] = v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME(dlc), make sure to error if redefining same key?
|
||||||
|
ctx[key] = val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
// errorLine is the location of the error.
|
// errorLine is the location of the error.
|
||||||
errorLine int
|
errorLine int
|
||||||
|
|
||||||
|
// errorPos is the position of the error.
|
||||||
|
errorPos int
|
||||||
|
|
||||||
// warning errors also include a reason optionally
|
// warning errors also include a reason optionally
|
||||||
reason string
|
reason string
|
||||||
}{
|
}{
|
||||||
@@ -48,20 +51,20 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "monitor"`),
|
pedanticErr: errors.New(`unknown field "monitor"`),
|
||||||
errorLine: 2,
|
errorLine: 2,
|
||||||
|
errorPos: 17,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when default permissions are used at top level",
|
name: "when default permissions are used at top level",
|
||||||
config: `
|
config: `
|
||||||
"default_permissions" {
|
"default_permissions" {
|
||||||
publish = ["_SANDBOX.>"]
|
publish = ["_SANDBOX.>"]
|
||||||
subscribe = ["_SANDBOX.>"]
|
subscribe = ["_SANDBOX.>"]
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "default_permissions"`),
|
pedanticErr: errors.New(`unknown field "default_permissions"`),
|
||||||
|
errorLine: 2,
|
||||||
// NOTE: line number is '5' because it is where the map definition ends.
|
errorPos: 18,
|
||||||
errorLine: 5,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when authorization config is empty",
|
name: "when authorization config is empty",
|
||||||
@@ -82,15 +85,16 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "foo"`),
|
pedanticErr: errors.New(`unknown field "foo"`),
|
||||||
errorLine: 3,
|
errorLine: 3,
|
||||||
|
errorPos: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when authorization config has unknown fields",
|
name: "when authorization config has unknown fields",
|
||||||
config: `
|
config: `
|
||||||
port = 4222
|
port = 4222
|
||||||
|
|
||||||
authorization = {
|
authorization = {
|
||||||
user = "hello"
|
user = "hello"
|
||||||
foo = "bar"
|
foo = "bar"
|
||||||
password = "world"
|
password = "world"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +102,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "foo"`),
|
pedanticErr: errors.New(`unknown field "foo"`),
|
||||||
errorLine: 6,
|
errorLine: 6,
|
||||||
|
errorPos: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when user authorization config has unknown fields",
|
name: "when user authorization config has unknown fields",
|
||||||
@@ -105,16 +110,17 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
authorization = {
|
authorization = {
|
||||||
users = [
|
users = [
|
||||||
{
|
{
|
||||||
user = "foo"
|
user = "foo"
|
||||||
pass = "bar"
|
pass = "bar"
|
||||||
token = "quux"
|
token = "quux"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "token"`),
|
pedanticErr: errors.New(`unknown field "token"`),
|
||||||
errorLine: 7,
|
errorLine: 7,
|
||||||
|
errorPos: 9,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when user authorization permissions config has unknown fields",
|
name: "when user authorization permissions config has unknown fields",
|
||||||
@@ -130,6 +136,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: errors.New(`Unknown field inboxes parsing permissions`),
|
defaultErr: errors.New(`Unknown field inboxes parsing permissions`),
|
||||||
pedanticErr: errors.New(`unknown field "inboxes"`),
|
pedanticErr: errors.New(`unknown field "inboxes"`),
|
||||||
errorLine: 5,
|
errorLine: 5,
|
||||||
|
errorPos: 7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when user authorization permissions config has unknown fields within allow or deny",
|
name: "when user authorization permissions config has unknown fields within allow or deny",
|
||||||
@@ -137,10 +144,10 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
authorization {
|
authorization {
|
||||||
permissions {
|
permissions {
|
||||||
subscribe = {
|
subscribe = {
|
||||||
allow = ["hello", "world"]
|
allow = ["hello", "world"]
|
||||||
deny = ["foo", "bar"]
|
deny = ["foo", "bar"]
|
||||||
denied = "_INBOX.>"
|
denied = "_INBOX.>"
|
||||||
}
|
}
|
||||||
publish = {}
|
publish = {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,6 +155,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: errors.New(`Unknown field name "denied" parsing subject permissions, only 'allow' or 'deny' are permitted`),
|
defaultErr: errors.New(`Unknown field name "denied" parsing subject permissions, only 'allow' or 'deny' are permitted`),
|
||||||
pedanticErr: errors.New(`unknown field "denied"`),
|
pedanticErr: errors.New(`unknown field "denied"`),
|
||||||
errorLine: 7,
|
errorLine: 7,
|
||||||
|
errorPos: 9,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when user authorization permissions config has unknown fields within allow or deny",
|
name: "when user authorization permissions config has unknown fields within allow or deny",
|
||||||
@@ -155,10 +163,10 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
authorization {
|
authorization {
|
||||||
permissions {
|
permissions {
|
||||||
publish = {
|
publish = {
|
||||||
allow = ["hello", "world"]
|
allow = ["hello", "world"]
|
||||||
deny = ["foo", "bar"]
|
deny = ["foo", "bar"]
|
||||||
allowed = "_INBOX.>"
|
allowed = "_INBOX.>"
|
||||||
}
|
}
|
||||||
subscribe = {}
|
subscribe = {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,11 +174,12 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: errors.New(`Unknown field name "allowed" parsing subject permissions, only 'allow' or 'deny' are permitted`),
|
defaultErr: errors.New(`Unknown field name "allowed" parsing subject permissions, only 'allow' or 'deny' are permitted`),
|
||||||
pedanticErr: errors.New(`unknown field "allowed"`),
|
pedanticErr: errors.New(`unknown field "allowed"`),
|
||||||
errorLine: 7,
|
errorLine: 7,
|
||||||
|
errorPos: 9,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when user authorization permissions config has unknown fields using arrays",
|
name: "when user authorization permissions config has unknown fields using arrays",
|
||||||
config: `
|
config: `
|
||||||
authorization {
|
authorization {
|
||||||
|
|
||||||
default_permissions {
|
default_permissions {
|
||||||
subscribe = ["a"]
|
subscribe = ["a"]
|
||||||
@@ -184,16 +193,17 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
pass = "bar"
|
pass = "bar"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: errors.New(`Unknown field inboxes parsing permissions`),
|
defaultErr: errors.New(`Unknown field inboxes parsing permissions`),
|
||||||
pedanticErr: errors.New(`unknown field "inboxes"`),
|
pedanticErr: errors.New(`unknown field "inboxes"`),
|
||||||
errorLine: 7,
|
errorLine: 7,
|
||||||
|
errorPos: 6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when user authorization permissions config has unknown fields using strings",
|
name: "when user authorization permissions config has unknown fields using strings",
|
||||||
config: `
|
config: `
|
||||||
authorization {
|
authorization {
|
||||||
|
|
||||||
default_permissions {
|
default_permissions {
|
||||||
subscribe = "a"
|
subscribe = "a"
|
||||||
@@ -207,11 +217,12 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
pass = "bar"
|
pass = "bar"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: errors.New(`Unknown field requests parsing permissions`),
|
defaultErr: errors.New(`Unknown field requests parsing permissions`),
|
||||||
pedanticErr: errors.New(`unknown field "requests"`),
|
pedanticErr: errors.New(`unknown field "requests"`),
|
||||||
errorLine: 6,
|
errorLine: 6,
|
||||||
|
errorPos: 6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when user authorization permissions config is empty",
|
name: "when user authorization permissions config is empty",
|
||||||
@@ -244,6 +255,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: errors.New(`Unknown field inboxes parsing permissions`),
|
defaultErr: errors.New(`Unknown field inboxes parsing permissions`),
|
||||||
pedanticErr: errors.New(`unknown field "inboxes"`),
|
pedanticErr: errors.New(`unknown field "inboxes"`),
|
||||||
errorLine: 6,
|
errorLine: 6,
|
||||||
|
errorPos: 11,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when clustering config is empty",
|
name: "when clustering config is empty",
|
||||||
@@ -258,19 +270,19 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "when unknown option is in clustering config",
|
name: "when unknown option is in clustering config",
|
||||||
config: `
|
config: `
|
||||||
# NATS Server Configuration
|
# NATS Server Configuration
|
||||||
port = 4222
|
port = 4222
|
||||||
|
|
||||||
cluster = {
|
cluster = {
|
||||||
|
|
||||||
port = 6222
|
port = 6222
|
||||||
|
|
||||||
foo = "bar"
|
foo = "bar"
|
||||||
|
|
||||||
authorization {
|
authorization {
|
||||||
user = "hello"
|
user = "hello"
|
||||||
pass = "world"
|
pass = "world"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -278,6 +290,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "foo"`),
|
pedanticErr: errors.New(`unknown field "foo"`),
|
||||||
errorLine: 9,
|
errorLine: 9,
|
||||||
|
errorPos: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when unknown option is in clustering authorization config",
|
name: "when unknown option is in clustering authorization config",
|
||||||
@@ -292,6 +305,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "foo"`),
|
pedanticErr: errors.New(`unknown field "foo"`),
|
||||||
errorLine: 4,
|
errorLine: 4,
|
||||||
|
errorPos: 7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when unknown option is in clustering authorization permissions config",
|
name: "when unknown option is in clustering authorization permissions config",
|
||||||
@@ -309,6 +323,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: errors.New(`Unknown field hello parsing permissions`),
|
defaultErr: errors.New(`Unknown field hello parsing permissions`),
|
||||||
pedanticErr: errors.New(`unknown field "hello"`),
|
pedanticErr: errors.New(`unknown field "hello"`),
|
||||||
errorLine: 7,
|
errorLine: 7,
|
||||||
|
errorPos: 9,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when unknown option is in tls config",
|
name: "when unknown option is in tls config",
|
||||||
@@ -320,6 +335,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: errors.New(`error parsing tls config, unknown field ["hello"]`),
|
defaultErr: errors.New(`error parsing tls config, unknown field ["hello"]`),
|
||||||
pedanticErr: errors.New(`unknown field "hello"`),
|
pedanticErr: errors.New(`unknown field "hello"`),
|
||||||
errorLine: 3,
|
errorLine: 3,
|
||||||
|
errorPos: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when unknown option is in cluster tls config",
|
name: "when unknown option is in cluster tls config",
|
||||||
@@ -334,6 +350,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: errors.New(`error parsing tls config, unknown field ["foo"]`),
|
defaultErr: errors.New(`error parsing tls config, unknown field ["foo"]`),
|
||||||
pedanticErr: errors.New(`unknown field "foo"`),
|
pedanticErr: errors.New(`unknown field "foo"`),
|
||||||
errorLine: 4,
|
errorLine: 4,
|
||||||
|
errorPos: 7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when using cipher suites in the TLS config",
|
name: "when using cipher suites in the TLS config",
|
||||||
@@ -343,12 +360,13 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||||
]
|
]
|
||||||
preferences = []
|
preferences = []
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: errors.New(`error parsing tls config, unknown field ["preferences"]`),
|
defaultErr: errors.New(`error parsing tls config, unknown field ["preferences"]`),
|
||||||
pedanticErr: errors.New(`unknown field "preferences"`),
|
pedanticErr: errors.New(`unknown field "preferences"`),
|
||||||
errorLine: 7,
|
errorLine: 7,
|
||||||
|
errorPos: 7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when using curve preferences in the TLS config",
|
name: "when using curve preferences in the TLS config",
|
||||||
@@ -359,27 +377,29 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
"CurveP384",
|
"CurveP384",
|
||||||
"CurveP521"
|
"CurveP521"
|
||||||
]
|
]
|
||||||
suites = []
|
suites = []
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: errors.New(`error parsing tls config, unknown field ["suites"]`),
|
defaultErr: errors.New(`error parsing tls config, unknown field ["suites"]`),
|
||||||
pedanticErr: errors.New(`unknown field "suites"`),
|
pedanticErr: errors.New(`unknown field "suites"`),
|
||||||
errorLine: 8,
|
errorLine: 8,
|
||||||
|
errorPos: 7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when unknown option is in cluster config with defined routes",
|
name: "when unknown option is in cluster config with defined routes",
|
||||||
config: `
|
config: `
|
||||||
cluster {
|
cluster {
|
||||||
port = 6222
|
port = 6222
|
||||||
routes = [
|
routes = [
|
||||||
nats://127.0.0.1:6222
|
nats://127.0.0.1:6222
|
||||||
]
|
]
|
||||||
peers = []
|
peers = []
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "peers"`),
|
pedanticErr: errors.New(`unknown field "peers"`),
|
||||||
errorLine: 7,
|
errorLine: 7,
|
||||||
|
errorPos: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when used as variable in authorization block it should not be considered as unknown field",
|
name: "when used as variable in authorization block it should not be considered as unknown field",
|
||||||
@@ -425,15 +445,16 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`unknown field "unused"`),
|
pedanticErr: errors.New(`unknown field "unused"`),
|
||||||
errorLine: 27,
|
errorLine: 27,
|
||||||
|
errorPos: 5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when used as variable in top level config it should not be considered as unknown field",
|
name: "when used as variable in top level config it should not be considered as unknown field",
|
||||||
config: `
|
config: `
|
||||||
monitoring_port = 8222
|
monitoring_port = 8222
|
||||||
|
|
||||||
http_port = $monitoring_port
|
http_port = $monitoring_port
|
||||||
|
|
||||||
port = 4222
|
port = 4222
|
||||||
`,
|
`,
|
||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: nil,
|
pedanticErr: nil,
|
||||||
@@ -441,32 +462,33 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "when used as variable in cluster config it should not be considered as unknown field",
|
name: "when used as variable in cluster config it should not be considered as unknown field",
|
||||||
config: `
|
config: `
|
||||||
cluster {
|
cluster {
|
||||||
clustering_port = 6222
|
clustering_port = 6222
|
||||||
port = $clustering_port
|
port = $clustering_port
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: nil,
|
pedanticErr: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "when setting permissions within cluster authorization block",
|
name: "when setting permissions within cluster authorization block",
|
||||||
config: `
|
config: `
|
||||||
cluster {
|
cluster {
|
||||||
authorization {
|
authorization {
|
||||||
permissions = {
|
permissions = {
|
||||||
publish = { allow = ["foo", "bar"] }
|
publish = { allow = ["foo", "bar"] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
permissions = {
|
permissions = {
|
||||||
publish = { deny = ["foo", "bar"] }
|
publish = { deny = ["foo", "bar"] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
defaultErr: nil,
|
defaultErr: nil,
|
||||||
pedanticErr: errors.New(`invalid use of field "authorization"`),
|
pedanticErr: errors.New(`invalid use of field "authorization"`),
|
||||||
errorLine: 7,
|
errorLine: 3,
|
||||||
|
errorPos: 5,
|
||||||
reason: `setting "permissions" within cluster authorization block is deprecated`,
|
reason: `setting "permissions" within cluster authorization block is deprecated`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -498,7 +520,7 @@ func TestConfigCheck(t *testing.T) {
|
|||||||
err := checkConfig(conf, true)
|
err := checkConfig(conf, true)
|
||||||
expectedErr := test.pedanticErr
|
expectedErr := test.pedanticErr
|
||||||
if err != nil && expectedErr != nil {
|
if err != nil && expectedErr != nil {
|
||||||
msg := fmt.Sprintf("%s in %s:%d", expectedErr.Error(), conf, test.errorLine)
|
msg := fmt.Sprintf("%s in %s:%d:%d", expectedErr.Error(), conf, test.errorLine, test.errorPos)
|
||||||
if test.reason != "" {
|
if test.reason != "" {
|
||||||
msg += ": " + test.reason
|
msg += ": " + test.reason
|
||||||
}
|
}
|
||||||
@@ -528,7 +550,7 @@ func TestConfigCheckIncludes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err := opts.ProcessConfigFile("./configs/include_conf_check_a.conf")
|
err := opts.ProcessConfigFile("./configs/include_conf_check_a.conf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error processing include files with configuration check enabled: %s", err)
|
t.Errorf("Unexpected error processing include files with configuration check enabled: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
opts = &Options{
|
opts = &Options{
|
||||||
@@ -536,9 +558,9 @@ func TestConfigCheckIncludes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err = opts.ProcessConfigFile("./configs/include_bad_conf_check_a.conf")
|
err = opts.ProcessConfigFile("./configs/include_bad_conf_check_a.conf")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error processing include files with configuration check enabled: %s", err)
|
t.Errorf("Expected error processing include files with configuration check enabled: %v", err)
|
||||||
}
|
}
|
||||||
expectedErr := errors.New(`unknown field "monitoring_port" in configs/include_bad_conf_check_b.conf:2`)
|
expectedErr := errors.New(`unknown field "monitoring_port" in configs/include_bad_conf_check_b.conf:10:19`)
|
||||||
if err != nil && expectedErr != nil && err.Error() != expectedErr.Error() {
|
if err != nil && expectedErr != nil && err.Error() != expectedErr.Error() {
|
||||||
t.Errorf("Expected %q, got %q", expectedErr.Error(), err.Error())
|
t.Errorf("Expected %q, got %q", expectedErr.Error(), err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
|
|
||||||
monitoring_port = 8222
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
monitoring_port = 8222
|
||||||
|
|
||||||
include "include_conf_check_c.conf"
|
include "include_conf_check_c.conf"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
monitoring_port = 8222
|
monitoring_port = 8222
|
||||||
|
|
||||||
include "include_conf_check_c.conf"
|
include "include_conf_check_c.conf"
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ type token interface {
|
|||||||
Line() int
|
Line() int
|
||||||
IsUsedVariable() bool
|
IsUsedVariable() bool
|
||||||
SourceFile() string
|
SourceFile() string
|
||||||
|
Position() int
|
||||||
}
|
}
|
||||||
|
|
||||||
type unknownConfigFieldErr struct {
|
type unknownConfigFieldErr struct {
|
||||||
@@ -207,7 +208,7 @@ type unknownConfigFieldErr struct {
|
|||||||
func (e *unknownConfigFieldErr) Error() string {
|
func (e *unknownConfigFieldErr) Error() string {
|
||||||
msg := fmt.Sprintf("unknown field %q", e.field)
|
msg := fmt.Sprintf("unknown field %q", e.field)
|
||||||
if e.token != nil {
|
if e.token != nil {
|
||||||
return msg + fmt.Sprintf(" in %s:%d", e.configFile, e.token.Line())
|
return msg + fmt.Sprintf(" in %s:%d:%d", e.configFile, e.token.Line(), e.token.Position())
|
||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
@@ -222,7 +223,7 @@ type configWarningErr struct {
|
|||||||
func (e *configWarningErr) Error() string {
|
func (e *configWarningErr) Error() string {
|
||||||
msg := fmt.Sprintf("invalid use of field %q", e.field)
|
msg := fmt.Sprintf("invalid use of field %q", e.field)
|
||||||
if e.token != nil {
|
if e.token != nil {
|
||||||
msg += fmt.Sprintf(" in %s:%d", e.configFile, e.token.Line())
|
msg += fmt.Sprintf(" in %s:%d:%d", e.configFile, e.token.Line(), e.token.Position())
|
||||||
}
|
}
|
||||||
msg += ": " + e.reason
|
msg += ": " + e.reason
|
||||||
return msg
|
return msg
|
||||||
|
|||||||
Reference in New Issue
Block a user