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

Added tests for compaction backward compatibility #1

Merged
merged 1 commit into from
Jun 9, 2021

Conversation

aaronfern
Copy link

What this PR does / why we need it:
Adds local store test cases to verify the backward compatibility of compaction with respect to garbage collection and restorer

Which issue(s) this PR fixes:
Partially Fixes gardener/etcd-druid#88

Special notes for your reviewer:

Release note:

NONE

@@ -645,6 +662,222 @@ var _ = Describe("Running Restorer", func() {

})

Describe("NEGATIVE:For scenarios involving both old as well as updated directory structures being present", func() {
Copy link
Owner

Choose a reason for hiding this comment

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

Why did you mark it as NEGATIVE ? It should be like other test cases.

Copy link
Author

Choose a reason for hiding this comment

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

Removed the NEGATIVE tag

Copy link

@amshuman-kr amshuman-kr left a comment

Choose a reason for hiding this comment

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

Thanks @aaronfern for the test cases! Seems to be already a very good first cut. A few suggestions and questions below.

@@ -51,7 +52,9 @@ func TestRestorer(t *testing.T) {
RunSpecs(t, "Restorer Suite")
}

var _ = SynchronizedBeforeSuite(func() []byte {
var _ = SynchronizedBeforeSuite(prepare, func(data []byte) {})

Choose a reason for hiding this comment

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

What is the purpose of the second empty func?

Copy link
Author

Choose a reason for hiding this comment

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

It's actually part of the syntax of the SynchronizedBeforeSuite call, it needs two functions as arguments.
However as I was adding a couple of test cases, I realised that this change wasn't necessarily required. Hence this change has been reverted.

Comment on lines 942 to 949
files, err := ioutil.ReadDir(path.Join(snapstoreDir, "v2"))
Expect(err).ShouldNot(HaveOccurred())
oldPath := path.Join(snapstoreDir, "v2")
newPath := path.Join(path.Join(snapstoreDir, "v1"), fmt.Sprintf("Backup-%d", curTime))
for _, f := range files {
err = os.Rename(path.Join(oldPath, f.Name()), path.Join(newPath, f.Name()))
Expect(err).ShouldNot(HaveOccurred())
}
Copy link

@amshuman-kr amshuman-kr Jun 5, 2021

Choose a reason for hiding this comment

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

I like this approach of taking snapshots into v2 and then moving to v1. This is a good way to test backward compatibility for restoration when we have stopped support for uploading to v1 👍

The code above moves everything under v2 to v1/Backup-XXX, including the snapshots taken before this function is called which would include the base full snapshot. This has the good effect that restoration from base snapshot from the pure v1 structure is tested.

To test the mixed case, could you please support the case where the first few snapshots (full snapshot and some incremental snapshots) are in the v1/Backup-XXX and some more incremental snapshots (at least one) are in v2. This could possibly be controlled via a parameter to the function.

Copy link
Author

Choose a reason for hiding this comment

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

Added a test case to support this scenario

//Test to check backward compatibility of restorer
//Tests restorer behaviour when local database has to be restored from snapstore with old (v1) as well as updated (v2) directory structures
//TODO: Consider removing when backward compatibility no longer needed
Context("With snapshots in v1 as well as v2 dir", func() {

Choose a reason for hiding this comment

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

There is another mixed case where the first few snapshots (full and some incremental) are in v1 structure and the remaining (at least one) are in v2 format. Restoration from this also should succeed. Can you please add this case too?

For completeness, there is the opposite case too where the first few snapshots (including the full snapshot) are in v2 structure and the remaining ones are in v1 structure. Strictly speaking, this should never happen but could be possible if we are forced to revert the folder structure change release of etcd-backup-restore for some reason. Covering this case, might protect against that case too.

Copy link
Author

Choose a reason for hiding this comment

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

Added a test case to support this scenario

Comment on lines 599 to 604
snap := &brtypes.Snapshot{
Kind: brtypes.SnapshotKindFull,
CreatedOn: snapTime,
StartRevision: 0,
LastRevision: 1001,
}

Choose a reason for hiding this comment

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

After the garbage collection, is the whole store expected to be in the v2 format? This is fine, I am just asking because I did not find SnapDir field being initialised for any of the expected snapshots.

Also, is there a commonality in the initialisation of the expected snapshot lists between the cases? If so, can you please convert the logic into a function and reuse?

Copy link
Author

Choose a reason for hiding this comment

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

No, not really. Snaps that are not garbage collected would remain in their original directory.
Added changes to support SnapDir in the expected snapshots and using that to decide test case result

Copy link

@amshuman-kr amshuman-kr left a comment

Choose a reason for hiding this comment

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

Thanks for the changes @aaronfern! Looks good now. Just a few more comments.


//takeValidV1Snaps saves valid snaps in the v1 prefix dir of snapstore so that restorer could restore from them
//TODO: Consider removing when backward compatibility no longer needed
func takeValidV1Snaps(logger *logrus.Entry, container string, deltaSnapshotPeriod time.Duration, endpoints []string, stopCh <-chan struct{}, startWithFullSnapshot bool, compressionConfig *compressor.CompressionConfig, mode string) error {

Choose a reason for hiding this comment

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

Is startWithFullSnapshot required here? It doesn't seem to be used.

Copy link
Author

Choose a reason for hiding this comment

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

Removed


//takeInvalidV1Snaps saves an invalid snap in the v1 prefix dir of the snapstore so that restorer can't restore from it
//TODO: Consider removing when backward compatibility no longer needed
func takeInvalidV1Snaps(logger *logrus.Entry, container string, deltaSnapshotPeriod time.Duration, endpoints []string, stopCh <-chan struct{}, startWithFullSnapshot bool, compressionConfig *compressor.CompressionConfig) error {

Choose a reason for hiding this comment

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

Is startWithFullSnapshot required here? It doesn't seem to be used.

Copy link
Author

Choose a reason for hiding this comment

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

Removed

Comment on lines 41 to 43
allSnapsInv1 = "allSnapsInv1"
fullSnapInv1 = "fullSnapInv1"
fullSnapInv2 = "fullSnapInv2"

Choose a reason for hiding this comment

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

Better to name these constants xxxInV1 or xxxInV2 with capital V otherwise Inv might be confused to mean invalid.

Copy link
Author

Choose a reason for hiding this comment

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

Done

Comment on lines 42 to 43
snapsInv1 = "v1"
snapsInv2 = "v2"

Choose a reason for hiding this comment

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

Better to use caps V in the constant names as mentioned above.

Copy link
Author

Choose a reason for hiding this comment

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

Done

for _, snap := range list {
if incr == false {
if snap.Kind == brtypes.SnapshotKindDelta {
incr = true

Choose a reason for hiding this comment

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

If I understood right, the snapshots are prepared in such a away that everything that does not have incremental snapshots should be in v1 structure and everything that has incremental snapshots should be in v2 structure?

Choose a reason for hiding this comment

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

Possibly there is a commonality between this case and the next too from the expectation perspective? The only difference seems to be the SnapDir check. Or am I oversimplifying it?

Copy link
Author

Choose a reason for hiding this comment

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

Moved this to a function

The logic there is to make sure that no full snaps are present in the list after a incr snap post garbage collection. The SnapDir check is done based on the test itself, and that's passed to the func in the form of mode now.

Comment on lines 1021 to 1025
// if mode == "v1" {
// dir = fmt.Sprintf("Backup-%d", snapTime.Unix())
// } else {
// dir = ""
// }

Choose a reason for hiding this comment

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

Please remove these lines if not required.

Copy link
Author

Choose a reason for hiding this comment

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

Removed

Copy link

@amshuman-kr amshuman-kr left a comment

Choose a reason for hiding this comment

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

Thanks for the changes @aaronfern! Looks good.

One last change to make debugging failed tests. Sorry, I missed it in the laster review.

Comment on lines 546 to 548
if snap.CreatedOn != expectedSnapList[index].CreatedOn || snap.Kind != expectedSnapList[index].Kind || snap.SnapDir != expectedSnapList[index].SnapDir {
Fail("Expected snap list doesn't match with output snap list")
}

Choose a reason for hiding this comment

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

Might be better to change this section to 3 Expects for the corresponding fields. This will help debug when the tests fail.

The same holds in other cases below.

Copy link
Author

Choose a reason for hiding this comment

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

Done

Copy link

@amshuman-kr amshuman-kr left a comment

Choose a reason for hiding this comment

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

Thanks for the changes @aaronfern!

/lgtm

@abdasgupta abdasgupta merged commit bb6dc59 into abdasgupta:working Jun 9, 2021
@aaronfern aaronfern deleted the working branch June 28, 2021 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants