config_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package nebula
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "path/filepath"
  6. "testing"
  7. "time"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. func TestConfig_Load(t *testing.T) {
  11. l := NewTestLogger()
  12. dir, err := ioutil.TempDir("", "config-test")
  13. // invalid yaml
  14. c := NewConfig(l)
  15. ioutil.WriteFile(filepath.Join(dir, "01.yaml"), []byte(" invalid yaml"), 0644)
  16. assert.EqualError(t, c.Load(dir), "yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `invalid...` into map[interface {}]interface {}")
  17. // simple multi config merge
  18. c = NewConfig(l)
  19. os.RemoveAll(dir)
  20. os.Mkdir(dir, 0755)
  21. assert.Nil(t, err)
  22. ioutil.WriteFile(filepath.Join(dir, "01.yaml"), []byte("outer:\n inner: hi"), 0644)
  23. ioutil.WriteFile(filepath.Join(dir, "02.yml"), []byte("outer:\n inner: override\nnew: hi"), 0644)
  24. assert.Nil(t, c.Load(dir))
  25. expected := map[interface{}]interface{}{
  26. "outer": map[interface{}]interface{}{
  27. "inner": "override",
  28. },
  29. "new": "hi",
  30. }
  31. assert.Equal(t, expected, c.Settings)
  32. //TODO: test symlinked file
  33. //TODO: test symlinked directory
  34. }
  35. func TestConfig_Get(t *testing.T) {
  36. l := NewTestLogger()
  37. // test simple type
  38. c := NewConfig(l)
  39. c.Settings["firewall"] = map[interface{}]interface{}{"outbound": "hi"}
  40. assert.Equal(t, "hi", c.Get("firewall.outbound"))
  41. // test complex type
  42. inner := []map[interface{}]interface{}{{"port": "1", "code": "2"}}
  43. c.Settings["firewall"] = map[interface{}]interface{}{"outbound": inner}
  44. assert.EqualValues(t, inner, c.Get("firewall.outbound"))
  45. // test missing
  46. assert.Nil(t, c.Get("firewall.nope"))
  47. }
  48. func TestConfig_GetStringSlice(t *testing.T) {
  49. l := NewTestLogger()
  50. c := NewConfig(l)
  51. c.Settings["slice"] = []interface{}{"one", "two"}
  52. assert.Equal(t, []string{"one", "two"}, c.GetStringSlice("slice", []string{}))
  53. }
  54. func TestConfig_GetBool(t *testing.T) {
  55. l := NewTestLogger()
  56. c := NewConfig(l)
  57. c.Settings["bool"] = true
  58. assert.Equal(t, true, c.GetBool("bool", false))
  59. c.Settings["bool"] = "true"
  60. assert.Equal(t, true, c.GetBool("bool", false))
  61. c.Settings["bool"] = false
  62. assert.Equal(t, false, c.GetBool("bool", true))
  63. c.Settings["bool"] = "false"
  64. assert.Equal(t, false, c.GetBool("bool", true))
  65. c.Settings["bool"] = "Y"
  66. assert.Equal(t, true, c.GetBool("bool", false))
  67. c.Settings["bool"] = "yEs"
  68. assert.Equal(t, true, c.GetBool("bool", false))
  69. c.Settings["bool"] = "N"
  70. assert.Equal(t, false, c.GetBool("bool", true))
  71. c.Settings["bool"] = "nO"
  72. assert.Equal(t, false, c.GetBool("bool", true))
  73. }
  74. func TestConfig_GetAllowList(t *testing.T) {
  75. l := NewTestLogger()
  76. c := NewConfig(l)
  77. c.Settings["allowlist"] = map[interface{}]interface{}{
  78. "192.168.0.0": true,
  79. }
  80. r, err := c.GetAllowList("allowlist", false)
  81. assert.EqualError(t, err, "config `allowlist` has invalid CIDR: 192.168.0.0")
  82. assert.Nil(t, r)
  83. c.Settings["allowlist"] = map[interface{}]interface{}{
  84. "192.168.0.0/16": "abc",
  85. }
  86. r, err = c.GetAllowList("allowlist", false)
  87. assert.EqualError(t, err, "config `allowlist` has invalid value (type string): abc")
  88. c.Settings["allowlist"] = map[interface{}]interface{}{
  89. "192.168.0.0/16": true,
  90. "10.0.0.0/8": false,
  91. }
  92. r, err = c.GetAllowList("allowlist", false)
  93. assert.EqualError(t, err, "config `allowlist` contains both true and false rules, but no default set for 0.0.0.0/0")
  94. c.Settings["allowlist"] = map[interface{}]interface{}{
  95. "0.0.0.0/0": true,
  96. "10.0.0.0/8": false,
  97. "10.42.42.0/24": true,
  98. "fd00::/8": true,
  99. "fd00:fd00::/16": false,
  100. }
  101. r, err = c.GetAllowList("allowlist", false)
  102. assert.EqualError(t, err, "config `allowlist` contains both true and false rules, but no default set for ::/0")
  103. c.Settings["allowlist"] = map[interface{}]interface{}{
  104. "0.0.0.0/0": true,
  105. "10.0.0.0/8": false,
  106. "10.42.42.0/24": true,
  107. }
  108. r, err = c.GetAllowList("allowlist", false)
  109. if assert.NoError(t, err) {
  110. assert.NotNil(t, r)
  111. }
  112. c.Settings["allowlist"] = map[interface{}]interface{}{
  113. "0.0.0.0/0": true,
  114. "10.0.0.0/8": false,
  115. "10.42.42.0/24": true,
  116. "::/0": false,
  117. "fd00::/8": true,
  118. "fd00:fd00::/16": false,
  119. }
  120. r, err = c.GetAllowList("allowlist", false)
  121. if assert.NoError(t, err) {
  122. assert.NotNil(t, r)
  123. }
  124. // Test interface names
  125. c.Settings["allowlist"] = map[interface{}]interface{}{
  126. "interfaces": map[interface{}]interface{}{
  127. `docker.*`: false,
  128. },
  129. }
  130. r, err = c.GetAllowList("allowlist", false)
  131. assert.EqualError(t, err, "config `allowlist` does not support `interfaces`")
  132. c.Settings["allowlist"] = map[interface{}]interface{}{
  133. "interfaces": map[interface{}]interface{}{
  134. `docker.*`: "foo",
  135. },
  136. }
  137. r, err = c.GetAllowList("allowlist", true)
  138. assert.EqualError(t, err, "config `allowlist.interfaces` has invalid value (type string): foo")
  139. c.Settings["allowlist"] = map[interface{}]interface{}{
  140. "interfaces": map[interface{}]interface{}{
  141. `docker.*`: false,
  142. `eth.*`: true,
  143. },
  144. }
  145. r, err = c.GetAllowList("allowlist", true)
  146. assert.EqualError(t, err, "config `allowlist.interfaces` values must all be the same true/false value")
  147. c.Settings["allowlist"] = map[interface{}]interface{}{
  148. "interfaces": map[interface{}]interface{}{
  149. `docker.*`: false,
  150. },
  151. }
  152. r, err = c.GetAllowList("allowlist", true)
  153. if assert.NoError(t, err) {
  154. assert.NotNil(t, r)
  155. }
  156. }
  157. func TestConfig_HasChanged(t *testing.T) {
  158. l := NewTestLogger()
  159. // No reload has occurred, return false
  160. c := NewConfig(l)
  161. c.Settings["test"] = "hi"
  162. assert.False(t, c.HasChanged(""))
  163. // Test key change
  164. c = NewConfig(l)
  165. c.Settings["test"] = "hi"
  166. c.oldSettings = map[interface{}]interface{}{"test": "no"}
  167. assert.True(t, c.HasChanged("test"))
  168. assert.True(t, c.HasChanged(""))
  169. // No key change
  170. c = NewConfig(l)
  171. c.Settings["test"] = "hi"
  172. c.oldSettings = map[interface{}]interface{}{"test": "hi"}
  173. assert.False(t, c.HasChanged("test"))
  174. assert.False(t, c.HasChanged(""))
  175. }
  176. func TestConfig_ReloadConfig(t *testing.T) {
  177. l := NewTestLogger()
  178. done := make(chan bool, 1)
  179. dir, err := ioutil.TempDir("", "config-test")
  180. assert.Nil(t, err)
  181. ioutil.WriteFile(filepath.Join(dir, "01.yaml"), []byte("outer:\n inner: hi"), 0644)
  182. c := NewConfig(l)
  183. assert.Nil(t, c.Load(dir))
  184. assert.False(t, c.HasChanged("outer.inner"))
  185. assert.False(t, c.HasChanged("outer"))
  186. assert.False(t, c.HasChanged(""))
  187. ioutil.WriteFile(filepath.Join(dir, "01.yaml"), []byte("outer:\n inner: ho"), 0644)
  188. c.RegisterReloadCallback(func(c *Config) {
  189. done <- true
  190. })
  191. c.ReloadConfig()
  192. assert.True(t, c.HasChanged("outer.inner"))
  193. assert.True(t, c.HasChanged("outer"))
  194. assert.True(t, c.HasChanged(""))
  195. // Make sure we call the callbacks
  196. select {
  197. case <-done:
  198. case <-time.After(1 * time.Second):
  199. panic("timeout")
  200. }
  201. }