registry_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package v1alpha1
  14. import (
  15. "reflect"
  16. "testing"
  17. "k8s.io/apimachinery/pkg/runtime"
  18. )
  19. func TestDecodeInto(t *testing.T) {
  20. type PluginFooConfig struct {
  21. FooTest string `json:"fooTest,omitempty"`
  22. }
  23. tests := []struct {
  24. name string
  25. args *runtime.Unknown
  26. expected PluginFooConfig
  27. }{
  28. {
  29. name: "test decode for JSON config",
  30. args: &runtime.Unknown{
  31. ContentType: runtime.ContentTypeJSON,
  32. Raw: []byte(`{
  33. "fooTest": "test decode"
  34. }`),
  35. },
  36. expected: PluginFooConfig{
  37. FooTest: "test decode",
  38. },
  39. },
  40. {
  41. name: "test decode for YAML config",
  42. args: &runtime.Unknown{
  43. ContentType: runtime.ContentTypeYAML,
  44. Raw: []byte(`fooTest: "test decode"`),
  45. },
  46. expected: PluginFooConfig{
  47. FooTest: "test decode",
  48. },
  49. },
  50. }
  51. for _, test := range tests {
  52. t.Run(test.name, func(t *testing.T) {
  53. var pluginFooConf PluginFooConfig
  54. if err := DecodeInto(test.args, &pluginFooConf); err != nil {
  55. t.Errorf("DecodeInto(): failed to decode args %+v: %v", test.args, err)
  56. }
  57. if !reflect.DeepEqual(test.expected, pluginFooConf) {
  58. t.Errorf("DecodeInto(): failed to decode plugin config, expected: %+v, got: %+v",
  59. test.expected, pluginFooConf)
  60. }
  61. })
  62. }
  63. }
  64. // isRegistryEqual compares two registries for equality. This function is used in place of
  65. // reflect.DeepEqual() and cmp() as they don't compare function values.
  66. func isRegistryEqual(registryX, registryY Registry) bool {
  67. for name, pluginFactory := range registryY {
  68. if val, ok := registryX[name]; ok {
  69. if reflect.ValueOf(pluginFactory) != reflect.ValueOf(val) {
  70. // pluginFactory functions are not the same.
  71. return false
  72. }
  73. } else {
  74. // registryY contains an entry that is not present in registryX
  75. return false
  76. }
  77. }
  78. for name := range registryX {
  79. if _, ok := registryY[name]; !ok {
  80. // registryX contains an entry that is not present in registryY
  81. return false
  82. }
  83. }
  84. return true
  85. }
  86. type mockNoopPlugin struct{}
  87. func (p *mockNoopPlugin) Name() string {
  88. return "MockNoop"
  89. }
  90. func NewMockNoopPluginFactory() PluginFactory {
  91. return func(_ *runtime.Unknown, _ FrameworkHandle) (Plugin, error) {
  92. return &mockNoopPlugin{}, nil
  93. }
  94. }
  95. func TestMerge(t *testing.T) {
  96. tests := []struct {
  97. name string
  98. primaryRegistry Registry
  99. registryToMerge Registry
  100. expected Registry
  101. shouldError bool
  102. }{
  103. {
  104. name: "valid Merge",
  105. primaryRegistry: Registry{
  106. "pluginFactory1": NewMockNoopPluginFactory(),
  107. },
  108. registryToMerge: Registry{
  109. "pluginFactory2": NewMockNoopPluginFactory(),
  110. },
  111. expected: Registry{
  112. "pluginFactory1": NewMockNoopPluginFactory(),
  113. "pluginFactory2": NewMockNoopPluginFactory(),
  114. },
  115. shouldError: false,
  116. },
  117. {
  118. name: "Merge duplicate factories",
  119. primaryRegistry: Registry{
  120. "pluginFactory1": NewMockNoopPluginFactory(),
  121. },
  122. registryToMerge: Registry{
  123. "pluginFactory1": NewMockNoopPluginFactory(),
  124. },
  125. expected: Registry{
  126. "pluginFactory1": NewMockNoopPluginFactory(),
  127. },
  128. shouldError: true,
  129. },
  130. }
  131. for _, scenario := range tests {
  132. t.Run(scenario.name, func(t *testing.T) {
  133. err := scenario.primaryRegistry.Merge(scenario.registryToMerge)
  134. if (err == nil) == scenario.shouldError {
  135. t.Errorf("Merge() shouldError is: %v, however err is: %v.", scenario.shouldError, err)
  136. return
  137. }
  138. if !isRegistryEqual(scenario.expected, scenario.primaryRegistry) {
  139. t.Errorf("Merge(). Expected %v. Got %v instead.", scenario.expected, scenario.primaryRegistry)
  140. }
  141. })
  142. }
  143. }
  144. func TestRegister(t *testing.T) {
  145. tests := []struct {
  146. name string
  147. registry Registry
  148. nameToRegister string
  149. factoryToRegister PluginFactory
  150. expected Registry
  151. shouldError bool
  152. }{
  153. {
  154. name: "valid Register",
  155. registry: Registry{},
  156. nameToRegister: "pluginFactory1",
  157. factoryToRegister: NewMockNoopPluginFactory(),
  158. expected: Registry{
  159. "pluginFactory1": NewMockNoopPluginFactory(),
  160. },
  161. shouldError: false,
  162. },
  163. {
  164. name: "Register duplicate factories",
  165. registry: Registry{
  166. "pluginFactory1": NewMockNoopPluginFactory(),
  167. },
  168. nameToRegister: "pluginFactory1",
  169. factoryToRegister: NewMockNoopPluginFactory(),
  170. expected: Registry{
  171. "pluginFactory1": NewMockNoopPluginFactory(),
  172. },
  173. shouldError: true,
  174. },
  175. }
  176. for _, scenario := range tests {
  177. t.Run(scenario.name, func(t *testing.T) {
  178. err := scenario.registry.Register(scenario.nameToRegister, scenario.factoryToRegister)
  179. if (err == nil) == scenario.shouldError {
  180. t.Errorf("Register() shouldError is: %v however err is: %v.", scenario.shouldError, err)
  181. return
  182. }
  183. if !isRegistryEqual(scenario.expected, scenario.registry) {
  184. t.Errorf("Register(). Expected %v. Got %v instead.", scenario.expected, scenario.registry)
  185. }
  186. })
  187. }
  188. }
  189. func TestUnregister(t *testing.T) {
  190. tests := []struct {
  191. name string
  192. registry Registry
  193. nameToUnregister string
  194. expected Registry
  195. shouldError bool
  196. }{
  197. {
  198. name: "valid Unregister",
  199. registry: Registry{
  200. "pluginFactory1": NewMockNoopPluginFactory(),
  201. "pluginFactory2": NewMockNoopPluginFactory(),
  202. },
  203. nameToUnregister: "pluginFactory1",
  204. expected: Registry{
  205. "pluginFactory2": NewMockNoopPluginFactory(),
  206. },
  207. shouldError: false,
  208. },
  209. {
  210. name: "Unregister non-existent plugin factory",
  211. registry: Registry{},
  212. nameToUnregister: "pluginFactory1",
  213. expected: Registry{},
  214. shouldError: true,
  215. },
  216. }
  217. for _, scenario := range tests {
  218. t.Run(scenario.name, func(t *testing.T) {
  219. err := scenario.registry.Unregister(scenario.nameToUnregister)
  220. if (err == nil) == scenario.shouldError {
  221. t.Errorf("Unregister() shouldError is: %v however err is: %v.", scenario.shouldError, err)
  222. return
  223. }
  224. if !isRegistryEqual(scenario.expected, scenario.registry) {
  225. t.Errorf("Unregister(). Expected %v. Got %v instead.", scenario.expected, scenario.registry)
  226. }
  227. })
  228. }
  229. }