Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(storage): support bucket restore in soft delete phase 2 #13894

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

mahendra-google
Copy link

Feature request includes the following:-

  1. Get Bucket Generation
  2. Get a Soft Deleted Bucket (Also soft-delete time and hard-delete time)
  3. List Soft Deleted Buckets
  4. Restore a Soft Deleted Bucket

@mahendra-google mahendra-google requested review from a team as code owners November 28, 2024 12:39
@product-auto-label product-auto-label bot added the api: storage Issues related to the Cloud Storage API. label Nov 28, 2024
Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a full code review by any means, but I'm hoping that this little bit will reduce the number of iterations required after Amanda is back from Thanksgiving.

@mahendra-google
Copy link
Author

This is not a full code review by any means, but I'm hoping that this little bit will reduce the number of iterations required after Amanda is back from Thanksgiving.

Ok

@jskeet
Copy link
Collaborator

jskeet commented Nov 29, 2024

Unassigning myself from review - I'm on vacation until Tuesday. (I expect Amanda will review before then.)

@amanda-tarafa amanda-tarafa self-assigned this Dec 3, 2024
@amanda-tarafa
Copy link
Contributor

I'll review today. @mahendra-google if you can rebase on main to remove conflicts, that'd be great, thanks.

@mahendra-google
Copy link
Author

I'll review today. @mahendra-google if you can rebase on main to remove conflicts, that'd be great, thanks.

@amanda-tarafa I have removed conflict for Directory.Packages.props file.

@mahendra-google
Copy link
Author

I'll review today. @mahendra-google if you can rebase on main to remove conflicts, that'd be great, thanks.

@amanda-tarafa I have removed conflict for Directory.Packages.props file.

@amanda-tarafa I have removed project file conflict.

@mahendra-google
Copy link
Author

mahendra-google commented Dec 6, 2024

@amanda-tarafa Storage Samples requires latest package of Google.Cloud.Storage.V1 having properties of GetBucketOptions , ListBucketOptions, RestoreBucketOptions to work sample as expected. So for samples can I proceed with lastest dlls?

Copy link
Contributor

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to add unit tests for all the option classes that you modified. See #12060 for examples.

@mahendra-google mahendra-google force-pushed the restore_bucket_soft_delete_phase_2 branch from cb1650a to db71efc Compare January 28, 2025 06:01
@mahendra-google
Copy link
Author

You need to add unit tests for all the option classes that you modified. See #12060 for examples.

Unit tests for all the option classes are added that I have modified

@danielduhh
Copy link

This is ready for a re-review @amanda-tarafa

@amanda-tarafa
Copy link
Contributor

Thanks, I'll do a pass tomorrow.

Copy link
Contributor

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there, thanks!

