def test_permission(self): key = Key.generate() view = View(self.log, key) view.build() path = os.path.join(os.sep, utils.random_ascii()) with self.assertRaises(exceptions.PermissionDenied): view.mkdir(path)
def test_dir_file_exists_conflict(self): view = View(self.log, self.root_key) view.build() path = os.path.join(os.sep, utils.random_ascii()) content = utils.random_ascii() view.write(path, content) with self.assertRaises(exceptions.Exists): view.mkdir(path)
def init(self): __, self.logpath = tempfile.mkstemp() __, self.logpath_b = tempfile.mkstemp() self.addCleanup(os.remove, self.logpath) self.addCleanup(os.remove, self.logpath_b) self.log, self.root_key = utils.bootstrap(self.logpath) shutil.copy2(self.logpath, self.logpath_b) self.log_b = Log(self.logpath_b) self.log.load() self.log_b.load() self.view = View(self.log, self.root_key) self.view_b = View(self.log_b, self.root_key) self.view.build() self.view_b.build() protocol = BasefsSyncProtocol(self.log) protocol_b = BasefsSyncProtocol(self.log_b) protocol.transport = utils.Socket() protocol_b.transport = utils.Socket() return protocol, protocol_b
def test_build(self): view = View(self.log, self.root_key) view.build() path = os.path.join(os.sep, '.cluster') self.assertEqual(b'127.0.0.1\n', view.get(path).content)
class HandlerTests(unittest.TestCase): def init(self): __, self.logpath = tempfile.mkstemp() __, self.logpath_b = tempfile.mkstemp() self.addCleanup(os.remove, self.logpath) self.addCleanup(os.remove, self.logpath_b) self.log, self.root_key = utils.bootstrap(self.logpath) shutil.copy2(self.logpath, self.logpath_b) self.log_b = Log(self.logpath_b) self.log.load() self.log_b.load() self.view = View(self.log, self.root_key) self.view_b = View(self.log_b, self.root_key) self.view.build() self.view_b.build() protocol = BasefsSyncProtocol(self.log) protocol_b = BasefsSyncProtocol(self.log_b) protocol.transport = utils.Socket() protocol_b.transport = utils.Socket() return protocol, protocol_b def test_sync(self): protocol, protocol_b = self.init() self.assertEqual(protocol.initial_request(), protocol_b.initial_request()) path = os.path.join(os.sep, 'home-' + utils.random_ascii()) node = self.view.mkdir(path) protocol.update_merkle(node.entry) self.assertNotEqual(protocol.initial_request(), protocol_b.initial_request()) # 1 request = protocol_b.initial_request() # 2 protocol.data_received(request) response = protocol.transport.read() protocol.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*/ ' + self.log.root.hash, response.decode().splitlines()[1]) # 3 protocol_b.data_received(response) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.PATH_REQ, response.decode().splitlines()[0]) self.assertEqual(path, response.decode().splitlines()[1]) self.assertEqual(2, len(response.decode().splitlines())) # 4 protocol.data_received(response) response = protocol.transport.read() with self.assertRaises(ValueError): protocol.transport.read(close_check=True) protocol.transport = utils.Socket() self.assertEqual(protocol.ENTRIES, response.decode().splitlines()[0]) self.assertEqual(3, len(response.decode().splitlines())) self.assertEqual(protocol.CLOSE, response.decode().splitlines()[-1]) # 5 protocol_b.data_received(response) with self.assertRaises(ValueError): protocol_b.transport.read(close_check=True) self.assertEqual(self.log.print_tree(), self.log_b.print_tree()) self.assertDictEqual(protocol.merkle, protocol_b.merkle) # delete dnode = self.view.delete(path) protocol.update_merkle(dnode.entry) request = protocol_b.initial_request() # 2 protocol.data_received(request) response = protocol.transport.read() protocol.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*/ ' + self.log.root.hash, response.decode().splitlines()[1]) # 3 protocol_b.data_received(response) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*%s %s' % (path, node.entry.hash), response.decode().splitlines()[1]) self.assertEqual(2, len(response.decode().splitlines())) # 4 protocol.data_received(response) response = protocol.transport.read() with self.assertRaises(ValueError): protocol.transport.read(close_check=True) protocol.transport = utils.Socket() self.assertEqual(protocol.ENTRIES, response.decode().splitlines()[0]) self.assertEqual(3, len(response.decode().splitlines())) self.assertEqual(protocol.CLOSE, response.decode().splitlines()[-1]) # 5 protocol_b.data_received(response) with self.assertRaises(ValueError): protocol_b.transport.read(close_check=True) self.assertEqual(self.log.print_tree(), self.log_b.print_tree()) self.assertDictEqual(protocol.merkle, protocol_b.merkle) def test_sync_reverse(self): # Reverse communication protocol, protocol_b = self.init() path = os.path.join(os.sep, 'home-' + utils.random_ascii()) node = self.view.mkdir(path) protocol.update_merkle(node.entry) # 1 request = protocol.initial_request() # 2 protocol_b.data_received(request) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*/ ' + self.log.root.hash, response.decode().splitlines()[1]) # 3 protocol.data_received(response) with self.assertRaises(ValueError): protocol.transport.read(close_check=True) response = protocol.transport.read() self.assertEqual(protocol.ENTRIES, response.decode().splitlines()[0]) self.assertEqual(3, len(response.decode().splitlines())) self.assertEqual(protocol.CLOSE, response.decode().splitlines()[-1]) # 4 protocol_b.data_received(response) with self.assertRaises(ValueError): protocol_b.transport.read(close_check=True) with self.assertRaises(ValueError): protocol.transport.read(close_check=True) self.assertEqual(self.log.print_tree(), self.log_b.print_tree()) self.assertDictEqual(protocol.merkle, protocol_b.merkle) # delete dnode = self.view.delete(path) protocol.update_merkle(dnode.entry) request = protocol.initial_request() # 2 protocol_b.data_received(request) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*/ ' + self.log.root.hash, response.decode().splitlines()[1]) # 3 protocol.data_received(response) response = protocol.transport.read() protocol.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual( '*%s %s %s' % (path, node.entry.hash, dnode.entry.hash), response.decode().splitlines()[1]) self.assertEqual(2, len(response.decode().splitlines())) # 4 protocol_b.data_received(response) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.ENTRY_REQ, response.decode().splitlines()[0]) self.assertEqual(dnode.entry.hash, response.decode().splitlines()[1]) # 5 protocol.data_received(response) response = protocol.transport.read() with self.assertRaises(ValueError): protocol.transport.read(close_check=True) protocol.transport = utils.Socket() self.assertEqual(protocol.ENTRIES, response.decode().splitlines()[0]) self.assertEqual(protocol.CLOSE, response.decode().splitlines()[-1]) self.assertEqual(3, len(response.decode().splitlines())) # BAD request before = self.log.print_tree() protocol.data_received(response) self.assertEqual(before, self.log.print_tree()) # 6 protocol_b.data_received(response) with self.assertRaises(ValueError): protocol_b.transport.read(close_check=True) self.assertDictEqual(protocol.merkle, protocol_b.merkle) self.assertEqual(self.log.print_tree(), self.log_b.print_tree())
def test_deleted_nested_dir(self): view = View(self.log, self.root_key) view.build() home_path = os.path.join(os.sep, 'home-' + utils.random_ascii()) user_path = os.path.join(home_path, 'user-' + utils.random_ascii()) view.mkdir(home_path) view.mkdir(user_path) view.delete(home_path) self.assertEqual(LogEntry.DELETE, view.get(home_path).entry.action) with self.assertRaises(exceptions.DoesNotExist): view.get(user_path) self.rebuild(view) self.assertEqual(LogEntry.DELETE, view.get(home_path).entry.action) with self.assertRaises(exceptions.DoesNotExist): view.get(user_path)
def test_revoke(self): root_view = View(self.log, self.root_key) root_view.build() home_path = os.path.join(os.sep, 'home-' + utils.random_ascii()) root_view.mkdir(home_path) key = Key.generate() root_view.grant(home_path, 'user', key) view = View(self.log, key) view.build() user_path = os.path.join(home_path, 'user-' + utils.random_ascii()) view.mkdir(user_path) root_view.build() file_path = os.path.join(user_path, 'file2-' + utils.random_ascii()) file_content = ('content1-' + utils.random_ascii(1024)) * 32 root_view.write(file_path, file_content) self.assertEqual(file_content.encode(), root_view.get(file_path).content) root_view.revoke(home_path, 'user') self.assertEqual(file_content.encode(), root_view.get(file_path).content) self.assertEqual(file_path, root_view.get(file_path).path) view.build() # with open(self.logpath, 'r') as r: # print(r.read()) print(self.log.print_tree(view=view, color=True)) root_view.build() # TODO tree eq after build, except the revoke brancj # TODO test maintain current state (file writen by revoked user) print(self.log.print_tree(view=root_view, color=True)) alt_file_content = 'content2-' + utils.random_ascii() with self.assertRaises(exceptions.DoesNotExist): view.write(file_path, alt_file_content)
def test_grant(self): view = View(self.log, self.root_key) view.build() home_path = os.path.join(os.sep, utils.random_ascii()) view.mkdir(home_path) key = Key.generate() view.grant(home_path, 'user', key) prev = str(view.root) view.build() self.assertEqual(len(prev), len(str(view.root))) # Change key view = View(self.log, key) view.build() content = utils.random_ascii() file_path = os.path.join(os.sep, utils.random_ascii()) with self.assertRaises(exceptions.PermissionDenied): view.write(file_path, content) user_path = os.path.join(home_path, utils.random_ascii()) view.mkdir(user_path) self.assertEqual(LogEntry.MKDIR, view.get(user_path).entry.action) file_path = os.path.join(user_path, utils.random_ascii()) content = utils.random_ascii() view.write(file_path, content) self.assertEqual(content.encode(), view.get(file_path).content) view = View(self.log, self.root_key) view.build() view.write(file_path, content) self.assertEqual(content.encode(), view.get(file_path).content) file_path = os.path.join(user_path, utils.random_ascii()) content = utils.random_ascii() view.write(file_path, content) self.assertEqual(content.encode(), view.get(file_path).content) self.rebuild(view)
def test_delete(self): view = View(self.log, self.root_key) view.build() # Delete File file_path = os.path.join(os.sep, utils.random_ascii()) content = utils.random_ascii() view.write(file_path, content) self.assertEqual(LogEntry.WRITE, view.get(file_path).entry.action) self.assertEqual(content.encode(), view.get(file_path).content) view.delete(file_path) self.assertEqual(LogEntry.DELETE, view.get(file_path).entry.action) # Reload self.rebuild(view) self.assertEqual(LogEntry.DELETE, view.get(file_path).entry.action) # Delete Dir home_path = os.path.join(os.sep, utils.random_ascii()) view.mkdir(home_path) self.assertEqual(LogEntry.MKDIR, view.paths.get(home_path).entry.action) view.delete(home_path) self.assertEqual(LogEntry.DELETE, view.get(home_path).entry.action)
def test_recreate_deleted(self): view = View(self.log, self.root_key) view.build() home_path = os.path.join(os.sep, 'home-' + utils.random_ascii()) user_path = os.path.join(home_path, 'user-' + utils.random_ascii()) view.mkdir(home_path) view.mkdir(user_path) file_path = os.path.join(user_path, utils.random_ascii()) file_content = utils.random_ascii() view.write(file_path, file_content) self.assertEqual(file_content.encode(), view.get(file_path).content) view.delete(home_path) with self.assertRaises(exceptions.DoesNotExist): view.get(file_path) view.mkdir(home_path) with self.assertRaises(exceptions.DoesNotExist): view.get(file_path) with self.assertRaises(exceptions.DoesNotExist): view.get(user_path) # File view.mkdir(user_path) new_file_content = utils.random_ascii() view.write(file_path, new_file_content) self.assertEqual(new_file_content.encode(), view.get(file_path).content) # Reload self.rebuild(view) self.assertEqual(new_file_content.encode(), view.get(file_path).content) view.get(user_path) view.delete(file_path) new_file_content = utils.random_ascii() view.write(file_path, new_file_content) self.assertEqual(new_file_content.encode(), view.get(file_path).content)
def test_revert(self): view = View(self.log, self.root_key) view.build() rata_node = view.mkdir('/rata')
def test_hardlink(self): view = View(self.log, self.root_key) view.build() rata_node = view.mkdir('/rata') view.link('/home', rata_node.entry.hash) print(view.get('/home') == rata_node) kakas_node = view.write('/kakas', b'hola') view.link('/kakas_link', kakas_node.entry.hash) self.assertEqual(b'hola', view.get('/kakas_link').content) view.delete('/kakas') self.assertEqual(b'hola', view.get('/kakas_link').content) print(view.get('/kakas').content)
def test_symlink(self): view = View(self.log, self.root_key) view.build() view.symlink('/kakas', '/rata') print(view.get('/kakas').content)
def test_branch_conflict(self): view = View(self.log, self.root_key) view.build() home_path = os.path.join(os.sep, 'home-' + utils.random_ascii()) view.mkdir(home_path) key = Key.generate() view.grant(home_path, 'user', key) view = View(self.log, key) view.build() parent_node = view.get(home_path) user_path = os.path.join(home_path, 'user-' + utils.random_ascii()) max_hash = None enc_content = '' for ix in range(12): content = 'content-' + utils.random_ascii(32) prev = enc_content enc_content = bsdiff4.diff(enc_content, content) entry = self.log.write(parent_node.entry, user_path, key, attachment=enc_content) max_hash = max(max_hash, entry.hash) if max_hash else entry.hash view = View(self.log, self.root_key) view.build() self.assertEqual(bsdiff4.patch(prev, self.log.entries[max_hash].get_content()), view.get(user_path).content) # Admin branch more power admin_content = 'content-' + utils.random_ascii(32) content = bsdiff4.diff(enc_content, admin_content) self.log.write(parent_node.entry, user_path, self.root_key, attachment=content) view.build() self.assertEqual(admin_content.encode(), view.get(user_path).content) alt_content = bsdiff4.diff(content, ('content-' + utils.random_ascii(32)).encode()) self.log.write(parent_node.entry, user_path, key, attachment=alt_content) self.assertEqual(admin_content.encode(), view.get(user_path).content) # Grant consistency with prev state view.grant(os.sep, 'user', key) self.assertEqual(admin_content.encode(), view.get(user_path).content) view.build() self.assertEqual(admin_content.encode(), view.get(user_path).content) # Test prints self.log.print_tree(view=view, color=True) self.log.print_tree(view=view, ascii=True)
def test_revoke(self): root_view = View(self.log, self.root_key) root_view.build() home_path = os.path.join(os.sep, 'home-' + utils.random_ascii()) root_view.mkdir(home_path) key = Key.generate() root_view.grant(home_path, 'user', key) view = View(self.log, key) view.build() user_path = os.path.join(home_path, 'user-' + utils.random_ascii()) view.mkdir(user_path) root_view.build() file_path = os.path.join(user_path, 'file2-' + utils.random_ascii()) file_content = ('content1-' + utils.random_ascii(1024))*32 root_view.write(file_path, file_content) self.assertEqual(file_content.encode(), root_view.get(file_path).content) root_view.revoke(home_path, 'user') self.assertEqual(file_content.encode(), root_view.get(file_path).content) self.assertEqual(file_path, root_view.get(file_path).path) view.build() # with open(self.logpath, 'r') as r: # print(r.read()) print(self.log.print_tree(view=view, color=True)) root_view.build() # TODO tree eq after build, except the revoke brancj # TODO test maintain current state (file writen by revoked user) print(self.log.print_tree(view=root_view, color=True)) alt_file_content = 'content2-' + utils.random_ascii() with self.assertRaises(exceptions.DoesNotExist): view.write(file_path, alt_file_content)
def test_mkdir(self): view = View(self.log, self.root_key) view.build() home_path = os.sep + utils.random_ascii() view.mkdir(home_path) self.assertEqual(LogEntry.MKDIR, view.paths.get(home_path).entry.action) user_path = os.path.join(home_path, utils.random_ascii()) view.mkdir(user_path) self.assertEqual(LogEntry.MKDIR, view.get(user_path).entry.action) not_path = os.path.join(os.sep, utils.random_ascii(), utils.random_ascii()) with self.assertRaises(exceptions.DoesNotExist): view.mkdir(not_path) with self.assertRaises(exceptions.DoesNotExist): view.get(not_path) self.rebuild(view) self.assertEqual(LogEntry.MKDIR, view.get(home_path).entry.action) self.assertEqual(LogEntry.MKDIR, view.get(user_path).entry.action) with self.assertRaises(exceptions.DoesNotExist): view.get(not_path)
def test_branch_conflict(self): view = View(self.log, self.root_key) view.build() home_path = os.path.join(os.sep, 'home-' + utils.random_ascii()) view.mkdir(home_path) key = Key.generate() view.grant(home_path, 'user', key) view = View(self.log, key) view.build() parent_node = view.get(home_path) user_path = os.path.join(home_path, 'user-' + utils.random_ascii()) max_hash = None enc_content = '' for ix in range(12): content = 'content-' + utils.random_ascii(32) prev = enc_content enc_content = bsdiff4.diff(enc_content, content) entry = self.log.write(parent_node.entry, user_path, key, attachment=enc_content) max_hash = max(max_hash, entry.hash) if max_hash else entry.hash view = View(self.log, self.root_key) view.build() self.assertEqual( bsdiff4.patch(prev, self.log.entries[max_hash].get_content()), view.get(user_path).content) # Admin branch more power admin_content = 'content-' + utils.random_ascii(32) content = bsdiff4.diff(enc_content, admin_content) self.log.write(parent_node.entry, user_path, self.root_key, attachment=content) view.build() self.assertEqual(admin_content.encode(), view.get(user_path).content) alt_content = bsdiff4.diff(content, ('content-' + utils.random_ascii(32)).encode()) self.log.write(parent_node.entry, user_path, key, attachment=alt_content) self.assertEqual(admin_content.encode(), view.get(user_path).content) # Grant consistency with prev state view.grant(os.sep, 'user', key) self.assertEqual(admin_content.encode(), view.get(user_path).content) view.build() self.assertEqual(admin_content.encode(), view.get(user_path).content) # Test prints self.log.print_tree(view=view, color=True) self.log.print_tree(view=view, ascii=True)
def test_write(self): view = View(self.log, self.root_key) view.build() path = os.path.join(os.sep, utils.random_ascii()) content = utils.random_ascii() view.write(path, content) self.assertEqual(LogEntry.WRITE, view.get(path).entry.action) self.assertEqual(content.encode(), view.get(path).content) self.rebuild(view) self.assertEqual(content.encode(), view.get(path).content) with self.assertRaises(exceptions.Exists): view.mkdir(path) view.delete(path) view.mkdir(path) path = os.path.join(path, 'content-%s' % utils.random_ascii()) alt_content = utils.random_ascii() view.write(path, alt_content) self.assertEqual(alt_content.encode(), view.get(path).content) alt_content += utils.random_ascii() view.write(path, alt_content) self.assertEqual(alt_content.encode(), view.get(path).content) alt_content = utils.random_ascii(512**2) view.write(path, alt_content) self.assertEqual(alt_content.encode(), view.get(path).content) view.delete(path) self.assertEqual(LogEntry.DELETE, view.get(path).entry.action) view.mkdir(path) self.assertEqual(LogEntry.MKDIR, view.get(path).entry.action) view.delete(path) self.assertEqual(LogEntry.DELETE, view.get(path).entry.action) view.write(path, alt_content) self.assertEqual(alt_content.encode(), view.get(path).content)
def command(mount=False, arg_parser=None): if arg_parser is None: # Invoking from code, not basefs bin set_parser(parser) arg_parser = parser args = arg_parser.parse_args() context = get_context(args.logpath, defaults) logpath = context.fs.logpath if context.mount_info: mountpoint = context.mount_info.mountpoint sys.stderr.write("Error: log %s already mounted in %s\n" % (logpath, mountpoint)) sys.exit(4) ip, *port = args.bind.split(':') if port: port = int(port[0]) else: port = context.fs.port if args.iface: iface_ip = utils.get_ip_address(args.iface) if ip != '0.0.0.0' and ip != iface_ip: sys.stderr.write("-bind and -iface ip addresses do not match %s != %s\n" % (ip, iface_ip)) sys.exit(9) ip = iface_ip # logpath = args.logpath config = get_or_create_config(defaults) hostname = args.hostname section = config[context.fs.name] if not hostname: if context.fs.name in config: hostname = section['hostname'] else: hostname = defaults.hostname rpc_port = port+1 sync_port = port+2 logpath = os.path.normpath(logpath) keypath = os.path.normpath(args.keypath) logging.basicConfig( level=logging.DEBUG if args.debug else logging.INFO, format='%(asctime)-15s [%(levelname)s] %(name)s: %(message)s', ) logpath = os.path.normpath(logpath) log = Log(logpath) log.load() if keypath == defaults.keypath and not os.path.exists(keypath): view = View(log) else: key = Key.load(keypath) view = View(log, key) view.build() serf = None serf_agent = None if args.serf: join = args.join.split(',') if args.join else [] serf, serf_agent = gossip.run(section, view, ip, port, hostname, join) if args.watcher: handler = handlers.Handler(args.watcher, view.log, state=serf.blockstate) else: if args.watcher: handler = handlers.Handler(args.watcher, view.log) if mount: init_function = lambda: None if args.serf: # Eventloop needs to run on a separated thread when using FUSE init_function = lambda: loop.run_thread(view, serf, port+2, config=section) mountpoint = args.mountpoint sys.stdout.write('Mounting %s into %s\n' % (logpath, mountpoint)) fs = FileSystem(view, serf=serf, serf_agent=serf_agent, init_function=init_function) fsname = '%s:%i' % (logpath, sync_port) foreground = args.foreground or args.debug FUSE(fs, mountpoint, fsname=fsname, nothreads=False, foreground=foreground) else: try: loop.run(view, serf, port+2, config=section) except KeyboardInterrupt: pass finally: serf_agent.stop()
class HandlerTests(unittest.TestCase): def init(self): __, self.logpath = tempfile.mkstemp() __, self.logpath_b = tempfile.mkstemp() self.addCleanup(os.remove, self.logpath) self.addCleanup(os.remove, self.logpath_b) self.log, self.root_key = utils.bootstrap(self.logpath) shutil.copy2(self.logpath, self.logpath_b) self.log_b = Log(self.logpath_b) self.log.load() self.log_b.load() self.view = View(self.log, self.root_key) self.view_b = View(self.log_b, self.root_key) self.view.build() self.view_b.build() protocol = BasefsSyncProtocol(self.log) protocol_b = BasefsSyncProtocol(self.log_b) protocol.transport = utils.Socket() protocol_b.transport = utils.Socket() return protocol, protocol_b def test_sync(self): protocol, protocol_b = self.init() self.assertEqual(protocol.initial_request(), protocol_b.initial_request()) path = os.path.join(os.sep, 'home-' + utils.random_ascii()) node = self.view.mkdir(path) protocol.update_merkle(node.entry) self.assertNotEqual(protocol.initial_request(), protocol_b.initial_request()) # 1 request = protocol_b.initial_request() # 2 protocol.data_received(request) response = protocol.transport.read() protocol.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*/ ' + self.log.root.hash, response.decode().splitlines()[1]) # 3 protocol_b.data_received(response) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.PATH_REQ, response.decode().splitlines()[0]) self.assertEqual(path, response.decode().splitlines()[1]) self.assertEqual(2, len(response.decode().splitlines())) # 4 protocol.data_received(response) response = protocol.transport.read() with self.assertRaises(ValueError): protocol.transport.read(close_check=True) protocol.transport = utils.Socket() self.assertEqual(protocol.ENTRIES, response.decode().splitlines()[0]) self.assertEqual(3, len(response.decode().splitlines())) self.assertEqual(protocol.CLOSE, response.decode().splitlines()[-1]) # 5 protocol_b.data_received(response) with self.assertRaises(ValueError): protocol_b.transport.read(close_check=True) self.assertEqual(self.log.print_tree(), self.log_b.print_tree()) self.assertDictEqual(protocol.merkle, protocol_b.merkle) # delete dnode = self.view.delete(path) protocol.update_merkle(dnode.entry) request = protocol_b.initial_request() # 2 protocol.data_received(request) response = protocol.transport.read() protocol.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*/ ' + self.log.root.hash, response.decode().splitlines()[1]) # 3 protocol_b.data_received(response) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*%s %s' % (path, node.entry.hash), response.decode().splitlines()[1]) self.assertEqual(2, len(response.decode().splitlines())) # 4 protocol.data_received(response) response = protocol.transport.read() with self.assertRaises(ValueError): protocol.transport.read(close_check=True) protocol.transport = utils.Socket() self.assertEqual(protocol.ENTRIES, response.decode().splitlines()[0]) self.assertEqual(3, len(response.decode().splitlines())) self.assertEqual(protocol.CLOSE, response.decode().splitlines()[-1]) # 5 protocol_b.data_received(response) with self.assertRaises(ValueError): protocol_b.transport.read(close_check=True) self.assertEqual(self.log.print_tree(), self.log_b.print_tree()) self.assertDictEqual(protocol.merkle, protocol_b.merkle) def test_sync_reverse(self): # Reverse communication protocol, protocol_b = self.init() path = os.path.join(os.sep, 'home-' + utils.random_ascii()) node = self.view.mkdir(path) protocol.update_merkle(node.entry) # 1 request = protocol.initial_request() # 2 protocol_b.data_received(request) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*/ ' + self.log.root.hash, response.decode().splitlines()[1]) # 3 protocol.data_received(response) with self.assertRaises(ValueError): protocol.transport.read(close_check=True) response = protocol.transport.read() self.assertEqual(protocol.ENTRIES, response.decode().splitlines()[0]) self.assertEqual(3, len(response.decode().splitlines())) self.assertEqual(protocol.CLOSE, response.decode().splitlines()[-1]) # 4 protocol_b.data_received(response) with self.assertRaises(ValueError): protocol_b.transport.read(close_check=True) with self.assertRaises(ValueError): protocol.transport.read(close_check=True) self.assertEqual(self.log.print_tree(), self.log_b.print_tree()) self.assertDictEqual(protocol.merkle, protocol_b.merkle) # delete dnode = self.view.delete(path) protocol.update_merkle(dnode.entry) request = protocol.initial_request() # 2 protocol_b.data_received(request) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*/ ' + self.log.root.hash, response.decode().splitlines()[1]) # 3 protocol.data_received(response) response = protocol.transport.read() protocol.transport = utils.Socket() self.assertEqual(protocol.LS, response.decode().splitlines()[0]) self.assertEqual('*%s %s %s' % (path, node.entry.hash, dnode.entry.hash), response.decode().splitlines()[1]) self.assertEqual(2, len(response.decode().splitlines())) # 4 protocol_b.data_received(response) response = protocol_b.transport.read() protocol_b.transport = utils.Socket() self.assertEqual(protocol.ENTRY_REQ, response.decode().splitlines()[0]) self.assertEqual(dnode.entry.hash, response.decode().splitlines()[1]) # 5 protocol.data_received(response) response = protocol.transport.read() with self.assertRaises(ValueError): protocol.transport.read(close_check=True) protocol.transport = utils.Socket() self.assertEqual(protocol.ENTRIES, response.decode().splitlines()[0]) self.assertEqual(protocol.CLOSE, response.decode().splitlines()[-1]) self.assertEqual(3, len(response.decode().splitlines())) # BAD request before = self.log.print_tree() protocol.data_received(response) self.assertEqual(before, self.log.print_tree()) # 6 protocol_b.data_received(response) with self.assertRaises(ValueError): protocol_b.transport.read(close_check=True) self.assertDictEqual(protocol.merkle, protocol_b.merkle) self.assertEqual(self.log.print_tree(), self.log_b.print_tree())