github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/logging/digitalocean/digitalocean_test.go (about) 1 package digitalocean_test 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/fastly/go-fastly/v9/fastly" 8 9 "github.com/fastly/cli/pkg/argparser" 10 "github.com/fastly/cli/pkg/commands/logging/digitalocean" 11 "github.com/fastly/cli/pkg/config" 12 "github.com/fastly/cli/pkg/errors" 13 "github.com/fastly/cli/pkg/global" 14 "github.com/fastly/cli/pkg/manifest" 15 "github.com/fastly/cli/pkg/mock" 16 "github.com/fastly/cli/pkg/testutil" 17 ) 18 19 func TestCreateDigitalOceanInput(t *testing.T) { 20 for _, testcase := range []struct { 21 name string 22 cmd *digitalocean.CreateCommand 23 want *fastly.CreateDigitalOceanInput 24 wantError string 25 }{ 26 { 27 name: "required values set flag serviceID", 28 cmd: createCommandRequired(), 29 want: &fastly.CreateDigitalOceanInput{ 30 ServiceID: "123", 31 ServiceVersion: 4, 32 Name: fastly.ToPointer("log"), 33 BucketName: fastly.ToPointer("bucket"), 34 AccessKey: fastly.ToPointer("access"), 35 SecretKey: fastly.ToPointer("secret"), 36 }, 37 }, 38 { 39 name: "all values set flag serviceID", 40 cmd: createCommandAll(), 41 want: &fastly.CreateDigitalOceanInput{ 42 ServiceID: "123", 43 ServiceVersion: 4, 44 Name: fastly.ToPointer("log"), 45 BucketName: fastly.ToPointer("bucket"), 46 Domain: fastly.ToPointer("nyc3.digitaloceanspaces.com"), 47 AccessKey: fastly.ToPointer("access"), 48 SecretKey: fastly.ToPointer("secret"), 49 Path: fastly.ToPointer("/log"), 50 Period: fastly.ToPointer(3600), 51 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 52 MessageType: fastly.ToPointer("classic"), 53 FormatVersion: fastly.ToPointer(2), 54 ResponseCondition: fastly.ToPointer("Prevent default logging"), 55 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 56 Placement: fastly.ToPointer("none"), 57 PublicKey: fastly.ToPointer(pgpPublicKey()), 58 CompressionCodec: fastly.ToPointer("zstd"), 59 }, 60 }, 61 { 62 name: "error missing serviceID", 63 cmd: createCommandMissingServiceID(), 64 want: nil, 65 wantError: errors.ErrNoServiceID.Error(), 66 }, 67 } { 68 t.Run(testcase.name, func(t *testing.T) { 69 var bs []byte 70 out := bytes.NewBuffer(bs) 71 verboseMode := true 72 73 serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{ 74 AutoCloneFlag: testcase.cmd.AutoClone, 75 APIClient: testcase.cmd.Globals.APIClient, 76 Manifest: testcase.cmd.Manifest, 77 Out: out, 78 ServiceVersionFlag: testcase.cmd.ServiceVersion, 79 VerboseMode: verboseMode, 80 }) 81 82 switch { 83 case err != nil && testcase.wantError == "": 84 t.Fatalf("unexpected error getting service details: %v", err) 85 return 86 case err != nil && testcase.wantError != "": 87 testutil.AssertErrorContains(t, err, testcase.wantError) 88 return 89 case err == nil && testcase.wantError != "": 90 t.Fatalf("expected error, have nil (service details: %s, %d)", serviceID, serviceVersion.Number) 91 case err == nil && testcase.wantError == "": 92 have, err := testcase.cmd.ConstructInput(serviceID, fastly.ToValue(serviceVersion.Number)) 93 testutil.AssertErrorContains(t, err, testcase.wantError) 94 testutil.AssertEqual(t, testcase.want, have) 95 } 96 }) 97 } 98 } 99 100 func TestUpdateDigitalOceanInput(t *testing.T) { 101 scenarios := []struct { 102 name string 103 cmd *digitalocean.UpdateCommand 104 api mock.API 105 want *fastly.UpdateDigitalOceanInput 106 wantError string 107 }{ 108 { 109 name: "all values set flag serviceID", 110 cmd: updateCommandAll(), 111 api: mock.API{ 112 ListVersionsFn: testutil.ListVersions, 113 CloneVersionFn: testutil.CloneVersionResult(4), 114 GetDigitalOceanFn: getDigitalOceanOK, 115 }, 116 want: &fastly.UpdateDigitalOceanInput{ 117 ServiceID: "123", 118 ServiceVersion: 4, 119 Name: "log", 120 NewName: fastly.ToPointer("new1"), 121 BucketName: fastly.ToPointer("new2"), 122 Domain: fastly.ToPointer("new3"), 123 AccessKey: fastly.ToPointer("new4"), 124 SecretKey: fastly.ToPointer("new5"), 125 Path: fastly.ToPointer("new6"), 126 Period: fastly.ToPointer(3601), 127 GzipLevel: fastly.ToPointer(0), 128 Format: fastly.ToPointer("new7"), 129 FormatVersion: fastly.ToPointer(3), 130 ResponseCondition: fastly.ToPointer("new8"), 131 MessageType: fastly.ToPointer("new9"), 132 TimestampFormat: fastly.ToPointer("new10"), 133 Placement: fastly.ToPointer("new11"), 134 PublicKey: fastly.ToPointer("new12"), 135 CompressionCodec: fastly.ToPointer("new13"), 136 }, 137 }, 138 { 139 name: "no updates", 140 cmd: updateCommandNoUpdates(), 141 api: mock.API{ 142 ListVersionsFn: testutil.ListVersions, 143 CloneVersionFn: testutil.CloneVersionResult(4), 144 GetDigitalOceanFn: getDigitalOceanOK, 145 }, 146 want: &fastly.UpdateDigitalOceanInput{ 147 ServiceID: "123", 148 ServiceVersion: 4, 149 Name: "log", 150 }, 151 }, 152 { 153 name: "error missing serviceID", 154 cmd: updateCommandMissingServiceID(), 155 want: nil, 156 wantError: errors.ErrNoServiceID.Error(), 157 }, 158 } 159 for testcaseIdx := range scenarios { 160 testcase := &scenarios[testcaseIdx] 161 t.Run(testcase.name, func(t *testing.T) { 162 testcase.cmd.Globals.APIClient = testcase.api 163 164 var bs []byte 165 out := bytes.NewBuffer(bs) 166 verboseMode := true 167 168 serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{ 169 AutoCloneFlag: testcase.cmd.AutoClone, 170 APIClient: testcase.api, 171 Manifest: testcase.cmd.Manifest, 172 Out: out, 173 ServiceVersionFlag: testcase.cmd.ServiceVersion, 174 VerboseMode: verboseMode, 175 }) 176 177 switch { 178 case err != nil && testcase.wantError == "": 179 t.Fatalf("unexpected error getting service details: %v", err) 180 return 181 case err != nil && testcase.wantError != "": 182 testutil.AssertErrorContains(t, err, testcase.wantError) 183 return 184 case err == nil && testcase.wantError != "": 185 t.Fatalf("expected error, have nil (service details: %s, %d)", serviceID, serviceVersion.Number) 186 case err == nil && testcase.wantError == "": 187 have, err := testcase.cmd.ConstructInput(serviceID, fastly.ToValue(serviceVersion.Number)) 188 testutil.AssertErrorContains(t, err, testcase.wantError) 189 testutil.AssertEqual(t, testcase.want, have) 190 } 191 }) 192 } 193 } 194 195 func createCommandRequired() *digitalocean.CreateCommand { 196 var b bytes.Buffer 197 198 g := global.Data{ 199 Config: config.File{}, 200 Env: config.Environment{}, 201 Output: &b, 202 } 203 g.APIClient, _ = mock.APIClient(mock.API{ 204 ListVersionsFn: testutil.ListVersions, 205 CloneVersionFn: testutil.CloneVersionResult(4), 206 })("token", "endpoint", false) 207 208 return &digitalocean.CreateCommand{ 209 Base: argparser.Base{ 210 Globals: &g, 211 }, 212 Manifest: manifest.Data{ 213 Flag: manifest.Flag{ 214 ServiceID: "123", 215 }, 216 }, 217 ServiceVersion: argparser.OptionalServiceVersion{ 218 OptionalString: argparser.OptionalString{Value: "1"}, 219 }, 220 AutoClone: argparser.OptionalAutoClone{ 221 OptionalBool: argparser.OptionalBool{ 222 Optional: argparser.Optional{ 223 WasSet: true, 224 }, 225 Value: true, 226 }, 227 }, 228 EndpointName: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "log"}, 229 BucketName: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "bucket"}, 230 AccessKey: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "access"}, 231 SecretKey: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "secret"}, 232 } 233 } 234 235 func createCommandAll() *digitalocean.CreateCommand { 236 var b bytes.Buffer 237 238 g := global.Data{ 239 Config: config.File{}, 240 Env: config.Environment{}, 241 Output: &b, 242 } 243 g.APIClient, _ = mock.APIClient(mock.API{ 244 ListVersionsFn: testutil.ListVersions, 245 CloneVersionFn: testutil.CloneVersionResult(4), 246 })("token", "endpoint", false) 247 248 return &digitalocean.CreateCommand{ 249 Base: argparser.Base{ 250 Globals: &g, 251 }, 252 Manifest: manifest.Data{ 253 Flag: manifest.Flag{ 254 ServiceID: "123", 255 }, 256 }, 257 ServiceVersion: argparser.OptionalServiceVersion{ 258 OptionalString: argparser.OptionalString{Value: "1"}, 259 }, 260 AutoClone: argparser.OptionalAutoClone{ 261 OptionalBool: argparser.OptionalBool{ 262 Optional: argparser.Optional{ 263 WasSet: true, 264 }, 265 Value: true, 266 }, 267 }, 268 EndpointName: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "log"}, 269 BucketName: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "bucket"}, 270 AccessKey: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "access"}, 271 SecretKey: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "secret"}, 272 Domain: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "nyc3.digitaloceanspaces.com"}, 273 Path: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "/log"}, 274 Period: argparser.OptionalInt{Optional: argparser.Optional{WasSet: true}, Value: 3600}, 275 Format: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: `%h %l %u %t "%r" %>s %b`}, 276 FormatVersion: argparser.OptionalInt{Optional: argparser.Optional{WasSet: true}, Value: 2}, 277 ResponseCondition: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "Prevent default logging"}, 278 TimestampFormat: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "%Y-%m-%dT%H:%M:%S.000"}, 279 Placement: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "none"}, 280 MessageType: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "classic"}, 281 PublicKey: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: pgpPublicKey()}, 282 CompressionCodec: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "zstd"}, 283 } 284 } 285 286 func createCommandMissingServiceID() *digitalocean.CreateCommand { 287 res := createCommandAll() 288 res.Manifest = manifest.Data{} 289 return res 290 } 291 292 func updateCommandNoUpdates() *digitalocean.UpdateCommand { 293 var b bytes.Buffer 294 295 g := global.Data{ 296 Config: config.File{}, 297 Env: config.Environment{}, 298 Output: &b, 299 } 300 301 return &digitalocean.UpdateCommand{ 302 Base: argparser.Base{ 303 Globals: &g, 304 }, 305 Manifest: manifest.Data{ 306 Flag: manifest.Flag{ 307 ServiceID: "123", 308 }, 309 }, 310 EndpointName: "log", 311 ServiceVersion: argparser.OptionalServiceVersion{ 312 OptionalString: argparser.OptionalString{Value: "1"}, 313 }, 314 AutoClone: argparser.OptionalAutoClone{ 315 OptionalBool: argparser.OptionalBool{ 316 Optional: argparser.Optional{ 317 WasSet: true, 318 }, 319 Value: true, 320 }, 321 }, 322 } 323 } 324 325 func updateCommandAll() *digitalocean.UpdateCommand { 326 var b bytes.Buffer 327 328 g := global.Data{ 329 Config: config.File{}, 330 Env: config.Environment{}, 331 Output: &b, 332 } 333 334 return &digitalocean.UpdateCommand{ 335 Base: argparser.Base{ 336 Globals: &g, 337 }, 338 Manifest: manifest.Data{ 339 Flag: manifest.Flag{ 340 ServiceID: "123", 341 }, 342 }, 343 EndpointName: "log", 344 ServiceVersion: argparser.OptionalServiceVersion{ 345 OptionalString: argparser.OptionalString{Value: "1"}, 346 }, 347 AutoClone: argparser.OptionalAutoClone{ 348 OptionalBool: argparser.OptionalBool{ 349 Optional: argparser.Optional{ 350 WasSet: true, 351 }, 352 Value: true, 353 }, 354 }, 355 NewName: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new1"}, 356 BucketName: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new2"}, 357 Domain: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new3"}, 358 AccessKey: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new4"}, 359 SecretKey: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new5"}, 360 Path: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new6"}, 361 Period: argparser.OptionalInt{Optional: argparser.Optional{WasSet: true}, Value: 3601}, 362 GzipLevel: argparser.OptionalInt{Optional: argparser.Optional{WasSet: true}, Value: 0}, 363 Format: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new7"}, 364 FormatVersion: argparser.OptionalInt{Optional: argparser.Optional{WasSet: true}, Value: 3}, 365 ResponseCondition: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new8"}, 366 MessageType: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new9"}, 367 TimestampFormat: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new10"}, 368 Placement: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new11"}, 369 PublicKey: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new12"}, 370 CompressionCodec: argparser.OptionalString{Optional: argparser.Optional{WasSet: true}, Value: "new13"}, 371 } 372 } 373 374 func updateCommandMissingServiceID() *digitalocean.UpdateCommand { 375 res := updateCommandAll() 376 res.Manifest = manifest.Data{} 377 return res 378 }