config_test.go 6.4 KB

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