github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/logging/kafka/kafka_integration_test.go (about) 1 package kafka_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 TestKafkaCreate(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 kafka create --service-id 123 --version 1 --name log --topic logs --brokers 127.0.0.1127.0.0.2 --parse-log-keyvals --max-batch-size 1024 --use-sasl --auth-method plain --username user --password password --autoclone"), 28 api: mock.API{ 29 ListVersionsFn: testutil.ListVersions, 30 CloneVersionFn: testutil.CloneVersionResult(4), 31 CreateKafkaFn: createKafkaOK, 32 }, 33 wantOutput: "Created Kafka logging endpoint log (service 123 version 4)", 34 }, 35 { 36 args: args("logging kafka create --service-id 123 --version 1 --name log --topic logs --brokers 127.0.0.1127.0.0.2 --autoclone"), 37 api: mock.API{ 38 ListVersionsFn: testutil.ListVersions, 39 CloneVersionFn: testutil.CloneVersionResult(4), 40 CreateKafkaFn: createKafkaError, 41 }, 42 wantError: errTest.Error(), 43 }, 44 } 45 for testcaseIdx := range scenarios { 46 testcase := &scenarios[testcaseIdx] 47 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 48 var stdout bytes.Buffer 49 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 50 opts := testutil.MockGlobalData(testcase.args, &stdout) 51 opts.APIClientFactory = mock.APIClient(testcase.api) 52 return opts, nil 53 } 54 err := app.Run(testcase.args, nil) 55 testutil.AssertErrorContains(t, err, testcase.wantError) 56 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 57 }) 58 } 59 } 60 61 func TestKafkaList(t *testing.T) { 62 args := testutil.Args 63 scenarios := []struct { 64 args []string 65 api mock.API 66 wantError string 67 wantOutput string 68 }{ 69 { 70 args: args("logging kafka list --service-id 123 --version 1"), 71 api: mock.API{ 72 ListVersionsFn: testutil.ListVersions, 73 ListKafkasFn: listKafkasOK, 74 }, 75 wantOutput: listKafkasShortOutput, 76 }, 77 { 78 args: args("logging kafka list --service-id 123 --version 1 --verbose"), 79 api: mock.API{ 80 ListVersionsFn: testutil.ListVersions, 81 ListKafkasFn: listKafkasOK, 82 }, 83 wantOutput: listKafkasVerboseOutput, 84 }, 85 { 86 args: args("logging kafka list --service-id 123 --version 1 -v"), 87 api: mock.API{ 88 ListVersionsFn: testutil.ListVersions, 89 ListKafkasFn: listKafkasOK, 90 }, 91 wantOutput: listKafkasVerboseOutput, 92 }, 93 { 94 args: args("logging kafka --verbose list --service-id 123 --version 1"), 95 api: mock.API{ 96 ListVersionsFn: testutil.ListVersions, 97 ListKafkasFn: listKafkasOK, 98 }, 99 wantOutput: listKafkasVerboseOutput, 100 }, 101 { 102 args: args("logging -v kafka list --service-id 123 --version 1"), 103 api: mock.API{ 104 ListVersionsFn: testutil.ListVersions, 105 ListKafkasFn: listKafkasOK, 106 }, 107 wantOutput: listKafkasVerboseOutput, 108 }, 109 { 110 args: args("logging kafka list --service-id 123 --version 1"), 111 api: mock.API{ 112 ListVersionsFn: testutil.ListVersions, 113 ListKafkasFn: listKafkasError, 114 }, 115 wantError: errTest.Error(), 116 }, 117 } 118 for testcaseIdx := range scenarios { 119 testcase := &scenarios[testcaseIdx] 120 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 121 var stdout bytes.Buffer 122 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 123 opts := testutil.MockGlobalData(testcase.args, &stdout) 124 opts.APIClientFactory = mock.APIClient(testcase.api) 125 return opts, nil 126 } 127 err := app.Run(testcase.args, nil) 128 testutil.AssertErrorContains(t, err, testcase.wantError) 129 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 130 }) 131 } 132 } 133 134 func TestKafkaDescribe(t *testing.T) { 135 args := testutil.Args 136 scenarios := []struct { 137 args []string 138 api mock.API 139 wantError string 140 wantOutput string 141 }{ 142 { 143 args: args("logging kafka describe --service-id 123 --version 1"), 144 wantError: "error parsing arguments: required flag --name not provided", 145 }, 146 { 147 args: args("logging kafka describe --service-id 123 --version 1 --name logs"), 148 api: mock.API{ 149 ListVersionsFn: testutil.ListVersions, 150 GetKafkaFn: getKafkaError, 151 }, 152 wantError: errTest.Error(), 153 }, 154 { 155 args: args("logging kafka describe --service-id 123 --version 1 --name logs"), 156 api: mock.API{ 157 ListVersionsFn: testutil.ListVersions, 158 GetKafkaFn: getKafkaOK, 159 }, 160 wantOutput: describeKafkaOutput, 161 }, 162 } 163 for testcaseIdx := range scenarios { 164 testcase := &scenarios[testcaseIdx] 165 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 166 var stdout bytes.Buffer 167 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 168 opts := testutil.MockGlobalData(testcase.args, &stdout) 169 opts.APIClientFactory = mock.APIClient(testcase.api) 170 return opts, nil 171 } 172 err := app.Run(testcase.args, nil) 173 testutil.AssertErrorContains(t, err, testcase.wantError) 174 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 175 }) 176 } 177 } 178 179 func TestKafkaUpdate(t *testing.T) { 180 args := testutil.Args 181 scenarios := []struct { 182 args []string 183 api mock.API 184 wantError string 185 wantOutput string 186 }{ 187 { 188 args: args("logging kafka update --service-id 123 --version 1 --new-name log"), 189 wantError: "error parsing arguments: required flag --name not provided", 190 }, 191 { 192 args: args("logging kafka update --service-id 123 --version 1 --name logs --new-name log --autoclone"), 193 api: mock.API{ 194 ListVersionsFn: testutil.ListVersions, 195 CloneVersionFn: testutil.CloneVersionResult(4), 196 UpdateKafkaFn: updateKafkaError, 197 }, 198 wantError: errTest.Error(), 199 }, 200 { 201 args: args("logging kafka 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 UpdateKafkaFn: updateKafkaOK, 206 }, 207 wantOutput: "Updated Kafka logging endpoint log (service 123 version 4)", 208 }, 209 { 210 args: args("logging kafka update --service-id 123 --version 1 --name logs --new-name log --parse-log-keyvals --max-batch-size 1024 --use-sasl --auth-method plain --username user --password password --autoclone"), 211 api: mock.API{ 212 ListVersionsFn: testutil.ListVersions, 213 CloneVersionFn: testutil.CloneVersionResult(4), 214 UpdateKafkaFn: updateKafkaSASL, 215 }, 216 wantOutput: "Updated Kafka 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 TestKafkaDelete(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 kafka delete --service-id 123 --version 1"), 245 wantError: "error parsing arguments: required flag --name not provided", 246 }, 247 { 248 args: args("logging kafka delete --service-id 123 --version 1 --name logs --autoclone"), 249 api: mock.API{ 250 ListVersionsFn: testutil.ListVersions, 251 CloneVersionFn: testutil.CloneVersionResult(4), 252 DeleteKafkaFn: deleteKafkaError, 253 }, 254 wantError: errTest.Error(), 255 }, 256 { 257 args: args("logging kafka delete --service-id 123 --version 1 --name logs --autoclone"), 258 api: mock.API{ 259 ListVersionsFn: testutil.ListVersions, 260 CloneVersionFn: testutil.CloneVersionResult(4), 261 DeleteKafkaFn: deleteKafkaOK, 262 }, 263 wantOutput: "Deleted Kafka 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 createKafkaOK(i *fastly.CreateKafkaInput) (*fastly.Kafka, error) { 285 return &fastly.Kafka{ 286 ServiceID: fastly.ToPointer(i.ServiceID), 287 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 288 Name: fastly.ToPointer("log"), 289 ResponseCondition: fastly.ToPointer("Prevent default logging"), 290 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 291 Topic: fastly.ToPointer("logs"), 292 Brokers: fastly.ToPointer("127.0.0.1,127.0.0.2"), 293 RequiredACKs: fastly.ToPointer("-1"), 294 CompressionCodec: fastly.ToPointer("zippy"), 295 UseTLS: fastly.ToPointer(true), 296 Placement: fastly.ToPointer("none"), 297 TLSCACert: fastly.ToPointer("-----BEGIN CERTIFICATE-----foo"), 298 TLSHostname: fastly.ToPointer("127.0.0.1,127.0.0.2"), 299 TLSClientCert: fastly.ToPointer("-----BEGIN CERTIFICATE-----bar"), 300 TLSClientKey: fastly.ToPointer("-----BEGIN PRIVATE KEY-----bar"), 301 FormatVersion: fastly.ToPointer(2), 302 ParseLogKeyvals: fastly.ToPointer(true), 303 RequestMaxBytes: fastly.ToPointer(1024), 304 AuthMethod: fastly.ToPointer("plain"), 305 User: fastly.ToPointer("user"), 306 Password: fastly.ToPointer("password"), 307 }, nil 308 } 309 310 func createKafkaError(_ *fastly.CreateKafkaInput) (*fastly.Kafka, error) { 311 return nil, errTest 312 } 313 314 func listKafkasOK(i *fastly.ListKafkasInput) ([]*fastly.Kafka, error) { 315 return []*fastly.Kafka{ 316 { 317 ServiceID: fastly.ToPointer(i.ServiceID), 318 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 319 Name: fastly.ToPointer("logs"), 320 ResponseCondition: fastly.ToPointer("Prevent default logging"), 321 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 322 Topic: fastly.ToPointer("logs"), 323 Brokers: fastly.ToPointer("127.0.0.1,127.0.0.2"), 324 RequiredACKs: fastly.ToPointer("-1"), 325 CompressionCodec: fastly.ToPointer("zippy"), 326 UseTLS: fastly.ToPointer(true), 327 Placement: fastly.ToPointer("none"), 328 TLSCACert: fastly.ToPointer("-----BEGIN CERTIFICATE-----foo"), 329 TLSHostname: fastly.ToPointer("127.0.0.1,127.0.0.2"), 330 TLSClientCert: fastly.ToPointer("-----BEGIN CERTIFICATE-----bar"), 331 TLSClientKey: fastly.ToPointer("-----BEGIN PRIVATE KEY-----bar"), 332 FormatVersion: fastly.ToPointer(2), 333 ParseLogKeyvals: fastly.ToPointer(false), 334 RequestMaxBytes: fastly.ToPointer(0), 335 AuthMethod: fastly.ToPointer("plain"), 336 User: fastly.ToPointer("user"), 337 Password: fastly.ToPointer("password"), 338 }, 339 { 340 ServiceID: fastly.ToPointer(i.ServiceID), 341 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 342 Name: fastly.ToPointer("analytics"), 343 Topic: fastly.ToPointer("analytics"), 344 Brokers: fastly.ToPointer("127.0.0.1,127.0.0.2"), 345 RequiredACKs: fastly.ToPointer("-1"), 346 CompressionCodec: fastly.ToPointer("zippy"), 347 UseTLS: fastly.ToPointer(true), 348 Placement: fastly.ToPointer("none"), 349 TLSCACert: fastly.ToPointer("-----BEGIN CERTIFICATE-----foo"), 350 TLSHostname: fastly.ToPointer("127.0.0.1,127.0.0.2"), 351 TLSClientCert: fastly.ToPointer("-----BEGIN CERTIFICATE-----bar"), 352 TLSClientKey: fastly.ToPointer("-----BEGIN PRIVATE KEY-----bar"), 353 ResponseCondition: fastly.ToPointer("Prevent default logging"), 354 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 355 FormatVersion: fastly.ToPointer(2), 356 ParseLogKeyvals: fastly.ToPointer(false), 357 RequestMaxBytes: fastly.ToPointer(0), 358 AuthMethod: fastly.ToPointer("plain"), 359 User: fastly.ToPointer("user"), 360 Password: fastly.ToPointer("password"), 361 }, 362 }, nil 363 } 364 365 func listKafkasError(_ *fastly.ListKafkasInput) ([]*fastly.Kafka, error) { 366 return nil, errTest 367 } 368 369 var listKafkasShortOutput = strings.TrimSpace(` 370 SERVICE VERSION NAME 371 123 1 logs 372 123 1 analytics 373 `) + "\n" 374 375 var listKafkasVerboseOutput = strings.TrimSpace(` 376 Fastly API endpoint: https://api.fastly.com 377 Fastly API token provided via config file (profile: user) 378 379 Service ID (via --service-id): 123 380 381 Version: 1 382 Kafka 1/2 383 Service ID: 123 384 Version: 1 385 Name: logs 386 Topic: logs 387 Brokers: 127.0.0.1,127.0.0.2 388 Required acks: -1 389 Compression codec: zippy 390 Use TLS: true 391 TLS CA certificate: -----BEGIN CERTIFICATE-----foo 392 TLS client certificate: -----BEGIN CERTIFICATE-----bar 393 TLS client key: -----BEGIN PRIVATE KEY-----bar 394 TLS hostname: 127.0.0.1,127.0.0.2 395 Format: %h %l %u %t "%r" %>s %b 396 Format version: 2 397 Response condition: Prevent default logging 398 Placement: none 399 Parse log key-values: false 400 Max batch size: 0 401 SASL authentication method: plain 402 SASL authentication username: user 403 SASL authentication password: password 404 Kafka 2/2 405 Service ID: 123 406 Version: 1 407 Name: analytics 408 Topic: analytics 409 Brokers: 127.0.0.1,127.0.0.2 410 Required acks: -1 411 Compression codec: zippy 412 Use TLS: true 413 TLS CA certificate: -----BEGIN CERTIFICATE-----foo 414 TLS client certificate: -----BEGIN CERTIFICATE-----bar 415 TLS client key: -----BEGIN PRIVATE KEY-----bar 416 TLS hostname: 127.0.0.1,127.0.0.2 417 Format: %h %l %u %t "%r" %>s %b 418 Format version: 2 419 Response condition: Prevent default logging 420 Placement: none 421 Parse log key-values: false 422 Max batch size: 0 423 SASL authentication method: plain 424 SASL authentication username: user 425 SASL authentication password: password 426 `) + "\n\n" 427 428 func getKafkaOK(i *fastly.GetKafkaInput) (*fastly.Kafka, error) { 429 return &fastly.Kafka{ 430 ServiceID: fastly.ToPointer(i.ServiceID), 431 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 432 Name: fastly.ToPointer("log"), 433 Brokers: fastly.ToPointer("127.0.0.1,127.0.0.2"), 434 Topic: fastly.ToPointer("logs"), 435 RequiredACKs: fastly.ToPointer("-1"), 436 UseTLS: fastly.ToPointer(true), 437 CompressionCodec: fastly.ToPointer("zippy"), 438 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 439 FormatVersion: fastly.ToPointer(2), 440 ResponseCondition: fastly.ToPointer("Prevent default logging"), 441 Placement: fastly.ToPointer("none"), 442 TLSCACert: fastly.ToPointer("-----BEGIN CERTIFICATE-----foo"), 443 TLSHostname: fastly.ToPointer("127.0.0.1,127.0.0.2"), 444 TLSClientCert: fastly.ToPointer("-----BEGIN CERTIFICATE-----bar"), 445 TLSClientKey: fastly.ToPointer("-----BEGIN PRIVATE KEY-----bar"), 446 }, nil 447 } 448 449 func getKafkaError(_ *fastly.GetKafkaInput) (*fastly.Kafka, error) { 450 return nil, errTest 451 } 452 453 var describeKafkaOutput = ` 454 Brokers: 127.0.0.1,127.0.0.2 455 Compression codec: zippy 456 Format: %h %l %u %t "%r" %>s %b 457 Format version: 2 458 Max batch size: 0 459 Name: log 460 Parse log key-values: false 461 Placement: none 462 Required acks: -1 463 Response condition: Prevent default logging 464 SASL authentication method: ` + ` 465 SASL authentication password: ` + ` 466 SASL authentication username: ` + ` 467 Service ID: 123 468 TLS CA certificate: -----BEGIN CERTIFICATE-----foo 469 TLS client certificate: -----BEGIN CERTIFICATE-----bar 470 TLS client key: -----BEGIN PRIVATE KEY-----bar 471 TLS hostname: 127.0.0.1,127.0.0.2 472 Topic: logs 473 Use TLS: true 474 Version: 1 475 ` 476 477 func updateKafkaOK(i *fastly.UpdateKafkaInput) (*fastly.Kafka, error) { 478 return &fastly.Kafka{ 479 ServiceID: fastly.ToPointer(i.ServiceID), 480 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 481 Name: fastly.ToPointer("log"), 482 ResponseCondition: fastly.ToPointer("Prevent default logging"), 483 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 484 Topic: fastly.ToPointer("logs"), 485 Brokers: fastly.ToPointer("127.0.0.1,127.0.0.2"), 486 RequiredACKs: fastly.ToPointer("-1"), 487 CompressionCodec: fastly.ToPointer("zippy"), 488 UseTLS: fastly.ToPointer(true), 489 Placement: fastly.ToPointer("none"), 490 TLSCACert: fastly.ToPointer("-----BEGIN CERTIFICATE-----foo"), 491 TLSHostname: fastly.ToPointer("127.0.0.1,127.0.0.2"), 492 TLSClientCert: fastly.ToPointer("-----BEGIN CERTIFICATE-----bar"), 493 TLSClientKey: fastly.ToPointer("-----BEGIN PRIVATE KEY-----bar"), 494 FormatVersion: fastly.ToPointer(2), 495 }, nil 496 } 497 498 func updateKafkaSASL(i *fastly.UpdateKafkaInput) (*fastly.Kafka, error) { 499 return &fastly.Kafka{ 500 ServiceID: fastly.ToPointer(i.ServiceID), 501 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 502 Name: fastly.ToPointer("log"), 503 ResponseCondition: fastly.ToPointer("Prevent default logging"), 504 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 505 Topic: fastly.ToPointer("logs"), 506 Brokers: fastly.ToPointer("127.0.0.1,127.0.0.2"), 507 RequiredACKs: fastly.ToPointer("-1"), 508 CompressionCodec: fastly.ToPointer("zippy"), 509 UseTLS: fastly.ToPointer(true), 510 Placement: fastly.ToPointer("none"), 511 TLSCACert: fastly.ToPointer("-----BEGIN CERTIFICATE-----foo"), 512 TLSHostname: fastly.ToPointer("127.0.0.1,127.0.0.2"), 513 TLSClientCert: fastly.ToPointer("-----BEGIN CERTIFICATE-----bar"), 514 TLSClientKey: fastly.ToPointer("-----BEGIN PRIVATE KEY-----bar"), 515 FormatVersion: fastly.ToPointer(2), 516 ParseLogKeyvals: fastly.ToPointer(true), 517 RequestMaxBytes: fastly.ToPointer(1024), 518 AuthMethod: fastly.ToPointer("plain"), 519 User: fastly.ToPointer("user"), 520 Password: fastly.ToPointer("password"), 521 }, nil 522 } 523 524 func updateKafkaError(_ *fastly.UpdateKafkaInput) (*fastly.Kafka, error) { 525 return nil, errTest 526 } 527 528 func deleteKafkaOK(_ *fastly.DeleteKafkaInput) error { 529 return nil 530 } 531 532 func deleteKafkaError(_ *fastly.DeleteKafkaInput) error { 533 return errTest 534 }