github.com/paketo-buildpacks/packit@v1.3.2-0.20211206231111-86b75c657449/servicebindings/resolver_test.go (about) 1 package servicebindings_test 2 3 import ( 4 "os" 5 "path/filepath" 6 "testing" 7 8 . "github.com/onsi/gomega" 9 "github.com/sclevine/spec" 10 11 "github.com/paketo-buildpacks/packit/servicebindings" 12 ) 13 14 func testResolver(t *testing.T, context spec.G, it spec.S) { 15 var Expect = NewWithT(t).Expect 16 17 context("binding root precedence", func() { 18 var ( 19 bindingRootK8s string 20 bindingRootCNB string 21 platformDir string 22 ) 23 24 it.Before(func() { 25 var err error 26 27 bindingRootK8s, err = os.MkdirTemp("", "bindings-k8s") 28 Expect(err).NotTo(HaveOccurred()) 29 30 err = os.MkdirAll(filepath.Join(bindingRootK8s, "some-binding"), os.ModePerm) 31 Expect(err).NotTo(HaveOccurred()) 32 33 err = os.WriteFile(filepath.Join(bindingRootK8s, "some-binding", "type"), []byte("some-type"), os.ModePerm) 34 Expect(err).NotTo(HaveOccurred()) 35 36 bindingRootCNB, err = os.MkdirTemp("", "bindings-cnb") 37 Expect(err).NotTo(HaveOccurred()) 38 39 err = os.MkdirAll(filepath.Join(bindingRootCNB, "some-binding"), os.ModePerm) 40 Expect(err).NotTo(HaveOccurred()) 41 42 err = os.WriteFile(filepath.Join(bindingRootCNB, "some-binding", "type"), []byte("some-type"), os.ModePerm) 43 Expect(err).NotTo(HaveOccurred()) 44 45 platformDir, err = os.MkdirTemp("", "bindings-platform") 46 Expect(err).NotTo(HaveOccurred()) 47 48 err = os.MkdirAll(filepath.Join(platformDir, "bindings", "some-binding"), os.ModePerm) 49 Expect(err).NotTo(HaveOccurred()) 50 51 err = os.WriteFile(filepath.Join(platformDir, "bindings", "some-binding", "type"), []byte("some-type"), os.ModePerm) 52 Expect(err).NotTo(HaveOccurred()) 53 }) 54 55 context("SERVICE_BINDING_ROOT env var is set", func() { 56 it.Before(func() { 57 Expect(os.Setenv("SERVICE_BINDING_ROOT", bindingRootK8s)).To(Succeed()) 58 }) 59 60 context("CNB_BINDINGS env var is set", func() { 61 it.Before(func() { 62 Expect(os.Setenv("CNB_BINDINGS", bindingRootCNB)).To(Succeed()) 63 }) 64 65 it("resolves bindings from SERVICE_BINDING_ROOT", func() { 66 resolver := servicebindings.NewResolver() 67 68 bindings, err := resolver.Resolve("some-type", "", platformDir) 69 Expect(err).NotTo(HaveOccurred()) 70 Expect(bindings).To(ConsistOf( 71 servicebindings.Binding{ 72 Name: "some-binding", 73 Path: filepath.Join(bindingRootK8s, "some-binding"), 74 Type: "some-type", 75 Entries: map[string]*servicebindings.Entry{}, 76 }, 77 )) 78 }) 79 }) 80 81 context("CNB_BINDINGS env var is not set", func() { 82 it.Before(func() { 83 Expect(os.Unsetenv("CNB_BINDINGS")).To(Succeed()) 84 }) 85 86 it("resolves bindings from SERVICE_BINDING_ROOT", func() { 87 resolver := servicebindings.NewResolver() 88 89 bindings, err := resolver.Resolve("some-type", "", platformDir) 90 Expect(err).NotTo(HaveOccurred()) 91 Expect(bindings).To(ConsistOf( 92 servicebindings.Binding{ 93 Name: "some-binding", 94 Path: filepath.Join(bindingRootK8s, "some-binding"), 95 Type: "some-type", 96 Entries: map[string]*servicebindings.Entry{}, 97 }, 98 )) 99 }) 100 }) 101 }) 102 103 context("SERVICE_BINDING_ROOT env var is not set", func() { 104 it.Before(func() { 105 Expect(os.Unsetenv("SERVICE_BINDING_ROOT")).To(Succeed()) 106 }) 107 108 context("CNB_BINDINGS env var is set", func() { 109 it.Before(func() { 110 Expect(os.Setenv("CNB_BINDINGS", bindingRootCNB)).To(Succeed()) 111 }) 112 113 it("resolves bindings from CNB_BINDINGS", func() { 114 resolver := servicebindings.NewResolver() 115 116 bindings, err := resolver.Resolve("some-type", "", platformDir) 117 Expect(err).NotTo(HaveOccurred()) 118 Expect(bindings).To(ConsistOf( 119 servicebindings.Binding{ 120 Name: "some-binding", 121 Path: filepath.Join(bindingRootCNB, "some-binding"), 122 Type: "some-type", 123 Entries: map[string]*servicebindings.Entry{}, 124 }, 125 )) 126 }) 127 }) 128 129 context("CNB_BINDINGS env var is not set", func() { 130 it.Before(func() { 131 Expect(os.Unsetenv("CNB_BINDINGS")).To(Succeed()) 132 }) 133 134 it("resolves bindings from platform dir", func() { 135 resolver := servicebindings.NewResolver() 136 137 bindings, err := resolver.Resolve("some-type", "", platformDir) 138 Expect(err).NotTo(HaveOccurred()) 139 Expect(bindings).To(ConsistOf( 140 servicebindings.Binding{ 141 Name: "some-binding", 142 Path: filepath.Join(platformDir, "bindings", "some-binding"), 143 Type: "some-type", 144 Entries: map[string]*servicebindings.Entry{}, 145 }, 146 )) 147 }) 148 }) 149 }) 150 }) 151 152 context("resolving bindings", func() { 153 var bindingRoot string 154 var resolver *servicebindings.Resolver 155 156 it.Before(func() { 157 var err error 158 bindingRoot, err = os.MkdirTemp("", "bindings") 159 Expect(err).NotTo(HaveOccurred()) 160 Expect(os.Setenv("SERVICE_BINDING_ROOT", bindingRoot)).To(Succeed()) 161 162 resolver = servicebindings.NewResolver() 163 164 err = os.MkdirAll(filepath.Join(bindingRoot, "binding-1A"), os.ModePerm) 165 Expect(err).NotTo(HaveOccurred()) 166 167 err = os.WriteFile(filepath.Join(bindingRoot, "binding-1A", "type"), []byte("type-1"), os.ModePerm) 168 Expect(err).NotTo(HaveOccurred()) 169 170 err = os.WriteFile(filepath.Join(bindingRoot, "binding-1A", "provider"), []byte("provider-1A"), os.ModePerm) 171 Expect(err).NotTo(HaveOccurred()) 172 173 err = os.WriteFile(filepath.Join(bindingRoot, "binding-1A", "username"), nil, os.ModePerm) 174 Expect(err).NotTo(HaveOccurred()) 175 176 err = os.WriteFile(filepath.Join(bindingRoot, "binding-1A", "password"), nil, os.ModePerm) 177 Expect(err).NotTo(HaveOccurred()) 178 179 err = os.MkdirAll(filepath.Join(bindingRoot, "binding-1B"), os.ModePerm) 180 Expect(err).NotTo(HaveOccurred()) 181 182 err = os.WriteFile(filepath.Join(bindingRoot, "binding-1B", "type"), []byte("type-1"), os.ModePerm) 183 Expect(err).NotTo(HaveOccurred()) 184 185 err = os.WriteFile(filepath.Join(bindingRoot, "binding-1B", "provider"), []byte("provider-1B"), os.ModePerm) 186 Expect(err).NotTo(HaveOccurred()) 187 188 err = os.WriteFile(filepath.Join(bindingRoot, "binding-1B", "username"), nil, os.ModePerm) 189 Expect(err).NotTo(HaveOccurred()) 190 191 err = os.WriteFile(filepath.Join(bindingRoot, "binding-1B", "password"), nil, os.ModePerm) 192 Expect(err).NotTo(HaveOccurred()) 193 194 err = os.MkdirAll(filepath.Join(bindingRoot, "binding-2"), os.ModePerm) 195 Expect(err).NotTo(HaveOccurred()) 196 197 err = os.WriteFile(filepath.Join(bindingRoot, "binding-2", "type"), []byte("type-2"), os.ModePerm) 198 Expect(err).NotTo(HaveOccurred()) 199 200 err = os.WriteFile(filepath.Join(bindingRoot, "binding-2", "provider"), []byte("provider-2"), os.ModePerm) 201 Expect(err).NotTo(HaveOccurred()) 202 203 err = os.WriteFile(filepath.Join(bindingRoot, "binding-2", "username"), nil, os.ModePerm) 204 Expect(err).NotTo(HaveOccurred()) 205 206 err = os.WriteFile(filepath.Join(bindingRoot, "binding-2", "password"), nil, os.ModePerm) 207 Expect(err).NotTo(HaveOccurred()) 208 }) 209 210 it.After(func() { 211 Expect(os.RemoveAll(bindingRoot)).To(Succeed()) 212 Expect(os.Unsetenv("SERVICE_BINDING_ROOT")).To(Succeed()) 213 }) 214 215 context("Resolve", func() { 216 it("resolves by type only (case-insensitive)", func() { 217 bindings, err := resolver.Resolve("TyPe-1", "", "") 218 Expect(err).NotTo(HaveOccurred()) 219 220 Expect(bindings).To(ConsistOf( 221 servicebindings.Binding{ 222 Name: "binding-1A", 223 Path: filepath.Join(bindingRoot, "binding-1A"), 224 Type: "type-1", 225 Provider: "provider-1A", 226 Entries: map[string]*servicebindings.Entry{ 227 "username": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-1A", "username")), 228 "password": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-1A", "password")), 229 }, 230 }, 231 servicebindings.Binding{ 232 Name: "binding-1B", 233 Path: filepath.Join(bindingRoot, "binding-1B"), 234 Type: "type-1", 235 Provider: "provider-1B", 236 Entries: map[string]*servicebindings.Entry{ 237 "username": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-1B", "username")), 238 "password": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-1B", "password")), 239 }, 240 }, 241 )) 242 }) 243 244 it("resolves by type and provider (case-insensitive)", func() { 245 bindings, err := resolver.Resolve("TyPe-1", "PrOvIdEr-1B", "") 246 Expect(err).NotTo(HaveOccurred()) 247 248 Expect(bindings).To(ConsistOf( 249 servicebindings.Binding{ 250 Name: "binding-1B", 251 Path: filepath.Join(bindingRoot, "binding-1B"), 252 Type: "type-1", 253 Provider: "provider-1B", 254 Entries: map[string]*servicebindings.Entry{ 255 "username": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-1B", "username")), 256 "password": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-1B", "password")), 257 }, 258 }, 259 )) 260 }) 261 262 it("allows 'metadata' as an entry name", func() { 263 err := os.MkdirAll(filepath.Join(bindingRoot, "binding-metadata"), os.ModePerm) 264 Expect(err).NotTo(HaveOccurred()) 265 266 err = os.WriteFile(filepath.Join(bindingRoot, "binding-metadata", "type"), []byte("type-metadata"), os.ModePerm) 267 Expect(err).NotTo(HaveOccurred()) 268 269 err = os.WriteFile(filepath.Join(bindingRoot, "binding-metadata", "metadata"), nil, os.ModePerm) 270 Expect(err).NotTo(HaveOccurred()) 271 272 bindings, err := resolver.Resolve("type-metadata", "", "") 273 Expect(err).NotTo(HaveOccurred()) 274 275 Expect(bindings).To(ConsistOf( 276 servicebindings.Binding{ 277 Name: "binding-metadata", 278 Path: filepath.Join(bindingRoot, "binding-metadata"), 279 Type: "type-metadata", 280 Entries: map[string]*servicebindings.Entry{ 281 "metadata": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-metadata", "metadata")), 282 }, 283 }, 284 )) 285 }) 286 287 it("returns an error if type is missing", func() { 288 err := os.MkdirAll(filepath.Join(bindingRoot, "bad-binding"), os.ModePerm) 289 Expect(err).NotTo(HaveOccurred()) 290 291 _, err = resolver.Resolve("bad-type", "", "") 292 Expect(err).To(MatchError(HavePrefix("failed to load bindings from '%s': failed to read binding 'bad-binding': missing 'type'", bindingRoot))) 293 }) 294 295 it("allows provider to be omitted", func() { 296 err := os.MkdirAll(filepath.Join(bindingRoot, "some-binding"), os.ModePerm) 297 Expect(err).NotTo(HaveOccurred()) 298 299 err = os.WriteFile(filepath.Join(bindingRoot, "some-binding", "type"), []byte("some-type"), os.ModePerm) 300 Expect(err).NotTo(HaveOccurred()) 301 302 bindings, err := resolver.Resolve("some-type", "", "") 303 Expect(err).NotTo(HaveOccurred()) 304 305 Expect(bindings).To(ConsistOf( 306 servicebindings.Binding{ 307 Name: "some-binding", 308 Path: filepath.Join(bindingRoot, "some-binding"), 309 Type: "some-type", 310 Provider: "", 311 Entries: map[string]*servicebindings.Entry{}, 312 }, 313 )) 314 }) 315 316 it("returns errors encountered reading files", func() { 317 err := os.MkdirAll(filepath.Join(bindingRoot, "bad-binding"), os.ModePerm) 318 Expect(err).NotTo(HaveOccurred()) 319 320 err = os.WriteFile(filepath.Join(bindingRoot, "bad-binding", "type"), []byte("bad-type"), 000) 321 Expect(err).NotTo(HaveOccurred()) 322 323 _, err = resolver.Resolve("bad-type", "", "") 324 Expect(err).To(MatchError(HavePrefix("failed to load bindings from '%s': failed to read binding 'bad-binding': open %s: permission denied", bindingRoot, filepath.Join(bindingRoot, "bad-binding", "type")))) 325 }) 326 327 it("returns empty list if binding root doesn't exist", func() { 328 Expect(os.RemoveAll(bindingRoot)).To(Succeed()) 329 330 bindings, err := resolver.Resolve("type-1", "", "") 331 Expect(err).NotTo(HaveOccurred()) 332 Expect(bindings).To(BeEmpty()) 333 }) 334 }) 335 336 context("ResolveOne", func() { 337 it("resolves one binding (case-insensitive)", func() { 338 binding, err := resolver.ResolveOne("TyPe-2", "", "") 339 Expect(err).NotTo(HaveOccurred()) 340 Expect(binding).To(Equal(servicebindings.Binding{ 341 Name: "binding-2", 342 Path: filepath.Join(bindingRoot, "binding-2"), 343 Type: "type-2", 344 Provider: "provider-2", 345 Entries: map[string]*servicebindings.Entry{ 346 "username": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-2", "username")), 347 "password": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-2", "password")), 348 }, 349 })) 350 }) 351 352 it("returns an error if no matches", func() { 353 _, err := resolver.ResolveOne("non-existent-type", "non-existent-provider", "") 354 Expect(err).To(MatchError("found 0 bindings for type 'non-existent-type' and provider 'non-existent-provider' but expected exactly 1")) 355 }) 356 357 it("returns an error if more than one match", func() { 358 _, err := resolver.ResolveOne("TyPe-1", "", "") 359 Expect(err).To(MatchError("found 2 bindings for type 'TyPe-1' and provider '' but expected exactly 1")) 360 }) 361 }) 362 363 context("legacy bindings", func() { 364 it("resolves legacy bindings", func() { 365 err := os.MkdirAll(filepath.Join(bindingRoot, "binding-legacy", "metadata"), os.ModePerm) 366 Expect(err).NotTo(HaveOccurred()) 367 368 err = os.MkdirAll(filepath.Join(bindingRoot, "binding-legacy", "secret"), os.ModePerm) 369 Expect(err).NotTo(HaveOccurred()) 370 371 err = os.WriteFile(filepath.Join(bindingRoot, "binding-legacy", "metadata", "kind"), []byte("type-legacy"), os.ModePerm) 372 Expect(err).NotTo(HaveOccurred()) 373 374 err = os.WriteFile(filepath.Join(bindingRoot, "binding-legacy", "metadata", "provider"), []byte("provider-legacy"), os.ModePerm) 375 Expect(err).NotTo(HaveOccurred()) 376 377 err = os.WriteFile(filepath.Join(bindingRoot, "binding-legacy", "metadata", "username"), nil, os.ModePerm) 378 Expect(err).NotTo(HaveOccurred()) 379 380 err = os.WriteFile(filepath.Join(bindingRoot, "binding-legacy", "secret", "password"), nil, os.ModePerm) 381 Expect(err).NotTo(HaveOccurred()) 382 383 bindings, err := resolver.Resolve("type-legacy", "", "") 384 Expect(err).NotTo(HaveOccurred()) 385 386 Expect(bindings).To(ConsistOf( 387 servicebindings.Binding{ 388 Name: "binding-legacy", 389 Path: filepath.Join(bindingRoot, "binding-legacy"), 390 Type: "type-legacy", 391 Provider: "provider-legacy", 392 Entries: map[string]*servicebindings.Entry{ 393 "username": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-legacy", "metadata", "username")), 394 "password": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-legacy", "secret", "password")), 395 }, 396 }, 397 )) 398 }) 399 400 it("allows 'secret' directory to be omitted", func() { 401 err := os.MkdirAll(filepath.Join(bindingRoot, "binding-legacy", "metadata"), os.ModePerm) 402 Expect(err).NotTo(HaveOccurred()) 403 404 err = os.WriteFile(filepath.Join(bindingRoot, "binding-legacy", "metadata", "kind"), []byte("type-legacy"), os.ModePerm) 405 Expect(err).NotTo(HaveOccurred()) 406 407 err = os.WriteFile(filepath.Join(bindingRoot, "binding-legacy", "metadata", "provider"), []byte("provider-legacy"), os.ModePerm) 408 Expect(err).NotTo(HaveOccurred()) 409 410 err = os.WriteFile(filepath.Join(bindingRoot, "binding-legacy", "metadata", "some-key"), nil, os.ModePerm) 411 Expect(err).NotTo(HaveOccurred()) 412 413 bindings, err := resolver.Resolve("type-legacy", "", "") 414 Expect(err).NotTo(HaveOccurred()) 415 416 Expect(bindings).To(ConsistOf( 417 servicebindings.Binding{ 418 Name: "binding-legacy", 419 Path: filepath.Join(bindingRoot, "binding-legacy"), 420 Type: "type-legacy", 421 Provider: "provider-legacy", 422 Entries: map[string]*servicebindings.Entry{ 423 "some-key": servicebindings.NewEntry(filepath.Join(bindingRoot, "binding-legacy", "metadata", "some-key")), 424 }, 425 }, 426 )) 427 }) 428 429 it("returns an error if kind is missing", func() { 430 err := os.MkdirAll(filepath.Join(bindingRoot, "bad-binding", "metadata"), os.ModePerm) 431 Expect(err).NotTo(HaveOccurred()) 432 433 _, err = resolver.Resolve("bad-type", "", "") 434 Expect(err).To(MatchError(HavePrefix("failed to load bindings from '%s': failed to read binding 'bad-binding': missing 'kind'", bindingRoot))) 435 }) 436 437 it("returns an error if provider is missing", func() { 438 err := os.MkdirAll(filepath.Join(bindingRoot, "bad-binding", "metadata"), os.ModePerm) 439 Expect(err).NotTo(HaveOccurred()) 440 441 err = os.WriteFile(filepath.Join(bindingRoot, "bad-binding", "metadata", "kind"), []byte("bad-type"), os.ModePerm) 442 Expect(err).NotTo(HaveOccurred()) 443 444 _, err = resolver.Resolve("bad-type", "", "") 445 Expect(err).To(MatchError(HavePrefix("failed to load bindings from '%s': failed to read binding 'bad-binding': missing 'provider'", bindingRoot))) 446 }) 447 }) 448 }) 449 }