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", "Lifecycle"}, 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 // Set an empty Lifecycle and verify that it will be sent. 416 au9 := &BucketAttrsToUpdate{ 417 Lifecycle: &Lifecycle{}, 418 } 419 got = au9.toRawBucket() 420 want = &raw.Bucket{ 421 Lifecycle: &raw.BucketLifecycle{ 422 ForceSendFields: []string{"Rule"}, 423 }, 424 ForceSendFields: []string{"Lifecycle"}, 425 } 426 if msg := testutil.Diff(got, want); msg != "" { 427 t.Errorf(msg) 428 } 429} 430 431func TestCallBuilders(t *testing.T) { 432 rc, err := raw.NewService(context.Background()) 433 if err != nil { 434 t.Fatal(err) 435 } 436 c := &Client{raw: rc} 437 const metagen = 17 438 439 b := c.Bucket("name") 440 bm := b.If(BucketConditions{MetagenerationMatch: metagen}).UserProject("p") 441 442 equal := func(x, y interface{}) bool { 443 return testutil.Equal(x, y, 444 cmp.AllowUnexported( 445 raw.BucketsGetCall{}, 446 raw.BucketsDeleteCall{}, 447 raw.BucketsPatchCall{}, 448 ), 449 cmp.FilterPath(func(p cmp.Path) bool { 450 return p[len(p)-1].Type() == reflect.TypeOf(&raw.Service{}) 451 }, cmp.Ignore()), 452 ) 453 } 454 455 for i, test := range []struct { 456 callFunc func(*BucketHandle) (interface{}, error) 457 want interface { 458 Header() http.Header 459 } 460 metagenFunc func(interface{}) 461 }{ 462 { 463 func(b *BucketHandle) (interface{}, error) { return b.newGetCall() }, 464 rc.Buckets.Get("name").Projection("full"), 465 func(req interface{}) { req.(*raw.BucketsGetCall).IfMetagenerationMatch(metagen).UserProject("p") }, 466 }, 467 { 468 func(b *BucketHandle) (interface{}, error) { return b.newDeleteCall() }, 469 rc.Buckets.Delete("name"), 470 func(req interface{}) { req.(*raw.BucketsDeleteCall).IfMetagenerationMatch(metagen).UserProject("p") }, 471 }, 472 { 473 func(b *BucketHandle) (interface{}, error) { 474 return b.newPatchCall(&BucketAttrsToUpdate{ 475 VersioningEnabled: false, 476 RequesterPays: false, 477 }) 478 }, 479 rc.Buckets.Patch("name", &raw.Bucket{ 480 Versioning: &raw.BucketVersioning{ 481 Enabled: false, 482 ForceSendFields: []string{"Enabled"}, 483 }, 484 Billing: &raw.BucketBilling{ 485 RequesterPays: false, 486 ForceSendFields: []string{"RequesterPays"}, 487 }, 488 }).Projection("full"), 489 func(req interface{}) { req.(*raw.BucketsPatchCall).IfMetagenerationMatch(metagen).UserProject("p") }, 490 }, 491 } { 492 got, err := test.callFunc(b) 493 if err != nil { 494 t.Fatal(err) 495 } 496 setClientHeader(test.want.Header()) 497 if !equal(got, test.want) { 498 t.Errorf("#%d: got %#v, want %#v", i, got, test.want) 499 } 500 got, err = test.callFunc(bm) 501 if err != nil { 502 t.Fatal(err) 503 } 504 test.metagenFunc(test.want) 505 if !equal(got, test.want) { 506 t.Errorf("#%d:\ngot %#v\nwant %#v", i, got, test.want) 507 } 508 } 509 510 // Error. 511 bm = b.If(BucketConditions{MetagenerationMatch: 1, MetagenerationNotMatch: 2}) 512 if _, err := bm.newGetCall(); err == nil { 513 t.Errorf("got nil, want error") 514 } 515 if _, err := bm.newDeleteCall(); err == nil { 516 t.Errorf("got nil, want error") 517 } 518 if _, err := bm.newPatchCall(&BucketAttrsToUpdate{}); err == nil { 519 t.Errorf("got nil, want error") 520 } 521} 522 523func TestNewBucket(t *testing.T) { 524 labels := map[string]string{"a": "b"} 525 matchClasses := []string{"STANDARD"} 526 aTime := time.Date(2017, 1, 2, 0, 0, 0, 0, time.UTC) 527 rb := &raw.Bucket{ 528 Name: "name", 529 Location: "loc", 530 DefaultEventBasedHold: true, 531 Metageneration: 3, 532 StorageClass: "sc", 533 TimeCreated: "2017-10-23T04:05:06Z", 534 Versioning: &raw.BucketVersioning{Enabled: true}, 535 Labels: labels, 536 Billing: &raw.BucketBilling{RequesterPays: true}, 537 Etag: "Zkyw9ACJZUvcYmlFaKGChzhmtnE/dt1zHSfweiWpwzdGsqXwuJZqiD0", 538 Lifecycle: &raw.BucketLifecycle{ 539 Rule: []*raw.BucketLifecycleRule{{ 540 Action: &raw.BucketLifecycleRuleAction{ 541 Type: "SetStorageClass", 542 StorageClass: "NEARLINE", 543 }, 544 Condition: &raw.BucketLifecycleRuleCondition{ 545 Age: 10, 546 IsLive: googleapi.Bool(true), 547 CreatedBefore: "2017-01-02", 548 MatchesStorageClass: matchClasses, 549 NumNewerVersions: 3, 550 }, 551 }}, 552 }, 553 RetentionPolicy: &raw.BucketRetentionPolicy{ 554 RetentionPeriod: 3, 555 EffectiveTime: aTime.Format(time.RFC3339), 556 }, 557 IamConfiguration: &raw.BucketIamConfiguration{ 558 BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{ 559 Enabled: true, 560 LockedTime: aTime.Format(time.RFC3339), 561 }, 562 UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ 563 Enabled: true, 564 LockedTime: aTime.Format(time.RFC3339), 565 }, 566 }, 567 Cors: []*raw.BucketCors{ 568 { 569 MaxAgeSeconds: 3600, 570 Method: []string{"GET", "POST"}, 571 Origin: []string{"*"}, 572 ResponseHeader: []string{"FOO"}, 573 }, 574 }, 575 Acl: []*raw.BucketAccessControl{ 576 {Bucket: "name", Role: "READER", Email: "joe@example.com", Entity: "allUsers"}, 577 }, 578 LocationType: "dual-region", 579 Encryption: &raw.BucketEncryption{DefaultKmsKeyName: "key"}, 580 Logging: &raw.BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, 581 Website: &raw.BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, 582 } 583 want := &BucketAttrs{ 584 Name: "name", 585 Location: "loc", 586 DefaultEventBasedHold: true, 587 MetaGeneration: 3, 588 StorageClass: "sc", 589 Created: time.Date(2017, 10, 23, 4, 5, 6, 0, time.UTC), 590 VersioningEnabled: true, 591 Labels: labels, 592 Etag: "Zkyw9ACJZUvcYmlFaKGChzhmtnE/dt1zHSfweiWpwzdGsqXwuJZqiD0", 593 RequesterPays: true, 594 Lifecycle: Lifecycle{ 595 Rules: []LifecycleRule{ 596 { 597 Action: LifecycleAction{ 598 Type: SetStorageClassAction, 599 StorageClass: "NEARLINE", 600 }, 601 Condition: LifecycleCondition{ 602 AgeInDays: 10, 603 Liveness: Live, 604 CreatedBefore: time.Date(2017, 1, 2, 0, 0, 0, 0, time.UTC), 605 MatchesStorageClasses: matchClasses, 606 NumNewerVersions: 3, 607 }, 608 }, 609 }, 610 }, 611 RetentionPolicy: &RetentionPolicy{ 612 EffectiveTime: aTime, 613 RetentionPeriod: 3 * time.Second, 614 }, 615 BucketPolicyOnly: BucketPolicyOnly{Enabled: true, LockedTime: aTime}, 616 UniformBucketLevelAccess: UniformBucketLevelAccess{Enabled: true, LockedTime: aTime}, 617 CORS: []CORS{ 618 { 619 MaxAge: time.Hour, 620 Methods: []string{"GET", "POST"}, 621 Origins: []string{"*"}, 622 ResponseHeaders: []string{"FOO"}, 623 }, 624 }, 625 Encryption: &BucketEncryption{DefaultKMSKeyName: "key"}, 626 Logging: &BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, 627 Website: &BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, 628 ACL: []ACLRule{{Entity: "allUsers", Role: RoleReader, Email: "joe@example.com"}}, 629 DefaultObjectACL: nil, 630 LocationType: "dual-region", 631 } 632 got, err := newBucket(rb) 633 if err != nil { 634 t.Fatal(err) 635 } 636 if diff := testutil.Diff(got, want); diff != "" { 637 t.Errorf("got=-, want=+:\n%s", diff) 638 } 639} 640