From ea76138f3b04bc7cf1edda7c38b5418b6376c445 Mon Sep 17 00:00:00 2001 From: Benson Wong Date: Thu, 1 Jun 2017 14:02:32 -0700 Subject: [PATCH 1/4] Add functional test for delete collection then post scenario A bug was discovered in gosync (issue #169) where a DELETE of a collection followed by a POST had the wrong behaviour. Add test_delete_collection_then_post to ensure all servers conform to the expected behaviour by clients. --- syncstorage/tests/functional/test_storage.py | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/syncstorage/tests/functional/test_storage.py b/syncstorage/tests/functional/test_storage.py index 508246c5..8f52211f 100644 --- a/syncstorage/tests/functional/test_storage.py +++ b/syncstorage/tests/functional/test_storage.py @@ -574,6 +574,64 @@ def test_delete_collection_items(self): res = self.app.get(self.root + '/storage/col2') self.assertEquals(len(res.json), 0) + def test_delete_collection_then_post(self): + # creating a collection of three + bso1 = {'id': '12', 'payload': _PLD} + bso2 = {'id': '13', 'payload': _PLD} + bso3 = {'id': '14', 'payload': _PLD} + bsos = [bso1, bso2, bso3] + + self.app.post_json(self.root + '/storage/col2', bsos) + res = self.app.get(self.root + '/storage/col2') + self.assertEquals(len(res.json), 3) + + resp = self.app.get(self.root + '/info/collections') + res = resp.json + self.assertTrue("col2" in res) + + infoBefore = self.app.get(self.root + '/info/collections') + + # Deleting the collection should result in: + # - collection does not appear in /info/collections + # - X-Last-Modified timestamp at the storage level changing + self.app.delete(self.root + '/storage/col2') + items = self.app.get(self.root + '/storage/col2').json + self.assertEquals(len(items), 0) + + infoAfter1 = self.app.get(self.root + '/info/collections') + res = infoAfter1.json + self.assertTrue("col2" not in res) + self.assertTrue("X-Last-Modified" in resp.headers) + self.assertNotEqual(infoBefore.headers["X-Last-Modified"], + infoAfter1.headers["X-Last-Modified"]) + + # make sure the storage level timestamp stays the same + time.sleep(0.2) + infoAfter2 = self.app.get(self.root + '/info/collections') + self.assertEqual(infoAfter1.headers["X-Last-Modified"], + infoAfter2.headers["X-Last-Modified"]) + + # post BSOs again with X-I-U-S == 0 + self.app.post_json( + self.root + '/storage/col2', bsos, + headers=[('X-If-Unmodified-Since', "0.00")]) + infoAfter3 = self.app.get(self.root + '/info/collections') + self.assertNotEqual(infoAfter3.headers["X-Last-Modified"], + infoAfter2.headers["X-Last-Modified"]) + + # delete and POST again with X-I-U-S > 0 + afterDel2 = self.app.delete(self.root + '/storage/col2') + items = self.app.get(self.root + '/storage/col2').json + self.assertEquals(len(items), 0) + self.app.post_json( + self.root + '/storage/col2', bsos, + headers=[('X-If-Unmodified-Since', "1.00")]) + + infoAfter4 = self.app.get(self.root + '/info/collections') + self.assertNotEqual(infoAfter4.headers["X-Last-Modified"], + infoAfter3.headers["X-Last-Modified"]) + + def test_delete_item(self): # creating a collection of three bso1 = {'id': '12', 'payload': _PLD} From 8848a6ab51b8422a6a3e0c012e342e9578fc8ba5 Mon Sep 17 00:00:00 2001 From: Benson Wong Date: Thu, 1 Jun 2017 14:23:28 -0700 Subject: [PATCH 2/4] fix flake8 errors --- syncstorage/tests/functional/test_storage.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/syncstorage/tests/functional/test_storage.py b/syncstorage/tests/functional/test_storage.py index 8f52211f..f5d4a3ce 100644 --- a/syncstorage/tests/functional/test_storage.py +++ b/syncstorage/tests/functional/test_storage.py @@ -603,13 +603,13 @@ def test_delete_collection_then_post(self): self.assertTrue("col2" not in res) self.assertTrue("X-Last-Modified" in resp.headers) self.assertNotEqual(infoBefore.headers["X-Last-Modified"], - infoAfter1.headers["X-Last-Modified"]) + infoAfter1.headers["X-Last-Modified"]) # make sure the storage level timestamp stays the same time.sleep(0.2) infoAfter2 = self.app.get(self.root + '/info/collections') self.assertEqual(infoAfter1.headers["X-Last-Modified"], - infoAfter2.headers["X-Last-Modified"]) + infoAfter2.headers["X-Last-Modified"]) # post BSOs again with X-I-U-S == 0 self.app.post_json( @@ -617,10 +617,10 @@ def test_delete_collection_then_post(self): headers=[('X-If-Unmodified-Since', "0.00")]) infoAfter3 = self.app.get(self.root + '/info/collections') self.assertNotEqual(infoAfter3.headers["X-Last-Modified"], - infoAfter2.headers["X-Last-Modified"]) + infoAfter2.headers["X-Last-Modified"]) # delete and POST again with X-I-U-S > 0 - afterDel2 = self.app.delete(self.root + '/storage/col2') + self.app.delete(self.root + '/storage/col2') items = self.app.get(self.root + '/storage/col2').json self.assertEquals(len(items), 0) self.app.post_json( @@ -629,8 +629,7 @@ def test_delete_collection_then_post(self): infoAfter4 = self.app.get(self.root + '/info/collections') self.assertNotEqual(infoAfter4.headers["X-Last-Modified"], - infoAfter3.headers["X-Last-Modified"]) - + infoAfter3.headers["X-Last-Modified"]) def test_delete_item(self): # creating a collection of three From e3f9bc5db36fdbb9ae5f2559f6982636785c4e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Fri, 2 Jun 2017 07:31:24 +0200 Subject: [PATCH 3/4] @natim review. --- syncstorage/tests/functional/test_storage.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/syncstorage/tests/functional/test_storage.py b/syncstorage/tests/functional/test_storage.py index f5d4a3ce..4064ac5e 100644 --- a/syncstorage/tests/functional/test_storage.py +++ b/syncstorage/tests/functional/test_storage.py @@ -585,11 +585,12 @@ def test_delete_collection_then_post(self): res = self.app.get(self.root + '/storage/col2') self.assertEquals(len(res.json), 3) - resp = self.app.get(self.root + '/info/collections') - res = resp.json + infoBefore = self.app.get(self.root + '/info/collections') + res = infoBefore.json self.assertTrue("col2" in res) - infoBefore = self.app.get(self.root + '/info/collections') + # make sure the storage level timestamp changes + time.sleep(0.2) # Deleting the collection should result in: # - collection does not appear in /info/collections @@ -601,7 +602,8 @@ def test_delete_collection_then_post(self): infoAfter1 = self.app.get(self.root + '/info/collections') res = infoAfter1.json self.assertTrue("col2" not in res) - self.assertTrue("X-Last-Modified" in resp.headers) + self.assertTrue("X-Last-Modified" in infoBefore.headers) + self.assertTrue("X-Last-Modified" in infoAfter1.headers) self.assertNotEqual(infoBefore.headers["X-Last-Modified"], infoAfter1.headers["X-Last-Modified"]) @@ -612,9 +614,8 @@ def test_delete_collection_then_post(self): infoAfter2.headers["X-Last-Modified"]) # post BSOs again with X-I-U-S == 0 - self.app.post_json( - self.root + '/storage/col2', bsos, - headers=[('X-If-Unmodified-Since', "0.00")]) + self.app.post_json(self.root + '/storage/col2', bsos, + headers=[('X-If-Unmodified-Since', "0.00")]) infoAfter3 = self.app.get(self.root + '/info/collections') self.assertNotEqual(infoAfter3.headers["X-Last-Modified"], infoAfter2.headers["X-Last-Modified"]) @@ -623,9 +624,8 @@ def test_delete_collection_then_post(self): self.app.delete(self.root + '/storage/col2') items = self.app.get(self.root + '/storage/col2').json self.assertEquals(len(items), 0) - self.app.post_json( - self.root + '/storage/col2', bsos, - headers=[('X-If-Unmodified-Since', "1.00")]) + self.app.post_json(self.root + '/storage/col2', bsos, + headers=[('X-If-Unmodified-Since', "1.00")]) infoAfter4 = self.app.get(self.root + '/info/collections') self.assertNotEqual(infoAfter4.headers["X-Last-Modified"], From b8d6cd4372a3a27240753584e5b145c0c2e6b73c Mon Sep 17 00:00:00 2001 From: Benson Wong Date: Fri, 2 Jun 2017 08:06:49 -0700 Subject: [PATCH 4/4] improve testing logic for collection deletion --- syncstorage/tests/functional/test_storage.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/syncstorage/tests/functional/test_storage.py b/syncstorage/tests/functional/test_storage.py index f5d4a3ce..2dfc5ef1 100644 --- a/syncstorage/tests/functional/test_storage.py +++ b/syncstorage/tests/functional/test_storage.py @@ -602,8 +602,8 @@ def test_delete_collection_then_post(self): res = infoAfter1.json self.assertTrue("col2" not in res) self.assertTrue("X-Last-Modified" in resp.headers) - self.assertNotEqual(infoBefore.headers["X-Last-Modified"], - infoAfter1.headers["X-Last-Modified"]) + self.assertTrue(float(infoBefore.headers["X-Last-Modified"]) < + float(infoAfter1.headers["X-Last-Modified"])) # make sure the storage level timestamp stays the same time.sleep(0.2) @@ -616,8 +616,8 @@ def test_delete_collection_then_post(self): self.root + '/storage/col2', bsos, headers=[('X-If-Unmodified-Since', "0.00")]) infoAfter3 = self.app.get(self.root + '/info/collections') - self.assertNotEqual(infoAfter3.headers["X-Last-Modified"], - infoAfter2.headers["X-Last-Modified"]) + self.assertTrue(float(infoAfter3.headers["X-Last-Modified"]) > + float(infoAfter2.headers["X-Last-Modified"])) # delete and POST again with X-I-U-S > 0 self.app.delete(self.root + '/storage/col2') @@ -628,8 +628,8 @@ def test_delete_collection_then_post(self): headers=[('X-If-Unmodified-Since', "1.00")]) infoAfter4 = self.app.get(self.root + '/info/collections') - self.assertNotEqual(infoAfter4.headers["X-Last-Modified"], - infoAfter3.headers["X-Last-Modified"]) + self.assertTrue(float(infoAfter4.headers["X-Last-Modified"]) > + float(infoAfter3.headers["X-Last-Modified"])) def test_delete_item(self): # creating a collection of three