From 5f06ae1a331c46ded47c96c205b3f1be92d64d29 Mon Sep 17 00:00:00 2001 From: shubham-diwakar Date: Thu, 22 Aug 2024 22:04:19 +0530 Subject: [PATCH] feat(storage): add update time in bucketAttrs (#10710) Add update time field in bucketAttrs struct. Fixes #9361 --- storage/bucket.go | 6 ++++++ storage/bucket_test.go | 4 ++++ storage/integration_test.go | 15 +++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/storage/bucket.go b/storage/bucket.go index d582a60d0e83..3eded017831e 100644 --- a/storage/bucket.go +++ b/storage/bucket.go @@ -416,6 +416,10 @@ type BucketAttrs struct { // This field is read-only. Created time.Time + // Updated is the time at which the bucket was last modified. + // This field is read-only. + Updated time.Time + // VersioningEnabled reports whether this bucket has versioning enabled. VersioningEnabled bool @@ -824,6 +828,7 @@ func newBucket(b *raw.Bucket) (*BucketAttrs, error) { DefaultEventBasedHold: b.DefaultEventBasedHold, StorageClass: b.StorageClass, Created: convertTime(b.TimeCreated), + Updated: convertTime(b.Updated), VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled, ACL: toBucketACLRules(b.Acl), DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl), @@ -861,6 +866,7 @@ func newBucketFromProto(b *storagepb.Bucket) *BucketAttrs { DefaultEventBasedHold: b.GetDefaultEventBasedHold(), StorageClass: b.GetStorageClass(), Created: b.GetCreateTime().AsTime(), + Updated: b.GetUpdateTime().AsTime(), VersioningEnabled: b.GetVersioning().GetEnabled(), ACL: toBucketACLRulesFromProto(b.GetAcl()), DefaultObjectACL: toObjectACLRulesFromProto(b.GetDefaultObjectAcl()), diff --git a/storage/bucket_test.go b/storage/bucket_test.go index fd03c1e41907..7126be8331a6 100644 --- a/storage/bucket_test.go +++ b/storage/bucket_test.go @@ -605,6 +605,7 @@ func TestNewBucket(t *testing.T) { Metageneration: 3, StorageClass: "sc", TimeCreated: "2017-10-23T04:05:06Z", + Updated: "2024-08-21T17:24:53Z", Versioning: &raw.BucketVersioning{Enabled: true}, Labels: labels, Billing: &raw.BucketBilling{RequesterPays: true}, @@ -676,6 +677,7 @@ func TestNewBucket(t *testing.T) { MetaGeneration: 3, StorageClass: "sc", Created: time.Date(2017, 10, 23, 4, 5, 6, 0, time.UTC), + Updated: time.Date(2024, 8, 21, 17, 24, 53, 0, time.UTC), VersioningEnabled: true, Labels: labels, Etag: "Zkyw9ACJZUvcYmlFaKGChzhmtnE/dt1zHSfweiWpwzdGsqXwuJZqiD0", @@ -767,6 +769,7 @@ func TestNewBucketFromProto(t *testing.T) { Rpo: rpoAsyncTurbo, Metageneration: int64(39), CreateTime: toProtoTimestamp(time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)), + UpdateTime: toProtoTimestamp(time.Date(2024, 1, 2, 3, 4, 5, 6, time.UTC)), Labels: map[string]string{"label": "value"}, Cors: []*storagepb.Bucket_Cors{ { @@ -820,6 +823,7 @@ func TestNewBucketFromProto(t *testing.T) { RPO: RPOAsyncTurbo, MetaGeneration: 39, Created: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), + Updated: time.Date(2024, 1, 2, 3, 4, 5, 6, time.UTC), Labels: map[string]string{"label": "value"}, CORS: []CORS{ { diff --git a/storage/integration_test.go b/storage/integration_test.go index 941a534aa30e..aa3dd8b73088 100644 --- a/storage/integration_test.go +++ b/storage/integration_test.go @@ -589,6 +589,9 @@ func TestIntegration_BucketUpdate(t *testing.T) { if !testutil.Equal(attrs.Labels, wantLabels) { t.Fatalf("add labels: got %v, want %v", attrs.Labels, wantLabels) } + if !attrs.Created.Before(attrs.Updated) { + t.Errorf("got attrs.Updated %v before attrs.Created %v, want Attrs.Updated to be after", attrs.Updated, attrs.Created) + } // Turn off versioning again; add and remove some more labels. ua = BucketAttrsToUpdate{VersioningEnabled: false} @@ -607,6 +610,9 @@ func TestIntegration_BucketUpdate(t *testing.T) { if !testutil.Equal(attrs.Labels, wantLabels) { t.Fatalf("got %v, want %v", attrs.Labels, wantLabels) } + if !attrs.Created.Before(attrs.Updated) { + t.Errorf("got attrs.Updated %v before attrs.Created %v, want Attrs.Updated to be after", attrs.Updated, attrs.Created) + } // Configure a lifecycle wantLifecycle := Lifecycle{ @@ -626,6 +632,9 @@ func TestIntegration_BucketUpdate(t *testing.T) { if !testutil.Equal(attrs.Lifecycle, wantLifecycle) { t.Fatalf("got %v, want %v", attrs.Lifecycle, wantLifecycle) } + if !attrs.Created.Before(attrs.Updated) { + t.Errorf("got attrs.Updated %v before attrs.Created %v, want Attrs.Updated to be after", attrs.Updated, attrs.Created) + } // Check that StorageClass has "STANDARD" value for unset field by default // before passing new value. wantStorageClass := "STANDARD" @@ -638,6 +647,9 @@ func TestIntegration_BucketUpdate(t *testing.T) { if !testutil.Equal(attrs.StorageClass, wantStorageClass) { t.Fatalf("got %v, want %v", attrs.StorageClass, wantStorageClass) } + if !attrs.Created.Before(attrs.Updated) { + t.Errorf("got attrs.Updated %v before attrs.Created %v, want Attrs.Updated to be after", attrs.Updated, attrs.Created) + } // Empty update should succeed without changing the bucket. gotAttrs, err := b.Update(ctx, BucketAttrsToUpdate{}) @@ -647,6 +659,9 @@ func TestIntegration_BucketUpdate(t *testing.T) { if !testutil.Equal(attrs, gotAttrs) { t.Fatalf("empty update: got %v, want %v", gotAttrs, attrs) } + if !attrs.Created.Before(attrs.Updated) { + t.Errorf("got attrs.Updated %v before attrs.Created %v, want Attrs.Updated to be after", attrs.Updated, attrs.Created) + } }) }