def test_get_changes_since(self): make_data_dir() file_put_contents(cpjoin(DATA_DIR, 'test 1'), 'test') file_put_contents(cpjoin(DATA_DIR, 'test 2'), 'test 1') file_put_contents(cpjoin(DATA_DIR, 'test 3'), 'test 2') #================== data_store = versioned_storage(DATA_DIR) data_store.begin() data_store.fs_put_from_file(cpjoin(DATA_DIR, 'test 1'), {'path' : '/test/path'}) id1 = data_store.commit('test msg', 'test user') changes = data_store.get_changes_since('root', data_store.get_head()) self.assertEqual(changes, {u'/test/path': {u'hash': u'9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', u'path': u'/test/path', u'status': u'new'}}) #================== data_store.begin() data_store.fs_put_from_file(cpjoin(DATA_DIR, 'test 2'), {'path' : '/another/path'}) data_store.fs_put_from_file(cpjoin(DATA_DIR, 'test 3'), {'path' : '/yet/another/path'}) data_store.commit('test msg', 'test user') changes = data_store.get_changes_since(id1, data_store.get_head()) self.assertEqual(changes, {u'/another/path': {u'hash': u'f67213b122a5d442d2b93bda8cc45c564a70ec5d2a4e0e95bb585cf199869c98', u'path': u'/another/path', u'status': u'new'}, u'/yet/another/path': {u'hash': u'dec2e4bc4992314a9c9a51bbd859e1b081b74178818c53c19d18d6f761f5d804', u'path': u'/yet/another/path', u'status': u'new'}}) delete_data_dir()
def test_hash_file(self): """ Test that file hash returns the correct result. """ make_data_dir() file_path = cpjoin(DATA_DIR, 'test') file_put_contents(file_path, 'some file contents') p1 = subprocess.Popen (['sha256sum', file_path], stdout=subprocess.PIPE) result1= p1.communicate()[0].split(' ')[0] result2 = hash_file(file_path) self.assertEqual(result1, result2, msg = 'Hashes are not the same') delete_data_dir()
def test_storage_delete_rollback(self): """ Test file delete rolls back correctly """ make_data_dir() s = storage(DATA_DIR, CONF_DIR) s.begin() s.file_put_contents('hello', 'test content') s.commit(True) s.delete_file('hello') s.rollback() self.assertTrue( os.path.isfile(cpjoin(DATA_DIR, 'hello')), msg = 'error, file "hello" does not exist, delete rollback failed') delete_data_dir()
def test_storage_move_rollback(self): """ Test file move rolls back correctly """ make_data_dir() s = storage(DATA_DIR, CONF_DIR) s.begin() s.file_put_contents('hello', 'test content') s.commit(True) s.move_file('hello', 'hello2') s.rollback() self.assertFalse( os.path.isfile(cpjoin(DATA_DIR, 'hello2')), msg = 'File "hello2" still exists, move rollback failed') delete_data_dir()
def test_hash_file(self): """ Test that file hash returns the correct result. """ make_data_dir() file_path = cpjoin(DATA_DIR, 'test') file_put_contents(file_path, b'some file contents') expected_result = 'cf57fcf9d6d7fb8fd7d8c30527c8f51026aa1d99ad77cc769dd0c757d4fe8667' result = hash_file(file_path) self.assertEqual(expected_result, result, msg='Hashes are not the same') delete_data_dir()
def test_storage_put_rollback(self): """ Test that file put rolls back correctly """ make_data_dir() s = storage(DATA_DIR, CONF_DIR) s.begin() s.file_put_contents('hello', 'test content') s.rollback() self.assertFalse( os.path.isfile(cpjoin(DATA_DIR, 'hello')), msg = 'File "hello" still exists, put rollback failed') self.assertTrue( os.path.isfile(cpjoin(DATA_DIR, CONF_DIR, BACKUP_DIR, '1_hello')), msg = 'Backup file "1_hello" does not exist, put rollback failed') delete_data_dir()
def test_storage_move_overwrite_rollback(self): """ Test file move rolls back correctly when move overwrites another file """ make_data_dir() s = storage(DATA_DIR, CONF_DIR) s.begin() s.file_put_contents('hello', 'test content') s.file_put_contents('hello2', 'test content 2') s.commit(True) s.move_file('hello', 'hello2') s.rollback() self.assertTrue( os.path.isfile(cpjoin(DATA_DIR, 'hello')), msg = 'File "hello" does not exist, move overwrite rollback failed') self.assertTrue( os.path.isfile(cpjoin(DATA_DIR, 'hello2')), msg = 'File "hello2" does not exist, move overwrite rollback failed') delete_data_dir()
def test_rollback(self): make_data_dir() file_put_contents(cpjoin(DATA_DIR, 'test 1'), 'test') file_put_contents(cpjoin(DATA_DIR, 'test 2'), 'test') file_put_contents(cpjoin(DATA_DIR, 'test 3'), 'test 2') #================== data_store = versioned_storage(DATA_DIR) data_store.begin() data_store.fs_put_from_file(cpjoin(DATA_DIR, 'test 1'), {'path' : '/test/path'}) data_store.commit('test msg', 'test user') data_store.begin() data_store.fs_put_from_file(cpjoin(DATA_DIR, 'test 2'), {'path' : '/another/path'}) data_store.fs_put_from_file(cpjoin(DATA_DIR, 'test 3'), {'path' : '/yet/another/path'}) data_store.rollback() self.assertEqual(os.listdir(cpjoin(DATA_DIR, 'files')), ['9f']) self.assertEqual(os.listdir(cpjoin(DATA_DIR, 'files', '9f')), ['86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08']) delete_data_dir()
def test_storage_multiple_rollback(self): """ Test rollback of multiple things at once """ make_data_dir() s = storage(DATA_DIR, CONF_DIR) s.begin() s.file_put_contents('hello', 'test content') s.commit(True) s.file_put_contents('hello2', 'test content 2') s.file_put_contents('hello3', 'test content 3') s.move_file('hello', 'goodbye') s.move_file('hello2', 'hello3') s.delete_file('hello3') s.file_put_contents('hello3', 'something else') s.rollback() self.assertTrue( os.path.isfile(cpjoin(DATA_DIR, 'hello')), msg = 'File "hello" does not exist, multiple rollback failed') self.assertFalse( os.path.isfile(cpjoin(DATA_DIR, 'hello3')), msg = 'File "hello3" still exists, multiple rollback failed') self.assertFalse( os.path.isfile(cpjoin(DATA_DIR, 'goodbye')), msg = 'File "goodbye" still exists, multiple rollback failed') self.assertTrue( os.path.isfile(cpjoin(DATA_DIR, CONF_DIR, BACKUP_DIR, '1_hello3')), msg = 'Backup file "1_hello3" does not exist, multiple rollback failed') self.assertTrue( os.path.isfile(cpjoin(DATA_DIR, CONF_DIR, BACKUP_DIR, '2_hello3')), msg = 'Backup file "2_hello3" does not exist, multiple rollback failed') self.assertTrue( os.path.isfile(cpjoin(DATA_DIR, CONF_DIR, BACKUP_DIR, '3_hello2')), msg = 'Backup file "3_hello2" does not exist, multiple rollback failed') delete_data_dir()
def tearDown(self): delete_data_dir()
def setUp(self): delete_data_dir() # Ensure clean start make_data_dir()
def test_system(self): test_content_1 = b'test file jhgrtelkj' test_content_2 = b''.join([struct.pack('B', i) for i in range(256) ]) # binary string with all byte values test_content_2_2 = test_content_2[::-1] test_content_3 = b'test content 3 sdavcxreiltlj' test_content_4 = b'test content 4 fsdwqtruytuyt' test_content_5 = b'test content 5 .,myuitouys' #========= setup() setup_client('client1') #================================================== # test_initial commit #================================================== file_put_contents(DATA_DIR + 'client1/test1', test_content_1) file_put_contents(DATA_DIR + 'client1/test2', test_content_2) # test with a binary blob #file_put_contents(DATA_DIR + u'client1/GȞƇØzÇ â˜¸k😒â™', test_content_2) # test unicode file name # commit the files session_token = client.authenticate() print(session_token) version_id = client.commit(session_token, 'test commit') self.assertNotEqual(version_id, None) # commit message should be in log req_result = client.get_versions(session_token)[0] self.assertEqual( 'test commit', json.loads(req_result)['versions'][0]['commit_message']) # file should show up in list_changes req_result = client.get_files_in_version(session_token, version_id)[0] self.assertTrue('/test1' in json.loads(req_result)['files']) self.assertTrue('/test2' in json.loads(req_result)['files']) # file should exist in server fs self.assertEqual( test_content_1, file_get_contents(DATA_DIR + 'server/files/' + get_server_file_name(test_content_1))) self.assertEqual( test_content_2, file_get_contents(DATA_DIR + 'server/files/' + get_server_file_name(test_content_2))) # NOTE As change detection is done using access timestamps, need a # delay between tests to make sure changes are detected correctly time.sleep(0.5) #================================================== # test update #================================================== setup_client('client2') session_token = client.authenticate() client.update(session_token) self.assertEqual(test_content_1, file_get_contents(DATA_DIR + 'client2/test1')) self.assertEqual(test_content_2, file_get_contents(DATA_DIR + 'client2/test2')) time.sleep(0.5) # See above #================================================== # test delete and add #================================================== os.unlink(DATA_DIR + 'client2/test1') file_put_contents(DATA_DIR + 'client2/test2', test_content_2_2) # test changing an existing file file_put_contents(DATA_DIR + 'client2/test3', test_content_3) file_put_contents(DATA_DIR + 'client2/test4', test_content_4) setup_client('client2') session_token = client.authenticate() version_id = client.commit(session_token, 'create and delete some files') # check change is reflected correctly in the commit log req_result = client.get_changes_in_version(session_token, version_id)[0] res_index = {v['path']: v for v in json.loads(req_result)['changes']} self.assertEqual('deleted', res_index['/test1']['status']) self.assertEqual('new', res_index['/test2']['status']) self.assertEqual('new', res_index['/test3']['status']) self.assertEqual('new', res_index['/test4']['status']) # update first repo, file should be deleted and new file added setup_client('client1') session_token = client.authenticate() client.update(session_token) # Verify changes are reflected in FS self.assertFalse(os.path.isfile(DATA_DIR + 'client1/test1')) self.assertEqual(test_content_2_2, file_get_contents(DATA_DIR + 'client1/test2')) self.assertEqual(test_content_3, file_get_contents(DATA_DIR + 'client1/test3')) self.assertEqual(test_content_4, file_get_contents(DATA_DIR + 'client1/test4')) time.sleep(0.5) # See above #================================================== # setup for next test #================================================== file_put_contents(DATA_DIR + 'client1/test1', test_content_1) file_put_contents(DATA_DIR + 'client1/test5', test_content_1) file_put_contents(DATA_DIR + 'client1/test6', test_content_1) setup_client('client1') client.commit(client.authenticate(), 'test setup') setup_client('client2') client.update(client.authenticate()) time.sleep(0.5) # See above #================================================== # test conflict resolution, both to the server # and client version #================================================== # Delete on client, change on server resolution file_put_contents(DATA_DIR + 'client1/test1', test_content_5 + b'11') os.unlink(DATA_DIR + 'client2/test1') file_put_contents(DATA_DIR + 'client1/test2', test_content_5 + b'00') os.unlink(DATA_DIR + 'client2/test2') # Delete on server, change on client resolution os.unlink(DATA_DIR + 'client1/test5') file_put_contents(DATA_DIR + 'client2/test5', test_content_5 + b'ff') os.unlink(DATA_DIR + 'client1/test6') file_put_contents(DATA_DIR + 'client2/test6', test_content_5 + b'gg') # Double change resolution file_put_contents(DATA_DIR + 'client1/test3', test_content_5 + b'aa') file_put_contents(DATA_DIR + 'client2/test3', test_content_5 + b'bb') file_put_contents(DATA_DIR + 'client1/test4', test_content_5 + b'cc') file_put_contents(DATA_DIR + 'client2/test4', test_content_5 + b'dd') # commit both clients second to commit should error setup_client('client1') session_token = client.authenticate() version_id = client.commit(session_token, 'initial commit for conflict test') setup_client('client2') session_token = client.authenticate() try: version_id = client.commit(session_token, 'this should conflict') self.fail() except SystemExit: pass # Update should begin conflict resolution process try: client.update(session_token, testing=True) self.fail() except SystemExit: pass # test server versions of conflict files downloaded correctly self.assertEqual(file_get_contents(DATA_DIR + 'client1/test1'), test_content_5 + b'11') self.assertEqual(file_get_contents(DATA_DIR + 'client1/test2'), test_content_5 + b'00') self.assertEqual(file_get_contents(DATA_DIR + 'client1/test3'), test_content_5 + b'aa') self.assertEqual(file_get_contents(DATA_DIR + 'client1/test4'), test_content_5 + b'cc') # NOTE nothing to download in delete on server case #test resolving it path = DATA_DIR + 'client2/.shttpfs/conflict_resolution.json' resolve = json.loads(file_get_contents(path)) resolve_index = {v['1_path']: v for v in resolve} resolve_index['/test1']['4_resolution'] = ['client'] resolve_index['/test2']['4_resolution'] = ['server'] resolve_index['/test3']['4_resolution'] = ['client'] resolve_index['/test4']['4_resolution'] = ['server'] resolve_index['/test5']['4_resolution'] = ['client'] resolve_index['/test6']['4_resolution'] = ['server'] file_put_contents( path, json.dumps([v for v in list(resolve_index.values())]).encode('utf8')) # perform update and test resolve as expected client.update(session_token) self.assertFalse(os.path.isfile(DATA_DIR + 'client2/test1')) self.assertEqual(test_content_5 + b'00', file_get_contents(DATA_DIR + 'client2/test2')) self.assertEqual(test_content_5 + b'bb', file_get_contents(DATA_DIR + 'client2/test3')) self.assertEqual(test_content_5 + b'cc', file_get_contents(DATA_DIR + 'client2/test4')) self.assertEqual(test_content_5 + b'ff', file_get_contents(DATA_DIR + 'client2/test5')) self.assertFalse(os.path.isfile(DATA_DIR + 'client2/test6')) # This should now commit version_id = client.commit(session_token, 'this should be ok') self.assertNotEqual(None, version_id) req_result = client.get_changes_in_version(session_token, version_id)[0] res_index = {v['path']: v for v in json.loads(req_result)['changes']} self.assertEqual('deleted', res_index['/test1']['status']) self.assertTrue('/test2' not in res_index) self.assertEqual('new', res_index['/test3']['status']) self.assertTrue('/test4' not in res_index) self.assertEqual('new', res_index['/test5']['status']) self.assertTrue('/test6' not in res_index) #================================================== delete_data_dir()
def test_system(self): test_content_1 = 'test file jhgrtelkj' test_content_2 = b''.join([struct.pack('B', i) for i in range(256)]) # binary string with all byte values test_content_2_2 = test_content_2[::-1] test_content_3 = 'test content 3 sdavcxreiltlj' test_content_4 = 'test content 4 fsdwqtruytuyt' test_content_5 = 'test content 5 .,myuitouys' #========= setup() setup_client('client1') #================================================== # test_initial commit #================================================== file_put_contents(DATA_DIR + 'client1/test1', test_content_1) file_put_contents(DATA_DIR + 'client1/test2', test_content_2) # test with a binary blob #file_put_contents(DATA_DIR + u'client1/GȞƇØzÇ â˜¸k😒â™', test_content_2) # test unicode file name # commit the files session_token = client.authenticate() version_id = client.commit(session_token, 'test commit') self.assertNotEqual(version_id, None) # commit message should be in log req_result = client.get_versions(session_token)[0] self.assertEqual('test commit', json.loads(req_result)['versions'][0]['commit_message']) # file should show up in list_changes req_result = client.get_files_in_version(session_token, version_id)[0] self.assertTrue('/test1' in json.loads(req_result)['files']) self.assertTrue('/test2' in json.loads(req_result)['files']) # file should exist in server fs self.assertEqual(test_content_1, file_get_contents(DATA_DIR + 'server/files/' + get_server_file_name(test_content_1))) self.assertEqual(test_content_2, file_get_contents(DATA_DIR + 'server/files/' + get_server_file_name(test_content_2))) # NOTE As change detection is done using access timestamps, need a # delay between tests to make sure changes are detected correctly time.sleep(0.5) #================================================== # test update #================================================== setup_client('client2') session_token = client.authenticate() client.update(session_token) self.assertEqual(test_content_1, file_get_contents(DATA_DIR + 'client2/test1')) self.assertEqual(test_content_2, file_get_contents(DATA_DIR + 'client2/test2')) time.sleep(0.5) # See above #================================================== # test delete and add #================================================== os.unlink(DATA_DIR + 'client2/test1') file_put_contents(DATA_DIR + 'client2/test2', test_content_2_2) # test changing an existing file file_put_contents(DATA_DIR + 'client2/test3', test_content_3) file_put_contents(DATA_DIR + 'client2/test4', test_content_4) setup_client('client2') session_token = client.authenticate() version_id = client.commit(session_token, 'create and delete some files') # check change is reflected correctly in the commit log req_result = client.get_changes_in_version(session_token, version_id)[0] res_index = { v['path'] : v for v in json.loads(req_result)['changes']} self.assertEqual('deleted', res_index['/test1']['status']) self.assertEqual('new' , res_index['/test2']['status']) self.assertEqual('new' , res_index['/test3']['status']) self.assertEqual('new' , res_index['/test4']['status']) # update first repo, file should be deleted and new file added setup_client('client1') session_token = client.authenticate() client.update(session_token) # Verify changes are reflected in FS self.assertFalse(os.path.isfile(DATA_DIR + 'client1/test1')) self.assertEqual(test_content_2_2, file_get_contents(DATA_DIR + 'client1/test2')) self.assertEqual(test_content_3, file_get_contents(DATA_DIR + 'client1/test3')) self.assertEqual(test_content_4, file_get_contents(DATA_DIR + 'client1/test4')) time.sleep(0.5) # See above #================================================== # setup for next test #================================================== file_put_contents(DATA_DIR + 'client1/test1', test_content_1) file_put_contents(DATA_DIR + 'client1/test5', test_content_1) file_put_contents(DATA_DIR + 'client1/test6', test_content_1) setup_client('client1') client.commit(client.authenticate(), 'test setup') setup_client('client2') client.update(client.authenticate()) time.sleep(0.5) # See above #================================================== # test conflict resolution, both to the server # and client version #================================================== # Delete on client, change on server resolution file_put_contents(DATA_DIR + 'client1/test1', test_content_5 + '11') os.unlink( DATA_DIR + 'client2/test1') file_put_contents(DATA_DIR + 'client1/test2', test_content_5 + '00') os.unlink( DATA_DIR + 'client2/test2') # Delete on server, change on client resolution os.unlink( DATA_DIR + 'client1/test5') file_put_contents(DATA_DIR + 'client2/test5', test_content_5 + 'ff') os.unlink( DATA_DIR + 'client1/test6') file_put_contents(DATA_DIR + 'client2/test6', test_content_5 + 'gg') # Double change resolution file_put_contents(DATA_DIR + 'client1/test3', test_content_5 + 'aa') file_put_contents(DATA_DIR + 'client2/test3', test_content_5 + 'bb') file_put_contents(DATA_DIR + 'client1/test4', test_content_5 + 'cc') file_put_contents(DATA_DIR + 'client2/test4', test_content_5 + 'dd') # commit both clients second to commit should error setup_client('client1') session_token = client.authenticate() version_id = client.commit(session_token, 'initial commit for conflict test') setup_client('client2') session_token = client.authenticate() try: version_id = client.commit(session_token, 'this should conflict') self.fail() except SystemExit: pass # Update should begin conflict resolution process try: client.update(session_token, testing=True) self.fail() except SystemExit: pass # test server versions of conflict files downloaded correctly self.assertEqual(file_get_contents(DATA_DIR + 'client1/test1'), test_content_5 + '11') self.assertEqual(file_get_contents(DATA_DIR + 'client1/test2'), test_content_5 + '00') self.assertEqual(file_get_contents(DATA_DIR + 'client1/test3'), test_content_5 + 'aa') self.assertEqual(file_get_contents(DATA_DIR + 'client1/test4'), test_content_5 + 'cc') # NOTE nothing to download in delete on server case #test resolving it path = DATA_DIR + 'client2/.shttpfs/conflict_resolution.json' resolve = json.loads(file_get_contents(path)) resolve_index = {v['1_path'] : v for v in resolve} resolve_index['/test1']['4_resolution'] = ['client'] resolve_index['/test2']['4_resolution'] = ['server'] resolve_index['/test3']['4_resolution'] = ['client'] resolve_index['/test4']['4_resolution'] = ['server'] resolve_index['/test5']['4_resolution'] = ['client'] resolve_index['/test6']['4_resolution'] = ['server'] file_put_contents(path, json.dumps([v for v in resolve_index.values()])) # perform update and test resolve as expected client.update(session_token) self.assertFalse( os.path.isfile(DATA_DIR + 'client2/test1')) self.assertEqual(test_content_5 + '00', file_get_contents(DATA_DIR + 'client2/test2')) self.assertEqual(test_content_5 + 'bb', file_get_contents(DATA_DIR + 'client2/test3')) self.assertEqual(test_content_5 + 'cc', file_get_contents(DATA_DIR + 'client2/test4')) self.assertEqual(test_content_5 + 'ff', file_get_contents(DATA_DIR + 'client2/test5')) self.assertFalse( os.path.isfile(DATA_DIR + 'client2/test6')) # This should now commit version_id = client.commit(session_token, 'this should be ok') self.assertNotEqual(None, version_id) req_result = client.get_changes_in_version(session_token, version_id)[0] res_index = { v['path'] : v for v in json.loads(req_result)['changes']} self.assertEqual('deleted', res_index['/test1']['status']) self.assertTrue('/test2' not in res_index) self.assertEqual('new', res_index['/test3']['status']) self.assertTrue('/test4' not in res_index) self.assertEqual('new', res_index['/test5']['status']) self.assertTrue('/test6' not in res_index) #================================================== delete_data_dir()