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