provider_test.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. Copyright © The ESO 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. https://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 barbican
  14. import (
  15. "context"
  16. "testing"
  17. "github.com/stretchr/testify/assert"
  18. corev1 "k8s.io/api/core/v1"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  21. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  22. esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
  23. )
  24. const (
  25. testAuthURL = "https://keystone.example.com/v3"
  26. testTenantName = "test-tenant"
  27. testDomainName = "default"
  28. testRegion = "RegionOne"
  29. testUsername = "test-user"
  30. testPassword = "test-password"
  31. testSecretName = "barbican-creds"
  32. testNamespace = "default"
  33. )
  34. type validateStoreTestCase struct {
  35. name string
  36. store esv1.GenericStore
  37. expectError bool
  38. errorMsg string
  39. }
  40. func TestProviderCapabilities(t *testing.T) {
  41. provider := &Provider{}
  42. capabilities := provider.Capabilities()
  43. assert.Equal(t, esv1.SecretStoreReadOnly, capabilities)
  44. }
  45. func TestValidateStore(t *testing.T) {
  46. provider := &Provider{}
  47. testCases := []validateStoreTestCase{
  48. {
  49. name: "nil store should return error",
  50. store: nil,
  51. expectError: true,
  52. errorMsg: "store is nil",
  53. },
  54. {
  55. name: "valid store should pass validation",
  56. store: makeValidSecretStore(),
  57. expectError: false,
  58. },
  59. }
  60. for _, tc := range testCases {
  61. t.Run(tc.name, func(t *testing.T) {
  62. warnings, err := provider.ValidateStore(tc.store)
  63. if tc.expectError {
  64. assert.Error(t, err)
  65. assert.Contains(t, err.Error(), tc.errorMsg)
  66. assert.Nil(t, warnings)
  67. } else {
  68. assert.NoError(t, err)
  69. assert.Nil(t, warnings)
  70. }
  71. })
  72. }
  73. }
  74. func TestGetProvider(t *testing.T) {
  75. testCases := []struct {
  76. name string
  77. store esv1.GenericStore
  78. expectError bool
  79. errorMsg string
  80. }{
  81. {
  82. name: "valid store with barbican provider",
  83. store: makeValidSecretStore(),
  84. expectError: false,
  85. },
  86. {
  87. name: "nil provider should return error",
  88. store: makeSecretStoreWithNilProvider(),
  89. expectError: true,
  90. errorMsg: "provider barbican is nil",
  91. },
  92. {
  93. name: "nil barbican provider should return error",
  94. store: makeSecretStoreWithNilBarbican(),
  95. expectError: true,
  96. errorMsg: "provider barbican is nil",
  97. },
  98. }
  99. for _, tc := range testCases {
  100. t.Run(tc.name, func(t *testing.T) {
  101. provider, err := getProvider(tc.store)
  102. if tc.expectError {
  103. assert.Error(t, err)
  104. assert.Contains(t, err.Error(), tc.errorMsg)
  105. assert.Nil(t, provider)
  106. } else {
  107. assert.NoError(t, err)
  108. assert.NotNil(t, provider)
  109. assert.Equal(t, testAuthURL, provider.AuthURL)
  110. assert.Equal(t, testTenantName, provider.TenantName)
  111. assert.Equal(t, testDomainName, provider.DomainName)
  112. assert.Equal(t, testRegion, provider.Region)
  113. }
  114. })
  115. }
  116. }
  117. func TestNewClient(t *testing.T) {
  118. testCases := []struct {
  119. name string
  120. store esv1.GenericStore
  121. kube *clientfake.ClientBuilder
  122. expectError bool
  123. errorMsg string
  124. }{
  125. {
  126. name: "missing authURL should return error",
  127. store: makeSecretStoreWithMissingAuthURL(),
  128. kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
  129. expectError: true,
  130. errorMsg: "missing required field",
  131. },
  132. {
  133. name: "username as value should pass",
  134. store: makeSecretStoreWithValueUsername(),
  135. kube: clientfake.NewClientBuilder().WithObjects(makeValidSecretWithNoUsername()),
  136. expectError: false,
  137. },
  138. {
  139. name: "username as value and secret should pass",
  140. store: makeSecretStoreWithValueUsername(),
  141. kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
  142. expectError: false,
  143. },
  144. {
  145. name: "missing username secret should return error",
  146. store: makeValidSecretStore(),
  147. kube: clientfake.NewClientBuilder(),
  148. expectError: true,
  149. errorMsg: "missing required field",
  150. },
  151. {
  152. name: "missing password in secret should return error",
  153. store: makeValidSecretStore(),
  154. kube: clientfake.NewClientBuilder().WithObjects(makeSecretWithMissingPassword()),
  155. expectError: true,
  156. errorMsg: "missing required field",
  157. },
  158. {
  159. name: "nil barbican provider should return error",
  160. store: makeSecretStoreWithNilBarbican(),
  161. kube: clientfake.NewClientBuilder().WithObjects(makeValidSecret()),
  162. expectError: true,
  163. errorMsg: "provider barbican is nil",
  164. },
  165. }
  166. for _, tc := range testCases {
  167. t.Run(tc.name, func(t *testing.T) {
  168. provider := &Provider{}
  169. fakeClient := tc.kube.Build()
  170. // Note: This test will fail when trying to actually connect to OpenStack
  171. // In a real test environment, we would need to mock the OpenStack client
  172. _, err := provider.NewClient(context.Background(), tc.store, fakeClient, testNamespace)
  173. if tc.expectError {
  174. assert.Error(t, err)
  175. assert.Contains(t, err.Error(), tc.errorMsg)
  176. } else {
  177. // This would only pass with proper OpenStack mocking
  178. assert.Error(t, err) // We expect an error due to missing OpenStack mock
  179. }
  180. })
  181. }
  182. }
  183. // Helper functions to create test fixtures
  184. func makeValidSecretStore() *esv1.SecretStore {
  185. return &esv1.SecretStore{
  186. ObjectMeta: metav1.ObjectMeta{
  187. Name: "test-store",
  188. Namespace: testNamespace,
  189. },
  190. Spec: esv1.SecretStoreSpec{
  191. Provider: &esv1.SecretStoreProvider{
  192. Barbican: &esv1.BarbicanProvider{
  193. AuthURL: testAuthURL,
  194. TenantName: testTenantName,
  195. DomainName: testDomainName,
  196. Region: testRegion,
  197. Auth: esv1.BarbicanAuth{
  198. Username: esv1.BarbicanProviderUsernameRef{
  199. SecretRef: &esmeta.SecretKeySelector{
  200. Name: testSecretName,
  201. Key: "username",
  202. },
  203. },
  204. Password: esv1.BarbicanProviderPasswordRef{
  205. SecretRef: &esmeta.SecretKeySelector{
  206. Name: testSecretName,
  207. Key: "password",
  208. },
  209. },
  210. },
  211. },
  212. },
  213. },
  214. }
  215. }
  216. func makeSecretStoreWithValueUsername() *esv1.SecretStore {
  217. store := makeValidSecretStore()
  218. store.Spec.Provider.Barbican.Auth.Username = esv1.BarbicanProviderUsernameRef{
  219. Value: testUsername,
  220. }
  221. return store
  222. }
  223. func makeSecretStoreWithNilProvider() *esv1.SecretStore {
  224. store := makeValidSecretStore()
  225. store.Spec.Provider = nil
  226. return store
  227. }
  228. func makeSecretStoreWithNilBarbican() *esv1.SecretStore {
  229. store := makeValidSecretStore()
  230. store.Spec.Provider.Barbican = nil
  231. return store
  232. }
  233. func makeSecretStoreWithMissingAuthURL() *esv1.SecretStore {
  234. store := makeValidSecretStore()
  235. store.Spec.Provider.Barbican.AuthURL = ""
  236. return store
  237. }
  238. func makeValidSecret() *corev1.Secret {
  239. return &corev1.Secret{
  240. ObjectMeta: metav1.ObjectMeta{
  241. Name: testSecretName,
  242. Namespace: testNamespace,
  243. },
  244. Data: map[string][]byte{
  245. "username": []byte(testUsername),
  246. "password": []byte(testPassword),
  247. },
  248. }
  249. }
  250. func makeValidSecretWithNoUsername() *corev1.Secret {
  251. return &corev1.Secret{
  252. ObjectMeta: metav1.ObjectMeta{
  253. Name: testSecretName,
  254. Namespace: testNamespace,
  255. },
  256. Data: map[string][]byte{
  257. "password": []byte(testPassword),
  258. },
  259. }
  260. }
  261. func makeSecretWithMissingPassword() *corev1.Secret {
  262. return &corev1.Secret{
  263. ObjectMeta: metav1.ObjectMeta{
  264. Name: testSecretName,
  265. Namespace: testNamespace,
  266. },
  267. Data: map[string][]byte{
  268. "username": []byte(testUsername),
  269. // missing password key
  270. },
  271. }
  272. }