1// Copyright 2017 Google LLC 2// 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// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package storage 16 17import ( 18 "context" 19 "net/http" 20 "reflect" 21 "testing" 22 "time" 23 24 "cloud.google.com/go/internal/testutil" 25 "github.com/google/go-cmp/cmp" 26 "google.golang.org/api/googleapi" 27 raw "google.golang.org/api/storage/v1" 28) 29 30func TestBucketAttrsToRawBucket(t *testing.T) { 31 t.Parallel() 32 attrs := &BucketAttrs{ 33 Name: "name", 34 ACL: []ACLRule{{Entity: "bob@example.com", Role: RoleOwner, Domain: "d", Email: "e"}}, 35 DefaultObjectACL: []ACLRule{{Entity: AllUsers, Role: RoleReader, EntityID: "eid", 36 ProjectTeam: &ProjectTeam{ProjectNumber: "17", Team: "t"}}}, 37 Etag: "Zkyw9ACJZUvcYmlFaKGChzhmtnE/dt1zHSfweiWpwzdGsqXwuJZqiD0", 38 Location: "loc", 39 StorageClass: "class", 40 RetentionPolicy: &RetentionPolicy{ 41 RetentionPeriod: 3 * time.Second, 42 }, 43 BucketPolicyOnly: BucketPolicyOnly{Enabled: true}, 44 UniformBucketLevelAccess: UniformBucketLevelAccess{Enabled: true}, 45 VersioningEnabled: false, 46 // should be ignored: 47 MetaGeneration: 39, 48 Created: time.Now(), 49 Labels: map[string]string{"label": "value"}, 50 CORS: []CORS{ 51 { 52 MaxAge: time.Hour, 53 Methods: []string{"GET", "POST"}, 54 Origins: []string{"*"}, 55 ResponseHeaders: []string{"FOO"}, 56 }, 57 }, 58 Encryption: &BucketEncryption{DefaultKMSKeyName: "key"}, 59 Logging: &BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, 60 Website: &BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, 61 Lifecycle: Lifecycle{ 62 Rules: []LifecycleRule{{ 63 Action: LifecycleAction{ 64 Type: SetStorageClassAction, 65 StorageClass: "NEARLINE", 66 }, 67 Condition: LifecycleCondition{ 68 AgeInDays: 10, 69 Liveness: Live, 70 CreatedBefore: time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC), 71 MatchesStorageClasses: []string{"STANDARD"}, 72 NumNewerVersions: 3, 73 }, 74 }, { 75 Action: LifecycleAction{ 76 Type: DeleteAction, 77 }, 78 Condition: LifecycleCondition{ 79 AgeInDays: 30, 80 Liveness: Live, 81 CreatedBefore: time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC), 82 MatchesStorageClasses: []string{"NEARLINE"}, 83 NumNewerVersions: 10, 84 }, 85 }, { 86 Action: LifecycleAction{ 87 Type: DeleteAction, 88 }, 89 Condition: LifecycleCondition{ 90 Liveness: Archived, 91 }, 92 }}, 93 }, 94 } 95 got := attrs.toRawBucket() 96 want := &raw.Bucket{ 97 Name: "name", 98 Acl: []*raw.BucketAccessControl{ 99 {Entity: "bob@example.com", Role: "OWNER"}, // other fields ignored on create/update 100 }, 101 DefaultObjectAcl: []*raw.ObjectAccessControl{ 102 {Entity: "allUsers", Role: "READER"}, // other fields ignored on create/update 103 }, 104 Location: "loc", 105 StorageClass: "class", 106 RetentionPolicy: &raw.BucketRetentionPolicy{ 107 RetentionPeriod: 3, 108 }, 109 IamConfiguration: &raw.BucketIamConfiguration{ 110 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 111 Enabled: true, 112 }, 113 }, 114 Versioning: nil, // ignore VersioningEnabled if false 115 Labels: map[string]string{"label": "value"}, 116 Cors: []*raw.BucketCors{ 117 { 118 MaxAgeSeconds: 3600, 119 Method: []string{"GET", "POST"}, 120 Origin: []string{"*"}, 121 ResponseHeader: []string{"FOO"}, 122 }, 123 }, 124 Encryption: &raw.BucketEncryption{DefaultKmsKeyName: "key"}, 125 Logging: &raw.BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, 126 Website: &raw.BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, 127 Lifecycle: &raw.BucketLifecycle{ 128 Rule: []*raw.BucketLifecycleRule{{ 129 Action: &raw.BucketLifecycleRuleAction{ 130 Type: SetStorageClassAction, 131 StorageClass: "NEARLINE", 132 }, 133 Condition: &raw.BucketLifecycleRuleCondition{ 134 Age: 10, 135 IsLive: googleapi.Bool(true), 136 CreatedBefore: "2017-01-02", 137 MatchesStorageClass: []string{"STANDARD"}, 138 NumNewerVersions: 3, 139 }, 140 }, { 141 Action: &raw.BucketLifecycleRuleAction{ 142 Type: DeleteAction, 143 }, 144 Condition: &raw.BucketLifecycleRuleCondition{ 145 Age: 30, 146 IsLive: googleapi.Bool(true), 147 CreatedBefore: "2017-01-02", 148 MatchesStorageClass: []string{"NEARLINE"}, 149 NumNewerVersions: 10, 150 }, 151 }, { 152 Action: &raw.BucketLifecycleRuleAction{ 153 Type: DeleteAction, 154 }, 155 Condition: &raw.BucketLifecycleRuleCondition{ 156 IsLive: googleapi.Bool(false), 157 }, 158 }}, 159 }, 160 } 161 if msg := testutil.Diff(got, want); msg != "" { 162 t.Error(msg) 163 } 164 165 attrs.VersioningEnabled = true 166 attrs.RequesterPays = true 167 got = attrs.toRawBucket() 168 want.Versioning = &raw.BucketVersioning{Enabled: true} 169 want.Billing = &raw.BucketBilling{RequesterPays: true} 170 if msg := testutil.Diff(got, want); msg != "" { 171 t.Error(msg) 172 } 173 174 // Test that setting either of BucketPolicyOnly or UniformBucketLevelAccess 175 // will enable UniformBucketLevelAccess. 176 // Set UBLA.Enabled = true --> UBLA should be set to enabled in the proto. 177 attrs.BucketPolicyOnly = BucketPolicyOnly{} 178 attrs.UniformBucketLevelAccess = UniformBucketLevelAccess{Enabled: true} 179 got = attrs.toRawBucket() 180 want.IamConfiguration = &raw.BucketIamConfiguration{ 181 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 182 Enabled: true, 183 }, 184 } 185 if msg := testutil.Diff(got, want); msg != "" { 186 t.Errorf(msg) 187 } 188 189 // Set BucketPolicyOnly.Enabled = true --> UBLA should be set to enabled in 190 // the proto. 191 attrs.BucketPolicyOnly = BucketPolicyOnly{Enabled: true} 192 attrs.UniformBucketLevelAccess = UniformBucketLevelAccess{} 193 got = attrs.toRawBucket() 194 want.IamConfiguration = &raw.BucketIamConfiguration{ 195 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 196 Enabled: true, 197 }, 198 } 199 if msg := testutil.Diff(got, want); msg != "" { 200 t.Errorf(msg) 201 } 202 203 // Set both BucketPolicyOnly.Enabled = true and 204 // UniformBucketLevelAccess.Enabled=true --> UBLA should be set to enabled 205 // in the proto. 206 attrs.BucketPolicyOnly = BucketPolicyOnly{Enabled: true} 207 attrs.UniformBucketLevelAccess = UniformBucketLevelAccess{Enabled: true} 208 got = attrs.toRawBucket() 209 want.IamConfiguration = &raw.BucketIamConfiguration{ 210 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 211 Enabled: true, 212 }, 213 } 214 if msg := testutil.Diff(got, want); msg != "" { 215 t.Errorf(msg) 216 } 217 218 // Set UBLA.Enabled=false and BucketPolicyOnly.Enabled=false --> UBLA 219 // should be disabled in the proto. 220 attrs.BucketPolicyOnly = BucketPolicyOnly{} 221 attrs.UniformBucketLevelAccess = UniformBucketLevelAccess{} 222 got = attrs.toRawBucket() 223 want.IamConfiguration = nil 224 if msg := testutil.Diff(got, want); msg != "" { 225 t.Errorf(msg) 226 } 227} 228 229func TestBucketAttrsToUpdateToRawBucket(t *testing.T) { 230 t.Parallel() 231 au := &BucketAttrsToUpdate{ 232 VersioningEnabled: false, 233 RequesterPays: false, 234 BucketPolicyOnly: &BucketPolicyOnly{Enabled: false}, 235 UniformBucketLevelAccess: &UniformBucketLevelAccess{Enabled: false}, 236 DefaultEventBasedHold: false, 237 RetentionPolicy: &RetentionPolicy{RetentionPeriod: time.Hour}, 238 Encryption: &BucketEncryption{DefaultKMSKeyName: "key2"}, 239 Lifecycle: &Lifecycle{ 240 Rules: []LifecycleRule{ 241 { 242 Action: LifecycleAction{Type: "Delete"}, 243 Condition: LifecycleCondition{AgeInDays: 30}, 244 }, 245 }, 246 }, 247 Logging: &BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, 248 Website: &BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, 249 } 250 au.SetLabel("a", "foo") 251 au.DeleteLabel("b") 252 au.SetLabel("c", "") 253 got := au.toRawBucket() 254 want := &raw.Bucket{ 255 Versioning: &raw.BucketVersioning{ 256 Enabled: false, 257 ForceSendFields: []string{"Enabled"}, 258 }, 259 Labels: map[string]string{ 260 "a": "foo", 261 "c": "", 262 }, 263 Billing: &raw.BucketBilling{ 264 RequesterPays: false, 265 ForceSendFields: []string{"RequesterPays"}, 266 }, 267 DefaultEventBasedHold: false, 268 RetentionPolicy: &raw.BucketRetentionPolicy{RetentionPeriod: 3600}, 269 IamConfiguration: &raw.BucketIamConfiguration{ 270 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 271 Enabled: false, 272 ForceSendFields: []string{"Enabled"}, 273 }, 274 }, 275 Encryption: &raw.BucketEncryption{DefaultKmsKeyName: "key2"}, 276 NullFields: []string{"Labels.b"}, 277 Lifecycle: &raw.BucketLifecycle{ 278 Rule: []*raw.BucketLifecycleRule{ 279 { 280 Action: &raw.BucketLifecycleRuleAction{Type: "Delete"}, 281 Condition: &raw.BucketLifecycleRuleCondition{Age: 30}, 282 }, 283 }, 284 }, 285 Logging: &raw.BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, 286 Website: &raw.BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, 287 ForceSendFields: []string{"DefaultEventBasedHold"}, 288 } 289 if msg := testutil.Diff(got, want); msg != "" { 290 t.Error(msg) 291 } 292 293 var au2 BucketAttrsToUpdate 294 au2.DeleteLabel("b") 295 got = au2.toRawBucket() 296 want = &raw.Bucket{ 297 Labels: map[string]string{}, 298 ForceSendFields: []string{"Labels"}, 299 NullFields: []string{"Labels.b"}, 300 } 301 if msg := testutil.Diff(got, want); msg != "" { 302 t.Error(msg) 303 } 304 305 // Test nulls. 306 au3 := &BucketAttrsToUpdate{ 307 RetentionPolicy: &RetentionPolicy{}, 308 Encryption: &BucketEncryption{}, 309 Logging: &BucketLogging{}, 310 Website: &BucketWebsite{}, 311 } 312 got = au3.toRawBucket() 313 want = &raw.Bucket{ 314 NullFields: []string{"RetentionPolicy", "Encryption", "Logging", "Website"}, 315 } 316 if msg := testutil.Diff(got, want); msg != "" { 317 t.Error(msg) 318 } 319 320 // Test that setting either of BucketPolicyOnly or UniformBucketLevelAccess 321 // will enable UniformBucketLevelAccess. 322 // Set UBLA.Enabled = true --> UBLA should be set to enabled in the proto. 323 au4 := &BucketAttrsToUpdate{ 324 UniformBucketLevelAccess: &UniformBucketLevelAccess{Enabled: true}, 325 } 326 got = au4.toRawBucket() 327 want = &raw.Bucket{ 328 IamConfiguration: &raw.BucketIamConfiguration{ 329 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 330 Enabled: true, 331 ForceSendFields: []string{"Enabled"}, 332 }, 333 }, 334 } 335 if msg := testutil.Diff(got, want); msg != "" { 336 t.Errorf(msg) 337 } 338 339 // Set BucketPolicyOnly.Enabled = true --> UBLA should be set to enabled in 340 // the proto. 341 au5 := &BucketAttrsToUpdate{ 342 BucketPolicyOnly: &BucketPolicyOnly{Enabled: true}, 343 } 344 got = au5.toRawBucket() 345 want = &raw.Bucket{ 346 IamConfiguration: &raw.BucketIamConfiguration{ 347 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 348 Enabled: true, 349 ForceSendFields: []string{"Enabled"}, 350 }, 351 }, 352 } 353 if msg := testutil.Diff(got, want); msg != "" { 354 t.Errorf(msg) 355 } 356 357 // Set both BucketPolicyOnly.Enabled = true and 358 // UniformBucketLevelAccess.Enabled=true --> UBLA should be set to enabled 359 // in the proto. 360 au6 := &BucketAttrsToUpdate{ 361 BucketPolicyOnly: &BucketPolicyOnly{Enabled: true}, 362 UniformBucketLevelAccess: &UniformBucketLevelAccess{Enabled: true}, 363 } 364 got = au6.toRawBucket() 365 want = &raw.Bucket{ 366 IamConfiguration: &raw.BucketIamConfiguration{ 367 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 368 Enabled: true, 369 ForceSendFields: []string{"Enabled"}, 370 }, 371 }, 372 } 373 if msg := testutil.Diff(got, want); msg != "" { 374 t.Errorf(msg) 375 } 376 377 // Set UBLA.Enabled=false and BucketPolicyOnly.Enabled=false --> UBLA 378 // should be disabled in the proto. 379 au7 := &BucketAttrsToUpdate{ 380 BucketPolicyOnly: &BucketPolicyOnly{Enabled: false}, 381 UniformBucketLevelAccess: &UniformBucketLevelAccess{Enabled: false}, 382 } 383 got = au7.toRawBucket() 384 want = &raw.Bucket{ 385 IamConfiguration: &raw.BucketIamConfiguration{ 386 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 387 Enabled: false, 388 ForceSendFields: []string{"Enabled"}, 389 }, 390 }, 391 } 392 if msg := testutil.Diff(got, want); msg != "" { 393 t.Errorf(msg) 394 } 395 396 // UBLA.Enabled will have precedence above BucketPolicyOnly.Enabled if both 397 // are set with different values. 398 au8 := &BucketAttrsToUpdate{ 399 BucketPolicyOnly: &BucketPolicyOnly{Enabled: true}, 400 UniformBucketLevelAccess: &UniformBucketLevelAccess{Enabled: false}, 401 } 402 got = au8.toRawBucket() 403 want = &raw.Bucket{ 404 IamConfiguration: &raw.BucketIamConfiguration{ 405 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 406 Enabled: false, 407 ForceSendFields: []string{"Enabled"}, 408 }, 409 }, 410 } 411 if msg := testutil.Diff(got, want); msg != "" { 412 t.Errorf(msg) 413 } 414} 415 416func TestCallBuilders(t *testing.T) { 417 rc, err := raw.NewService(context.Background()) 418 if err != nil { 419 t.Fatal(err) 420 } 421 c := &Client{raw: rc} 422 const metagen = 17 423 424 b := c.Bucket("name") 425 bm := b.If(BucketConditions{MetagenerationMatch: metagen}).UserProject("p") 426 427 equal := func(x, y interface{}) bool { 428 return testutil.Equal(x, y, 429 cmp.AllowUnexported( 430 raw.BucketsGetCall{}, 431 raw.BucketsDeleteCall{}, 432 raw.BucketsPatchCall{}, 433 ), 434 cmp.FilterPath(func(p cmp.Path) bool { 435 return p[len(p)-1].Type() == reflect.TypeOf(&raw.Service{}) 436 }, cmp.Ignore()), 437 ) 438 } 439 440 for i, test := range []struct { 441 callFunc func(*BucketHandle) (interface{}, error) 442 want interface { 443 Header() http.Header 444 } 445 metagenFunc func(interface{}) 446 }{ 447 { 448 func(b *BucketHandle) (interface{}, error) { return b.newGetCall() }, 449 rc.Buckets.Get("name").Projection("full"), 450 func(req interface{}) { req.(*raw.BucketsGetCall).IfMetagenerationMatch(metagen).UserProject("p") }, 451 }, 452 { 453 func(b *BucketHandle) (interface{}, error) { return b.newDeleteCall() }, 454 rc.Buckets.Delete("name"), 455 func(req interface{}) { req.(*raw.BucketsDeleteCall).IfMetagenerationMatch(metagen).UserProject("p") }, 456 }, 457 { 458 func(b *BucketHandle) (interface{}, error) { 459 return b.newPatchCall(&BucketAttrsToUpdate{ 460 VersioningEnabled: false, 461 RequesterPays: false, 462 }) 463 }, 464 rc.Buckets.Patch("name", &raw.Bucket{ 465 Versioning: &raw.BucketVersioning{ 466 Enabled: false, 467 ForceSendFields: []string{"Enabled"}, 468 }, 469 Billing: &raw.BucketBilling{ 470 RequesterPays: false, 471 ForceSendFields: []string{"RequesterPays"}, 472 }, 473 }).Projection("full"), 474 func(req interface{}) { req.(*raw.BucketsPatchCall).IfMetagenerationMatch(metagen).UserProject("p") }, 475 }, 476 } { 477 got, err := test.callFunc(b) 478 if err != nil { 479 t.Fatal(err) 480 } 481 setClientHeader(test.want.Header()) 482 if !equal(got, test.want) { 483 t.Errorf("#%d: got %#v, want %#v", i, got, test.want) 484 } 485 got, err = test.callFunc(bm) 486 if err != nil { 487 t.Fatal(err) 488 } 489 test.metagenFunc(test.want) 490 if !equal(got, test.want) { 491 t.Errorf("#%d:\ngot %#v\nwant %#v", i, got, test.want) 492 } 493 } 494 495 // Error. 496 bm = b.If(BucketConditions{MetagenerationMatch: 1, MetagenerationNotMatch: 2}) 497 if _, err := bm.newGetCall(); err == nil { 498 t.Errorf("got nil, want error") 499 } 500 if _, err := bm.newDeleteCall(); err == nil { 501 t.Errorf("got nil, want error") 502 } 503 if _, err := bm.newPatchCall(&BucketAttrsToUpdate{}); err == nil { 504 t.Errorf("got nil, want error") 505 } 506} 507 508func TestNewBucket(t *testing.T) { 509 labels := map[string]string{"a": "b"} 510 matchClasses := []string{"STANDARD"} 511 aTime := time.Date(2017, 1, 2, 0, 0, 0, 0, time.UTC) 512 rb := &raw.Bucket{ 513 Name: "name", 514 Location: "loc", 515 DefaultEventBasedHold: true, 516 Metageneration: 3, 517 StorageClass: "sc", 518 TimeCreated: "2017-10-23T04:05:06Z", 519 Versioning: &raw.BucketVersioning{Enabled: true}, 520 Labels: labels, 521 Billing: &raw.BucketBilling{RequesterPays: true}, 522 Etag: "Zkyw9ACJZUvcYmlFaKGChzhmtnE/dt1zHSfweiWpwzdGsqXwuJZqiD0", 523 Lifecycle: &raw.BucketLifecycle{ 524 Rule: []*raw.BucketLifecycleRule{{ 525 Action: &raw.BucketLifecycleRuleAction{ 526 Type: "SetStorageClass", 527 StorageClass: "NEARLINE", 528 }, 529 Condition: &raw.BucketLifecycleRuleCondition{ 530 Age: 10, 531 IsLive: googleapi.Bool(true), 532 CreatedBefore: "2017-01-02", 533 MatchesStorageClass: matchClasses, 534 NumNewerVersions: 3, 535 }, 536 }}, 537 }, 538 RetentionPolicy: &raw.BucketRetentionPolicy{ 539 RetentionPeriod: 3, 540 EffectiveTime: aTime.Format(time.RFC3339), 541 }, 542 IamConfiguration: &raw.BucketIamConfiguration{ 543 BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{ 544 Enabled: true, 545 LockedTime: aTime.Format(time.RFC3339), 546 }, 547 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 548 Enabled: true, 549 LockedTime: aTime.Format(time.RFC3339), 550 }, 551 }, 552 Cors: []*raw.BucketCors{ 553 { 554 MaxAgeSeconds: 3600, 555 Method: []string{"GET", "POST"}, 556 Origin: []string{"*"}, 557 ResponseHeader: []string{"FOO"}, 558 }, 559 }, 560 Acl: []*raw.BucketAccessControl{ 561 {Bucket: "name", Role: "READER", Email: "joe@example.com", Entity: "allUsers"}, 562 }, 563 LocationType: "dual-region", 564 Encryption: &raw.BucketEncryption{DefaultKmsKeyName: "key"}, 565 Logging: &raw.BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, 566 Website: &raw.BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, 567 } 568 want := &BucketAttrs{ 569 Name: "name", 570 Location: "loc", 571 DefaultEventBasedHold: true, 572 MetaGeneration: 3, 573 StorageClass: "sc", 574 Created: time.Date(2017, 10, 23, 4, 5, 6, 0, time.UTC), 575 VersioningEnabled: true, 576 Labels: labels, 577 Etag: "Zkyw9ACJZUvcYmlFaKGChzhmtnE/dt1zHSfweiWpwzdGsqXwuJZqiD0", 578 RequesterPays: true, 579 Lifecycle: Lifecycle{ 580 Rules: []LifecycleRule{ 581 { 582 Action: LifecycleAction{ 583 Type: SetStorageClassAction, 584 StorageClass: "NEARLINE", 585 }, 586 Condition: LifecycleCondition{ 587 AgeInDays: 10, 588 Liveness: Live, 589 CreatedBefore: time.Date(2017, 1, 2, 0, 0, 0, 0, time.UTC), 590 MatchesStorageClasses: matchClasses, 591 NumNewerVersions: 3, 592 }, 593 }, 594 }, 595 }, 596 RetentionPolicy: &RetentionPolicy{ 597 EffectiveTime: aTime, 598 RetentionPeriod: 3 * time.Second, 599 }, 600 BucketPolicyOnly: BucketPolicyOnly{Enabled: true, LockedTime: aTime}, 601 UniformBucketLevelAccess: UniformBucketLevelAccess{Enabled: true, LockedTime: aTime}, 602 CORS: []CORS{ 603 { 604 MaxAge: time.Hour, 605 Methods: []string{"GET", "POST"}, 606 Origins: []string{"*"}, 607 ResponseHeaders: []string{"FOO"}, 608 }, 609 }, 610 Encryption: &BucketEncryption{DefaultKMSKeyName: "key"}, 611 Logging: &BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, 612 Website: &BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, 613 ACL: []ACLRule{{Entity: "allUsers", Role: RoleReader, Email: "joe@example.com"}}, 614 DefaultObjectACL: nil, 615 LocationType: "dual-region", 616 } 617 got, err := newBucket(rb) 618 if err != nil { 619 t.Fatal(err) 620 } 621 if diff := testutil.Diff(got, want); diff != "" { 622 t.Errorf("got=-, want=+:\n%s", diff) 623 } 624} 625