Comment on lines 86 to 96
foreach (var bucket in actualBuckets)
{ // Verify if the bucket is soft-deleted only
Assert.NotNull(bucket.Generation);
Assert.NotNull(bucket.SoftDeleteTimeDateTimeOffset);
Assert.NotNull(bucket.HardDeleteTimeDateTimeOffset);

if (bucket.Name == softDeleteBucket.Name)
{ // Compare the generation number
Assert.Equal(bucket.Generation, softDeleteBucket.Generation);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Assert.All and Assert.Contains instead of a loop here.

Copy link
Author

@mahendra-google mahendra-google Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amanda-tarafa Is it not working as expected ? because these changes are approved by My team's silver language leads using the Internal PR review approval process.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are different ways to achieve the same result, some are clearer than others. Please use Assert.All and Asssert.Contains.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, is not only about clarity, this test is not sufficient as it is. It will pass even if actualBuckets is empty or if it does not contains softDeleteBucket. Using Assert.All and Assert.Contains will make the test sufficient.

Copy link
Author

@mahendra-google mahendra-google Feb 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amanda-tarafa If actualBuckets is made empty (actualBuckets = new List<Bucket>();), count will be zero , it will not go inside foreach loop , So it will not pass , I would rather say it will skip assert. Let me know your thoughts on this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amanda-tarafa On the same lines , if I don't create a soft delete bucket in test itself (which I already created if I remove that piece of code of creation of soft delete bucket ) and hypothetically assuming storage fixture has also not created any soft delete bucket in any other tests , According to me in that case also actualBuckets count will be zero and it will not go inside loop. So it will skip asserts. Does that mean test should fail rather skip ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test that executes no asserts, assuming there are no exceptions (none in this case), is a passing test, it's not a skipped test. A passing test indicates that the feature has been tested and everything is working as expected, whereas a skipped test indicates that nothing was tested. This test is wrong because it may pass even when nothing is tested.

Explicitly, if there is a bug in production code that has the effect of the list returning empty (even when you have just created a soft deleted bucket), this test will pass, when it shouldn't have. That's because this test is saying:

  • Create a soft deleted bucket (correct, we guarantee there's at least one soft deleted bucket so we can test).
  • Fetch soft deleted buckets (the feature we want to test).
  • If there happens to be elements in the list, make sure they are all soft deleted. (hmm, if the feature we want to test is broken so that the list is empty, then we really don't test anything and we don't find out the feature is broken)
  • If the recently created bucket happens to be on the list, make sure all its fields have the expected values and that it is indeed soft deleted. (hmm, if the feature we want to test is broken so that the list is empty, then we really don't test anything and we don't find out the feature is broken)

The key being the "if it happens" where a test needs to make certain "it happened", no ifs and no buts.

What this test needs to do is:

  • Create a soft deleted bucket
  • Fetch soft deleted buckets
  • Make sure the recently created bucket is on the list, and all its fields have the expected values.
  • Make sure all the elements on the list are indeed soft deleted. Apart from the test own bucket, these may be buckets created by the fixture or by other tests, we don't care if there are none of these, or many, because we don't care about the order in which tests execute. The only thing that we care is that all tests in the list are soft deleted because that's the feature we are testing.

See those two last points describing the correct test, how they very naturally transalate to:

  • Assert.Contains recently created bucket with the right fields.
  • Assert.All are soft deletede buckets

You can certainly express the same semantic with a loop and some checks, but, it's way less naturally readable plus, errors like the one currently in this test are harder to spot and harder to explain, as this very thread demonstrates. Using the right assert statements makes the tests robust and correct more easily, plus way clearer.

Please fix.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the elaborated reply it clears some of my doubts about the test as well especially the production bug scenario.

Comment on lines 86 to 96
foreach (var bucket in actualBuckets)
{ // Verify if the bucket is soft-deleted only
Assert.NotNull(bucket.Generation);
Assert.NotNull(bucket.SoftDeleteTimeDateTimeOffset);
Assert.NotNull(bucket.HardDeleteTimeDateTimeOffset);

if (bucket.Name == softDeleteBucket.Name)
{ // Compare the generation number
Assert.Equal(bucket.Generation, softDeleteBucket.Generation);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are different ways to achieve the same result, some are clearer than others. Please use Assert.All and Asssert.Contains.

Comment on lines 86 to 96
foreach (var bucket in actualBuckets)
{ // Verify if the bucket is soft-deleted only
Assert.NotNull(bucket.Generation);
Assert.NotNull(bucket.SoftDeleteTimeDateTimeOffset);
Assert.NotNull(bucket.HardDeleteTimeDateTimeOffset);

if (bucket.Name == softDeleteBucket.Name)
{ // Compare the generation number
Assert.Equal(bucket.Generation, softDeleteBucket.Generation);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, is not only about clarity, this test is not sufficient as it is. It will pass even if actualBuckets is empty or if it does not contains softDeleteBucket. Using Assert.All and Assert.Contains will make the test sufficient.

Comment on lines 86 to 96
foreach (var bucket in actualBuckets)
{ // Verify if the bucket is soft-deleted only
Assert.NotNull(bucket.Generation);
Assert.NotNull(bucket.SoftDeleteTimeDateTimeOffset);
Assert.NotNull(bucket.HardDeleteTimeDateTimeOffset);

if (bucket.Name == softDeleteBucket.Name)
{ // Compare the generation number
Assert.Equal(bucket.Generation, softDeleteBucket.Generation);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test that executes no asserts, assuming there are no exceptions (none in this case), is a passing test, it's not a skipped test. A passing test indicates that the feature has been tested and everything is working as expected, whereas a skipped test indicates that nothing was tested. This test is wrong because it may pass even when nothing is tested.

Explicitly, if there is a bug in production code that has the effect of the list returning empty (even when you have just created a soft deleted bucket), this test will pass, when it shouldn't have. That's because this test is saying:

  • Create a soft deleted bucket (correct, we guarantee there's at least one soft deleted bucket so we can test).
  • Fetch soft deleted buckets (the feature we want to test).
  • If there happens to be elements in the list, make sure they are all soft deleted. (hmm, if the feature we want to test is broken so that the list is empty, then we really don't test anything and we don't find out the feature is broken)
  • If the recently created bucket happens to be on the list, make sure all its fields have the expected values and that it is indeed soft deleted. (hmm, if the feature we want to test is broken so that the list is empty, then we really don't test anything and we don't find out the feature is broken)

The key being the "if it happens" where a test needs to make certain "it happened", no ifs and no buts.

What this test needs to do is:

  • Create a soft deleted bucket
  • Fetch soft deleted buckets
  • Make sure the recently created bucket is on the list, and all its fields have the expected values.
  • Make sure all the elements on the list are indeed soft deleted. Apart from the test own bucket, these may be buckets created by the fixture or by other tests, we don't care if there are none of these, or many, because we don't care about the order in which tests execute. The only thing that we care is that all tests in the list are soft deleted because that's the feature we are testing.

See those two last points describing the correct test, how they very naturally transalate to:

  • Assert.Contains recently created bucket with the right fields.
  • Assert.All are soft deletede buckets

You can certainly express the same semantic with a loop and some checks, but, it's way less naturally readable plus, errors like the one currently in this test are harder to spot and harder to explain, as this very thread demonstrates. Using the right assert statements makes the tests robust and correct more easily, plus way clearer.

Please fix.

@amanda-tarafa
Copy link
Contributor

@mahendra-google Do let me know here when this is ready for review again. No rush on my part, but just know I won't review until you have said so here. Thanks!

@mahendra-google
Copy link
Author

@mahendra-google Do let me know here when this is ready for review again. No rush on my part, but just know I won't review until you have said so here. Thanks!

@amanda-tarafa Yes right , I will leave a comment for re-review in PR itself like @danielduhh left , apart from clicking on re-review icon post completion of internal PR review from my team as a part of process. Thanks!

@amanda-tarafa
Copy link
Contributor

@amanda-tarafa Yes right , I will leave a comment for re-review in PR itself like @danielduhh left , apart from clicking on re-review icon post completion of internal PR review from my team as a part of process. Thanks!

That's perfect, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: storage Issues related to the Cloud Storage API.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants