github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/logging/azureblob/azureblob_integration_test.go (about) 1 package azureblob_test 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "strings" 8 "testing" 9 10 "github.com/fastly/go-fastly/v9/fastly" 11 12 "github.com/fastly/cli/pkg/app" 13 "github.com/fastly/cli/pkg/global" 14 "github.com/fastly/cli/pkg/mock" 15 "github.com/fastly/cli/pkg/testutil" 16 ) 17 18 func TestBlobStorageCreate(t *testing.T) { 19 args := testutil.Args 20 scenarios := []struct { 21 args []string 22 api mock.API 23 wantError string 24 wantOutput string 25 }{ 26 { 27 args: args("logging azureblob create --service-id 123 --version 1 --name log --account-name account --container log --sas-token abc --autoclone"), 28 api: mock.API{ 29 ListVersionsFn: testutil.ListVersions, 30 CloneVersionFn: testutil.CloneVersionResult(4), 31 CreateBlobStorageFn: createBlobStorageOK, 32 }, 33 wantOutput: "Created Azure Blob Storage logging endpoint log (service 123 version 4)", 34 }, 35 { 36 args: args("logging azureblob create --service-id 123 --version 1 --name log --account-name account --container log --sas-token abc --autoclone"), 37 api: mock.API{ 38 ListVersionsFn: testutil.ListVersions, 39 CloneVersionFn: testutil.CloneVersionResult(4), 40 CreateBlobStorageFn: createBlobStorageError, 41 }, 42 wantError: errTest.Error(), 43 }, 44 { 45 args: args("logging azureblob create --service-id 123 --version 1 --name log --account-name account --container log --sas-token abc --compression-codec zstd --gzip-level 9 --autoclone"), 46 api: mock.API{ 47 ListVersionsFn: testutil.ListVersions, 48 CloneVersionFn: testutil.CloneVersionResult(4), 49 CreateBlobStorageFn: createBlobStorageError, 50 }, 51 wantError: "error parsing arguments: the --compression-codec flag is mutually exclusive with the --gzip-level flag", 52 }, 53 } 54 for testcaseIdx := range scenarios { 55 testcase := &scenarios[testcaseIdx] 56 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 57 var stdout bytes.Buffer 58 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 59 opts := testutil.MockGlobalData(testcase.args, &stdout) 60 opts.APIClientFactory = mock.APIClient(testcase.api) 61 return opts, nil 62 } 63 err := app.Run(testcase.args, nil) 64 testutil.AssertErrorContains(t, err, testcase.wantError) 65 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 66 }) 67 } 68 } 69 70 func TestBlobStorageList(t *testing.T) { 71 args := testutil.Args 72 scenarios := []struct { 73 args []string 74 api mock.API 75 wantError string 76 wantOutput string 77 }{ 78 { 79 args: args("logging azureblob list --service-id 123 --version 1"), 80 api: mock.API{ 81 ListVersionsFn: testutil.ListVersions, 82 ListBlobStoragesFn: listBlobStoragesOK, 83 }, 84 wantOutput: listBlobStoragesShortOutput, 85 }, 86 { 87 args: args("logging azureblob list --service-id 123 --version 1 --verbose"), 88 api: mock.API{ 89 ListVersionsFn: testutil.ListVersions, 90 ListBlobStoragesFn: listBlobStoragesOK, 91 }, 92 wantOutput: listBlobStoragesVerboseOutput, 93 }, 94 { 95 args: args("logging azureblob list --service-id 123 --version 1 -v"), 96 api: mock.API{ 97 ListVersionsFn: testutil.ListVersions, 98 ListBlobStoragesFn: listBlobStoragesOK, 99 }, 100 wantOutput: listBlobStoragesVerboseOutput, 101 }, 102 { 103 args: args("logging azureblob --verbose list --service-id 123 --version 1"), 104 api: mock.API{ 105 ListVersionsFn: testutil.ListVersions, 106 ListBlobStoragesFn: listBlobStoragesOK, 107 }, 108 wantOutput: listBlobStoragesVerboseOutput, 109 }, 110 { 111 args: args("logging -v azureblob list --service-id 123 --version 1"), 112 api: mock.API{ 113 ListVersionsFn: testutil.ListVersions, 114 ListBlobStoragesFn: listBlobStoragesOK, 115 }, 116 wantOutput: listBlobStoragesVerboseOutput, 117 }, 118 { 119 args: args("logging azureblob list --service-id 123 --version 1"), 120 api: mock.API{ 121 ListVersionsFn: testutil.ListVersions, 122 ListBlobStoragesFn: listBlobStoragesError, 123 }, 124 wantError: errTest.Error(), 125 }, 126 } 127 for testcaseIdx := range scenarios { 128 testcase := &scenarios[testcaseIdx] 129 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 130 var stdout bytes.Buffer 131 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 132 opts := testutil.MockGlobalData(testcase.args, &stdout) 133 opts.APIClientFactory = mock.APIClient(testcase.api) 134 return opts, nil 135 } 136 err := app.Run(testcase.args, nil) 137 testutil.AssertErrorContains(t, err, testcase.wantError) 138 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 139 }) 140 } 141 } 142 143 func TestBlobStorageDescribe(t *testing.T) { 144 args := testutil.Args 145 scenarios := []struct { 146 args []string 147 api mock.API 148 wantError string 149 wantOutput string 150 }{ 151 { 152 args: args("logging azureblob describe --service-id 123 --version 1"), 153 wantError: "error parsing arguments: required flag --name not provided", 154 }, 155 { 156 args: args("logging azureblob describe --service-id 123 --version 1 --name logs"), 157 api: mock.API{ 158 ListVersionsFn: testutil.ListVersions, 159 GetBlobStorageFn: getBlobStorageError, 160 }, 161 wantError: errTest.Error(), 162 }, 163 { 164 args: args("logging azureblob describe --service-id 123 --version 1 --name logs"), 165 api: mock.API{ 166 ListVersionsFn: testutil.ListVersions, 167 GetBlobStorageFn: getBlobStorageOK, 168 }, 169 wantOutput: describeBlobStorageOutput, 170 }, 171 } 172 for testcaseIdx := range scenarios { 173 testcase := &scenarios[testcaseIdx] 174 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 175 var stdout bytes.Buffer 176 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 177 opts := testutil.MockGlobalData(testcase.args, &stdout) 178 opts.APIClientFactory = mock.APIClient(testcase.api) 179 return opts, nil 180 } 181 err := app.Run(testcase.args, nil) 182 testutil.AssertErrorContains(t, err, testcase.wantError) 183 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 184 }) 185 } 186 } 187 188 func TestBlobStorageUpdate(t *testing.T) { 189 args := testutil.Args 190 scenarios := []struct { 191 args []string 192 api mock.API 193 wantError string 194 wantOutput string 195 }{ 196 { 197 args: args("logging azureblob update --service-id 123 --version 1 --new-name log"), 198 wantError: "error parsing arguments: required flag --name not provided", 199 }, 200 { 201 args: args("logging azureblob update --service-id 123 --version 1 --name logs --new-name log --autoclone"), 202 api: mock.API{ 203 ListVersionsFn: testutil.ListVersions, 204 CloneVersionFn: testutil.CloneVersionResult(4), 205 UpdateBlobStorageFn: updateBlobStorageError, 206 }, 207 wantError: errTest.Error(), 208 }, 209 { 210 args: args("logging azureblob update --service-id 123 --version 1 --name logs --new-name log --autoclone"), 211 api: mock.API{ 212 ListVersionsFn: testutil.ListVersions, 213 CloneVersionFn: testutil.CloneVersionResult(4), 214 UpdateBlobStorageFn: updateBlobStorageOK, 215 }, 216 wantOutput: "Updated Azure Blob Storage logging endpoint log (service 123 version 4)", 217 }, 218 } 219 for testcaseIdx := range scenarios { 220 testcase := &scenarios[testcaseIdx] 221 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 222 var stdout bytes.Buffer 223 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 224 opts := testutil.MockGlobalData(testcase.args, &stdout) 225 opts.APIClientFactory = mock.APIClient(testcase.api) 226 return opts, nil 227 } 228 err := app.Run(testcase.args, nil) 229 testutil.AssertErrorContains(t, err, testcase.wantError) 230 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 231 }) 232 } 233 } 234 235 func TestBlobStorageDelete(t *testing.T) { 236 args := testutil.Args 237 scenarios := []struct { 238 args []string 239 api mock.API 240 wantError string 241 wantOutput string 242 }{ 243 { 244 args: args("logging azureblob delete --service-id 123 --version 1"), 245 wantError: "error parsing arguments: required flag --name not provided", 246 }, 247 { 248 args: args("logging azureblob delete --service-id 123 --version 1 --name logs --autoclone"), 249 api: mock.API{ 250 ListVersionsFn: testutil.ListVersions, 251 CloneVersionFn: testutil.CloneVersionResult(4), 252 DeleteBlobStorageFn: deleteBlobStorageError, 253 }, 254 wantError: errTest.Error(), 255 }, 256 { 257 args: args("logging azureblob delete --service-id 123 --version 1 --name logs --autoclone"), 258 api: mock.API{ 259 ListVersionsFn: testutil.ListVersions, 260 CloneVersionFn: testutil.CloneVersionResult(4), 261 DeleteBlobStorageFn: deleteBlobStorageOK, 262 }, 263 wantOutput: "Deleted Azure Blob Storage logging endpoint logs (service 123 version 4)", 264 }, 265 } 266 for testcaseIdx := range scenarios { 267 testcase := &scenarios[testcaseIdx] 268 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 269 var stdout bytes.Buffer 270 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 271 opts := testutil.MockGlobalData(testcase.args, &stdout) 272 opts.APIClientFactory = mock.APIClient(testcase.api) 273 return opts, nil 274 } 275 err := app.Run(testcase.args, nil) 276 testutil.AssertErrorContains(t, err, testcase.wantError) 277 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 278 }) 279 } 280 } 281 282 var errTest = errors.New("fixture error") 283 284 func createBlobStorageOK(i *fastly.CreateBlobStorageInput) (*fastly.BlobStorage, error) { 285 s := fastly.BlobStorage{ 286 ServiceID: fastly.ToPointer(i.ServiceID), 287 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 288 Name: fastly.ToPointer("log"), 289 Path: fastly.ToPointer("/logs"), 290 AccountName: fastly.ToPointer("account"), 291 Container: fastly.ToPointer("container"), 292 SASToken: fastly.ToPointer("token"), 293 Period: fastly.ToPointer(3600), 294 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 295 PublicKey: fastly.ToPointer(pgpPublicKey()), 296 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 297 FormatVersion: fastly.ToPointer(2), 298 MessageType: fastly.ToPointer("classic"), 299 Placement: fastly.ToPointer("none"), 300 ResponseCondition: fastly.ToPointer("Prevent default logging"), 301 CompressionCodec: fastly.ToPointer("zstd"), 302 } 303 304 return &s, nil 305 } 306 307 func createBlobStorageError(_ *fastly.CreateBlobStorageInput) (*fastly.BlobStorage, error) { 308 return nil, errTest 309 } 310 311 func listBlobStoragesOK(i *fastly.ListBlobStoragesInput) ([]*fastly.BlobStorage, error) { 312 return []*fastly.BlobStorage{ 313 { 314 ServiceID: fastly.ToPointer(i.ServiceID), 315 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 316 Name: fastly.ToPointer("logs"), 317 Path: fastly.ToPointer("/logs"), 318 AccountName: fastly.ToPointer("account"), 319 Container: fastly.ToPointer("container"), 320 SASToken: fastly.ToPointer("token"), 321 Period: fastly.ToPointer(3600), 322 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 323 PublicKey: fastly.ToPointer(pgpPublicKey()), 324 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 325 FormatVersion: fastly.ToPointer(2), 326 MessageType: fastly.ToPointer("classic"), 327 Placement: fastly.ToPointer("none"), 328 ResponseCondition: fastly.ToPointer("Prevent default logging"), 329 CompressionCodec: fastly.ToPointer("zstd"), 330 }, 331 { 332 ServiceID: fastly.ToPointer(i.ServiceID), 333 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 334 Name: fastly.ToPointer("analytics"), 335 AccountName: fastly.ToPointer("account"), 336 Container: fastly.ToPointer("analytics"), 337 SASToken: fastly.ToPointer("token"), 338 Path: fastly.ToPointer("/logs"), 339 Period: fastly.ToPointer(86400), 340 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 341 FormatVersion: fastly.ToPointer(2), 342 MessageType: fastly.ToPointer("classic"), 343 ResponseCondition: fastly.ToPointer("Prevent default logging"), 344 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 345 Placement: fastly.ToPointer("none"), 346 PublicKey: fastly.ToPointer(pgpPublicKey()), 347 CompressionCodec: fastly.ToPointer("zstd"), 348 }, 349 }, nil 350 } 351 352 func listBlobStoragesError(_ *fastly.ListBlobStoragesInput) ([]*fastly.BlobStorage, error) { 353 return nil, errTest 354 } 355 356 var listBlobStoragesShortOutput = strings.TrimSpace(` 357 SERVICE VERSION NAME 358 123 1 logs 359 123 1 analytics 360 `) + "\n" 361 362 var listBlobStoragesVerboseOutput = strings.TrimSpace(` 363 Fastly API endpoint: https://api.fastly.com 364 Fastly API token provided via config file (profile: user) 365 366 Service ID (via --service-id): 123 367 368 Version: 1 369 BlobStorage 1/2 370 Service ID: 123 371 Version: 1 372 Name: logs 373 Container: container 374 Account name: account 375 SAS token: token 376 Path: /logs 377 Period: 3600 378 GZip level: 0 379 Format: %h %l %u %t "%r" %>s %b 380 Format version: 2 381 Response condition: Prevent default logging 382 Message type: classic 383 Timestamp format: %Y-%m-%dT%H:%M:%S.000 384 Placement: none 385 Public key: `+pgpPublicKey()+` 386 File max bytes: 0 387 Compression codec: zstd 388 BlobStorage 2/2 389 Service ID: 123 390 Version: 1 391 Name: analytics 392 Container: analytics 393 Account name: account 394 SAS token: token 395 Path: /logs 396 Period: 86400 397 GZip level: 0 398 Format: %h %l %u %t "%r" %>s %b 399 Format version: 2 400 Response condition: Prevent default logging 401 Message type: classic 402 Timestamp format: %Y-%m-%dT%H:%M:%S.000 403 Placement: none 404 Public key: `+pgpPublicKey()+` 405 File max bytes: 0 406 Compression codec: zstd 407 `) + "\n\n" 408 409 func getBlobStorageOK(i *fastly.GetBlobStorageInput) (*fastly.BlobStorage, error) { 410 return &fastly.BlobStorage{ 411 ServiceID: fastly.ToPointer(i.ServiceID), 412 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 413 Name: fastly.ToPointer("logs"), 414 Container: fastly.ToPointer("container"), 415 AccountName: fastly.ToPointer("account"), 416 SASToken: fastly.ToPointer("token"), 417 Path: fastly.ToPointer("/logs"), 418 Period: fastly.ToPointer(3600), 419 GzipLevel: fastly.ToPointer(0), 420 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 421 FormatVersion: fastly.ToPointer(2), 422 ResponseCondition: fastly.ToPointer("Prevent default logging"), 423 MessageType: fastly.ToPointer("classic"), 424 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 425 Placement: fastly.ToPointer("none"), 426 PublicKey: fastly.ToPointer(pgpPublicKey()), 427 CompressionCodec: fastly.ToPointer("zstd"), 428 }, nil 429 } 430 431 func getBlobStorageError(_ *fastly.GetBlobStorageInput) (*fastly.BlobStorage, error) { 432 return nil, errTest 433 } 434 435 var describeBlobStorageOutput = "\n" + strings.TrimSpace(` 436 Account name: account 437 Compression codec: zstd 438 Container: container 439 File max bytes: 0 440 Format: %h %l %u %t "%r" %>s %b 441 Format version: 2 442 GZip level: 0 443 Message type: classic 444 Name: logs 445 Path: /logs 446 Period: 3600 447 Placement: none 448 Public key: `+pgpPublicKey()+` 449 Response condition: Prevent default logging 450 SAS token: token 451 Service ID: 123 452 Timestamp format: %Y-%m-%dT%H:%M:%S.000 453 Version: 1 454 `) + "\n" 455 456 func updateBlobStorageOK(i *fastly.UpdateBlobStorageInput) (*fastly.BlobStorage, error) { 457 return &fastly.BlobStorage{ 458 ServiceID: fastly.ToPointer(i.ServiceID), 459 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 460 Name: fastly.ToPointer("log"), 461 Container: fastly.ToPointer("container"), 462 AccountName: fastly.ToPointer("account"), 463 SASToken: fastly.ToPointer("token"), 464 Path: fastly.ToPointer("/logs"), 465 Period: fastly.ToPointer(3600), 466 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 467 FormatVersion: fastly.ToPointer(2), 468 ResponseCondition: fastly.ToPointer("Prevent default logging"), 469 MessageType: fastly.ToPointer("classic"), 470 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 471 Placement: fastly.ToPointer("none"), 472 PublicKey: fastly.ToPointer(pgpPublicKey()), 473 CompressionCodec: fastly.ToPointer("zstd"), 474 }, nil 475 } 476 477 func updateBlobStorageError(_ *fastly.UpdateBlobStorageInput) (*fastly.BlobStorage, error) { 478 return nil, errTest 479 } 480 481 func deleteBlobStorageOK(_ *fastly.DeleteBlobStorageInput) error { 482 return nil 483 } 484 485 func deleteBlobStorageError(_ *fastly.DeleteBlobStorageInput) error { 486 return errTest 487 } 488 489 // pgpPublicKey returns a PEM encoded PGP public key suitable for testing. 490 func pgpPublicKey() string { 491 return strings.TrimSpace(`-----BEGIN PGP PUBLIC KEY BLOCK----- 492 mQENBFyUD8sBCACyFnB39AuuTygseek+eA4fo0cgwva6/FSjnWq7riouQee8GgQ/ 493 ibXTRyv4iVlwI12GswvMTIy7zNvs1R54i0qvsLr+IZ4GVGJqs6ZJnvQcqe3xPoR4 494 8AnBfw90o32r/LuHf6QCJXi+AEu35koNlNAvLJ2B+KACaNB7N0EeWmqpV/1V2k9p 495 lDYk+th7LcCuaFNGqKS/PrMnnMqR6VDLCjHhNx4KR79b0Twm/2qp6an3hyNRu8Gn 496 dwxpf1/BUu3JWf+LqkN4Y3mbOmSUL3MaJNvyQguUzTfS0P0uGuBDHrJCVkMZCzDB 497 89ag55jCPHyGeHBTd02gHMWzsg3WMBWvCsrzABEBAAG0JXRlcnJhZm9ybSAodGVz 498 dCkgPHRlc3RAdGVycmFmb3JtLmNvbT6JAU4EEwEIADgWIQSHYyc6Kj9l6HzQsau6 499 vFFc9jxV/wUCXJQPywIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRC6vFFc 500 9jxV/815CAClb32OxV7wG01yF97TzlyTl8TnvjMtoG29Mw4nSyg+mjM3b8N7iXm9 501 OLX59fbDAWtBSldSZE22RXd3CvlFOG/EnKBXSjBtEqfyxYSnyOPkMPBYWGL/ApkX 502 SvPYJ4LKdvipYToKFh3y9kk2gk1DcDBDyaaHvR+3rv1u3aoy7/s2EltAfDS3ZQIq 503 7/cWTLJml/lleeB/Y6rPj8xqeCYhE5ahw9gsV/Mdqatl24V9Tks30iijx0Hhw+Gx 504 kATUikMGr2GDVqoIRga5kXI7CzYff4rkc0Twn47fMHHHe/KY9M2yVnMHUXmAZwbG 505 M1cMI/NH1DjevCKdGBLcRJlhuLPKF/anuQENBFyUD8sBCADIpd7r7GuPd6n/Ikxe 506 u6h7umV6IIPoAm88xCYpTbSZiaK30Svh6Ywra9jfE2KlU9o6Y/art8ip0VJ3m07L 507 4RSfSpnzqgSwdjSq5hNour2Fo/BzYhK7yaz2AzVSbe33R0+RYhb4b/6N+bKbjwGF 508 ftCsqVFMH+PyvYkLbvxyQrHlA9woAZaNThI1ztO5rGSnGUR8xt84eup28WIFKg0K 509 UEGUcTzz+8QGAwAra+0ewPXo/AkO+8BvZjDidP417u6gpBHOJ9qYIcO9FxHeqFyu 510 YrjlrxowEgXn5wO8xuNz6Vu1vhHGDHGDsRbZF8pv1d5O+0F1G7ttZ2GRRgVBZPwi 511 kiyRABEBAAGJATYEGAEIACAWIQSHYyc6Kj9l6HzQsau6vFFc9jxV/wUCXJQPywIb 512 DAAKCRC6vFFc9jxV/9YOCACe8qmOSnKQpQfW+PqYOqo3dt7JyweTs3FkD6NT8Zml 513 dYy/vkstbTjPpX6aTvUZjkb46BVi7AOneVHpD5GBqvRsZ9iVgDYHaehmLCdKiG5L 514 3Tp90NN+QY5WDbsGmsyk6+6ZMYejb4qYfweQeduOj27aavCJdLkCYMoRKfcFYI8c 515 FaNmEfKKy/r1PO20NXEG6t9t05K/frHy6ZG8bCNYdpagfFVot47r9JaQqWlTNtIR 516 5+zkkSq/eG9BEtRij3a6cTdQbktdBzx2KBeI0PYc1vlZR0LpuFKZqY9vlE6vTGLR 517 wMfrTEOvx0NxUM3rpaCgEmuWbB1G1Hu371oyr4srrr+N 518 =28dr 519 -----END PGP PUBLIC KEY BLOCK----- 520 `) 521 }