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