def run_server(directory, port, token, file_size_limit, min_chunk_size, max_chunk_size): """ Start a (non-daemonized) server. This is a server-related command that start a non-daemonized server (not detached from the shell). The directory parameter is the root directory which will be served and therefore must be an existing directory. The server listens on port 6768 by default but it can be changed with the port parameter. If the token is not specified, it's generated and printed out to the console before the server starts running. Additionally, the file size limit and the chunk size range can be altered. The file size limit and minimum chunk size must be both be greater than 0, and maximum chunk size must be greater or equal to minimum chunk size. """ if not token: token = generate_token() display_generated_token(token) try: server = Server(directory, token, file_size_limit, min_chunk_size, max_chunk_size) except NotADirectoryError: print(INVALID_ROOT_DIRECTORY_MESSAGE) exit(1) except ValueError: print(INCORRECT_VALUE_ERROR_MESSAGE) exit(1) server.run('127.0.0.1', port)
def setUp(self): # create remote working directory self.remote_directory = TemporaryDirectory() self.remote_directory_path = PosixPath(self.remote_directory.name) # start the server in an external thread self.server = Server(self.remote_directory_path, TOKEN) def server_loop(server): server.run(HOSTNAME, PORT) self.server_thread = threading.Thread(target=server_loop, args=(self.server,)) self.server_thread.start()
def start_server(directory, port, token, pidfile, file_size_limit, min_chunk_size, max_chunk_size): """ Start a daemonized server. This is a server-related command that start a daemonized server (detached from the shell). Unlike the run command, it accepts the --pidfile flag which tells the pidfile location. By default, the pidfile is created in the current working directory and named 'daemon.pid'. Refer to the run command for more information. """ if not token: token = generate_token() display_generated_token(token) try: server = Server(directory, token, file_size_limit, min_chunk_size, max_chunk_size) except NotADirectoryError: print(INVALID_ROOT_DIRECTORY_MESSAGE) exit(1) except ValueError: print(INCORRECT_VALUE_ERROR_MESSAGE) exit(1) def loop(): server.run('127.0.0.1', port) daemon = Daemon(loop, pidfile) daemon.start()
class TestClient(unittest.TestCase): """ Test the client class. It consists of testing its methods that implement all native file operations. """ def setUp(self): # create local working directory self.local_directory = TemporaryDirectory() self.local_directory_path = PosixPath(self.local_directory.name) # create remote working directory self.remote_directory = TemporaryDirectory() self.remote_directory_path = PosixPath(self.remote_directory.name) # start the server in an external thread self.server = Server(self.remote_directory_path, TOKEN) def server_loop(server): server.run(HOSTNAME, PORT) self.server_thread = threading.Thread(target=server_loop, args=(self.server, )) self.server_thread.start() # change working direcory to local working directory self.last_working_directory = os.getcwd() os.chdir(self.local_directory_path) def tearDown(self): # restore current working directory os.chdir(self.last_working_directory) # terminate the server and wait until it terminates self.server.terminate() self.server_thread.join() # delete all testing contents in both local and remote working # directory self.local_directory.cleanup() self.remote_directory.cleanup() def _create_temporary_file(self, root, directory, name, size): """ Create a temporary file in the 'remote' directory. This function creates a temporary file with a given name in a given directory located in the temporary workinng 'remote' directory. It's filled with a given amount of random data. It returns a posix path of the created file and the generated data. """ assert os.path.isabs(directory) == True directory = directory[1:] file_data = os.urandom(size) temporary_file_path = root / directory / name temporary_file = temporary_file_path.open('wb') temporary_file.write(file_data) temporary_file.close() return temporary_file_path, file_data def _create_temporary_directory(self, root, directory, name): """ Create a temporary directory in the 'remote' directory. This function creates a temporary directory with a given name in a given directory located in the temporary workinng 'remote' directory. It returns a posix path of the created directory. """ assert os.path.isabs(directory) == True directory = directory[1:] temporary_directory_path = root / directory / name temporary_directory_path.mkdir(exist_ok=False) return temporary_directory_path def create_local_file(self, directory, name, size): return self._create_temporary_file(self.local_directory_path, directory, name, size) def create_local_directory(self, directory, name): return self._create_temporary_directory(self.local_directory_path, directory, name) def create_remote_file(self, directory, name, size): return self._create_temporary_file(self.remote_directory_path, directory, name, size) def create_remote_directory(self, directory, name): return self._create_temporary_directory(self.remote_directory_path, directory, name) def test_list_files(self): """ Test the list files method. It creates 'foo.bin' file and 'bar/' directory in the root directory and tests before and after if the correct dictionnary is returned. It ends with testing listing files with a relative path (which is not permitted) and listing files of a non-existing directory. """ # create client instance client = Client(HOSTNAME, PORT, TOKEN) # test listing files of the empty root directory files = client.list_files('/') self.assertDictEqual(files, {}) # test listing files of root directory after creating 'foo.bin' # and 'bar/' in it file_path, _ = self.create_remote_file('/', 'foo.bin', 1052) directory_path = self.create_remote_directory('/', 'bar') expected_files = { 'foo.bin': (False, 1052, file_path.stat().st_atime), 'bar': (True, 0, directory_path.stat().st_atime) } files = client.list_files('/') self.assertDictEqual(files, expected_files) # test listing files with a relative directory with self.assertRaises(ValueError): client.list_files('bar') # test listing files of a non-existing directory with self.assertRaises(NotADirectoryError): client.list_files('/foo') def test_create_file(self): """ Test the create file method. It starts with creating a temporary working tree of files. /foo.bin /bar/qaz.txt Then, it attempts to create a file 'foo.bin' in 'bar' directory with invalid parameters to test each possible errors. It finishes with creating the file successfully and test if it has effectively been created. """ # create client instance client = Client(HOSTNAME, PORT, TOKEN) # create remote working tree of files self.create_remote_file('/', 'foo.bin', 1052) self.create_remote_directory('/', 'bar') self.create_remote_file('/bar', 'qaz.txt', 431) # prepare common variables name = 'foo.bin' directory = '/bar' # test creating a file with an invalid name invalid_names = ['*baz', 'b"az', 'baz|'] for invalid_name in invalid_names: with self.assertRaises(InvalidFileName): client.create_file(invalid_name, directory) # test creating a file with a conflicting name invalid_directory = '/' with self.assertRaises(FileExistsError): client.create_file(name, invalid_directory) # test creating a file with a relative directory invalid_directory = 'bar' with self.assertRaises(ValueError): client.create_file(name, invalid_directory) # test creating a file with a non-existing directory invalid_directory = '/foo' with self.assertRaises(NotADirectoryError): client.create_file(name, invalid_directory) # test creating a file with valid parameters created_file = self.remote_directory_path / directory[1:] / name self.assertFalse(created_file.exists()) client.create_file(name, directory) self.assertTrue(created_file.exists()) self.assertTrue(created_file.is_file()) def test_make_directories(self): """ Test the make directory method. It starts with creating a temporary working tree of files. /foo/ /bar/qaz/ Then, it attempts to create a directory 'foo/' in 'bar/' directory with invalid parameters to test each possible errors. It finishes with creating the directory successfully and test if it has effectively been created. """ # create client instance client = Client(HOSTNAME, PORT, TOKEN) # create remote working tree of files self.create_remote_directory('/', 'foo') self.create_remote_directory('/', 'bar') self.create_remote_directory('/', 'qaz') # prepare common variables name = 'foo' directory = '/bar' # test making a directory with an invalid name invalid_names = ['*baz', 'b"az', 'baz|'] for invalid_name in invalid_names: with self.assertRaises(InvalidFileName): client.make_directory(invalid_name, directory) # test making a directory with a conflicting name invalid_directory = '/' with self.assertRaises(FileExistsError): client.make_directory(name, invalid_directory) # test making a directory with a relative directory invalid_directory = 'bar' with self.assertRaises(ValueError): client.make_directory(name, invalid_directory) # test making a directory with a non-existing directory invalid_directory = '/foo/bar' with self.assertRaises(NotADirectoryError): client.make_directory(name, invalid_directory) # test making a directory with valid parameters created_directory = self.remote_directory_path / directory[1:] / name self.assertFalse(created_directory.exists()) client.make_directory(name, directory) self.assertTrue(created_directory.exists()) self.assertTrue(created_directory.is_dir()) def test_upload_file(self): """ Test the upload file method. It starts with creating a local working directory and remote working directory as follow. Local working directory. foo.bin Remote working directory. bar/ qaz/foo.bin Then it attempts to upload the local 'foo.bin' file to the remote 'bar/' directory. It does it by testing different foobar. It finishes with barfoo. """ # create client instance client = Client(HOSTNAME, PORT, TOKEN) # create local working tree of files _, file_data = self.create_local_file('/', 'foo.bin', 1052) # create remote working tree of files self.create_remote_directory('/', 'bar') self.create_remote_directory('/', 'qaz') self.create_remote_file('/qaz', 'foo.bin', 1052) # prepare common variables source = 'foo.bin' destination = '/bar' name = None chunk_size = 512 process_chunk = None # prepare assert routines def assert_file_not_uploaded(source, destination, name=None): if not name: name = PurePosixPath(source).name uploaded_file_path = self.remote_directory_path / destination[ 1:] / name self.assertFalse(uploaded_file_path.exists()) def assert_file_uploaded(source, destination, name=None): if not name: name = PurePosixPath(source).name uploaded_file_path = self.remote_directory_path / destination[ 1:] / name self.assertTrue(uploaded_file_path.is_file()) uploaded_file = uploaded_file_path.open('rb') self.assertEqual(uploaded_file.read(), file_data) uploaded_file.close() def delete_uploaded_file(source, destination, name=None): if not name: name = PurePosixPath(source).name uploaded_file_path = self.remote_directory_path / destination[ 1:] / name os.remove(uploaded_file_path) # test uploading a file with source is a relative path assert_file_not_uploaded(source, destination, name) client.upload_file(source, destination, name, chunk_size, process_chunk) assert_file_uploaded(source, destination, name) delete_uploaded_file(source, destination, name) # test uploading a file with source is an absolute path assert_file_not_uploaded(source, destination, name) client.upload_file(self.local_directory_path / source, destination, name, chunk_size, process_chunk) assert_file_uploaded(source, destination, name) delete_uploaded_file(source, destination, name) # test uploading a file with changing its name assert_file_not_uploaded(source, destination, 'bar.bin') client.upload_file(source, destination, 'bar.bin', chunk_size, process_chunk) assert_file_uploaded(source, destination, 'bar.bin') delete_uploaded_file(source, destination, 'bar.bin') # test uploading a file with a source file that doesn't exist # (todo: make 2 versions of it, one with source exists but is # not a file) with self.assertRaises(SourceNotFound): client.upload_file('foo.txt', destination, name, chunk_size, process_chunk) assert_file_not_uploaded(source, destination, 'foo.txt') # test uploading a file with destination being a relative path with self.assertRaises(ValueError): client.upload_file(source, 'bar', name, chunk_size, process_chunk) assert_file_not_uploaded(source, '/bar', name) # test uploading a file with a destination directory that # doesn't exist (todo: make 2 versions of it, one with # destination exist but is not a directory) with self.assertRaises(DestinationNotFound): client.upload_file(source, '/foo', name, chunk_size, process_chunk) assert_file_not_uploaded(source, '/foo', name) # test uploading a file with a name that conflicts with an # existing file in the destination directory with self.assertRaises(FileExistsError): client.upload_file(source, '/qaz', name, chunk_size, process_chunk) # test uploading a file with an invalid chunk size with self.assertRaises(ValueError): client.upload_file(source, destination, name, 0, process_chunk) assert_file_not_uploaded(source, destination, name) # test uploading a file with a custom process chunk callback expected_chunk_data = (file_data[:512], file_data[512:1024], file_data[1024:]) expected_remaining_bytes = (1052, 1052 - 512, 1052 - 512 - 512) def custom_process_chunk(chunk_data, remaining_bytes, file_size, file_name): self.assertEqual(chunk_data, expected_chunk_data[custom_process_chunk.counter]) self.assertEqual( remaining_bytes, expected_remaining_bytes[custom_process_chunk.counter]) self.assertEqual(file_size, 1052) custom_process_chunk.counter += 1 return True custom_process_chunk.counter = 0 assert_file_not_uploaded(source, destination, name) client.upload_file(source, destination, name, 512, custom_process_chunk) self.assertEqual(custom_process_chunk.counter, 3) assert_file_uploaded(source, destination, name) delete_uploaded_file(source, destination, name) # test uploading a file with a custom process chunk callback # that interupts the upload def custom_process_chunk(chunk_data, remaining_bytes, file_size, file_name): custom_process_chunk.counter += 1 if custom_process_chunk.counter == 1: return False return True custom_process_chunk.counter = 0 client.upload_file(source, destination, name, chunk_size, custom_process_chunk) assert_file_not_uploaded(source, destination, name) # test uploading a file with chunk size greater than the file # size being uploaded assert_file_not_uploaded(source, destination, name) client.upload_file(source, destination, name, 4096, process_chunk) assert_file_uploaded(source, destination, name) delete_uploaded_file(source, destination, name) # test uploading a file again to ensure the previous operations # didn't corrupt the server state assert_file_not_uploaded(source, destination, name) client.upload_file(source, destination, name, chunk_size, process_chunk) assert_file_uploaded(source, destination, name) delete_uploaded_file(source, destination, name) def test_upload_directory(self): """ Test the upload directory method. It starts with creating a local working directory and remote working directory as follow. Local working directory. foo/ bar.bin qaz/xyz.img Remote working directory. foo/ bar/ Then, it attempts to upload the 'foo/' local directory to the 'bar/' remote directory by trying different erroueonous versions. It finishes with foobar. To be written. """ # create client instance client = Client(HOSTNAME, PORT, TOKEN) # create local working directory self.create_local_directory('/', 'foo') _, bar_file_data = self.create_local_file('/foo', 'bar.bin', 1052) self.create_local_directory('/foo', 'qaz') _, xyz_file_data = self.create_local_file('/foo/qaz', 'xyz.img', 321) # create remote working directory self.create_remote_directory('/', 'foo') self.create_remote_directory('/', 'bar') # prepare common variables source = 'foo' destination = '/bar' name = None chunk_size = 512 process_chunk = None # prepare assert routines def assert_directory_not_uploaded(source, destination, name=None): if not name: name = PosixPath(source).name uploaded_directory_path = self.remote_directory_path / destination[ 1:] / name self.assertFalse(uploaded_directory_path.exists()) def assert_directory_uploaded(source, destination, name=None): if not name: name = PosixPath(source).name # assert foo/ foo_directory_path = self.remote_directory_path / destination[ 1:] / name self.assertTrue(foo_directory_path.is_dir()) # assert foo/bar.bin bar_file_path = self.remote_directory_path / destination[ 1:] / name / 'bar.bin' self.assertTrue(bar_file_path.is_file()) self.assertEqual(bar_file_path.open('rb').read(), bar_file_data) # assert foo/qaz qaz_directory_path = self.remote_directory_path / destination[ 1:] / name / 'qaz' self.assertTrue(qaz_directory_path.is_dir()) # assert foo/qaz/xyz.img xyz_file_path = self.remote_directory_path / destination[ 1:] / name / 'qaz/xyz.img' self.assertTrue(xyz_file_path.is_file()) self.assertEqual(xyz_file_path.open('rb').read(), xyz_file_data) def delete_uploaded_directory(source, destination, name=None): if not name: name = PosixPath(source).name uploaded_directory_path = self.remote_directory_path / destination[ 1:] / name shutil.rmtree(uploaded_directory_path) # test uploading a directory with source is an relative path assert_directory_not_uploaded(source, destination, name) client.upload_directory(self.local_directory_path / source, destination, name, chunk_size, process_chunk) assert_directory_uploaded(source, destination, name) delete_uploaded_directory(source, destination, name) # test uploading a directory with source is an absolute path assert_directory_not_uploaded(source, destination, name) client.upload_directory(source, destination, name, chunk_size, process_chunk) assert_directory_uploaded(source, destination, name) delete_uploaded_directory(source, destination, name) # test uploading a directory with changing its name assert_directory_not_uploaded(source, destination, 'qux') client.upload_directory(source, destination, 'qux', chunk_size, process_chunk) assert_directory_uploaded(source, destination, 'qux') delete_uploaded_directory(source, destination, 'qux') # test uploading a directory with a source directory that # doesn't exist (todo: make 2 versions of it, one with source # exists but is not a directory) with self.assertRaises(SourceNotFound): client.upload_directory('qaz', destination, name, chunk_size, process_chunk) # test uploading a directory with destination being a relative # path with self.assertRaises(ValueError): client.upload_directory(source, 'bar', name, chunk_size, process_chunk) # test uploading a directory with a destination directory that # doesn't exist (todo: make 2 versions of it, one with # destination exists but is not a directory) with self.assertRaises(DestinationNotFound): client.upload_directory(source, '/qaz', name, chunk_size, process_chunk) # test uploading a directory with an invalid chunk size with self.assertRaises(ValueError): client.upload_directory(source, destination, name, 0, process_chunk) # test uploading the directory again to ensure the previous # operations didn't correup the server state assert_directory_not_uploaded(source, destination, name) client.upload_directory(source, destination, name, chunk_size, process_chunk) assert_directory_uploaded(source, destination, name) delete_uploaded_directory(source, destination, name) def test_download_file(self): """ Test the download file method. It starts with creating a local working directory and remote working directory as follow. Local working directory. /bar/foo.bin qaz/ Remote working directory. /bar/foo.bin Then it attempts to download the remote 'foo.bin' file to the local 'qaz/' directory. It does it by testing different foobar. It finishes with barfoo. """ # create client instance client = Client(HOSTNAME, PORT, TOKEN) # create local working tree of files self.create_local_directory('/', 'bar') self.create_local_directory('/', 'qaz') self.create_local_file('/bar', 'foo.bin', 1052) # create remote working tree of files self.create_remote_directory('/', 'bar') _, file_data = self.create_remote_file('/bar', 'foo.bin', 1052) # prepare common variables source = '/bar/foo.bin' destination = 'qaz' name = None chunk_size = 512 process_chunk = None # prepare assert routines def assert_file_not_downloaded(source, destination, name=None): if not name: name = PurePosixPath(source).name downloaded_file_path = self.local_directory_path / destination / name self.assertFalse(downloaded_file_path.exists()) def assert_file_downloaded(source, destination, name=None): if not name: name = PurePosixPath(source).name downloaded_file_path = self.local_directory_path / destination / name self.assertTrue(downloaded_file_path.is_file()) downloaded_file = downloaded_file_path.open('rb') self.assertEqual(downloaded_file.read(), file_data) downloaded_file.close() def delete_downloaded_file(source, destination, name=None): if not name: name = PurePosixPath(source).name downloaded_file_path = self.local_directory_path / destination / name os.remove(downloaded_file_path) # test downloading a file with destination is a relative path assert_file_not_downloaded(source, destination, name) client.download_file(source, destination, name, chunk_size, process_chunk) assert_file_downloaded(source, destination, name) delete_downloaded_file(source, destination, name) # test downloading a file with destination is an absolute path assert_file_not_downloaded(source, destination, name) client.download_file(source, self.local_directory_path / destination, name, chunk_size, process_chunk) assert_file_downloaded(source, destination, name) delete_downloaded_file(source, destination, name) # test downloading a file with changing its name assert_file_not_downloaded(source, destination, 'bar.bin') client.download_file(source, destination, 'bar.bin', chunk_size, process_chunk) assert_file_downloaded(source, destination, 'bar.bin') delete_downloaded_file(source, destination, 'bar.bin') # test downloading a file with source being a relative path with self.assertRaises(ValueError): client.download_file('bar/foo.bin', destination, name, chunk_size, process_chunk) assert_file_not_downloaded('bar/foo.bin', destination, name) # test downloading a file with a source file that doesn't exist # (todo: make 2 versions of it, one with source exists but is # not a file) with self.assertRaises(SourceNotFound): client.download_file('/foo.bin', destination, name, chunk_size, process_chunk) assert_file_not_downloaded('/foo.bin', destination, name) # test downloading a file with a destination directory that # doesn't exist (todo: make 2 versions of it, one with # destination exist but is not a directory) with self.assertRaises(DestinationNotFound): client.download_file(source, 'foo', name, chunk_size, process_chunk) assert_file_not_downloaded(source, 'foo', name) # test downloading a file with a name that conflicts with an # existing file in the destination directory with self.assertRaises(FileExistsError): client.download_file(source, 'bar', name, chunk_size, process_chunk) # test downloading a file with an invalid chunk size with self.assertRaises(ValueError): client.download_file(source, destination, name, 0, process_chunk) assert_file_not_downloaded(source, destination, name) # test downloading a file with a custom process chunk callback pass # test downloading a file with a custom process chunk callback # that interupts the upload pass # test downloading a file with chunk size greater than the file # size being uploaded pass # test downloading a file again to ensure the previous operations # didn't corrupt the server state pass def test_download_directory(self): """ Test the download directory method. Local working directory. bar/ qaz/foo Remote working directory. foo/ bar.bin qaz/xyz.img Then, it attempts to download the 'foo/' remote directory to the 'bar/' remote directory by trying different erroueonous versions. To be written. """ # create client instance client = Client(HOSTNAME, PORT, TOKEN) # create local working tree of files self.create_local_directory('/', 'bar') self.create_local_directory('/', 'qaz') self.create_local_directory('/qaz', 'foo') # create remote working tree of files self.create_remote_directory('/', 'foo') _, bar_file_data = self.create_remote_file('/foo', 'bar.bin', 1052) self.create_remote_directory('/foo', 'qaz') _, xyz_file_data = self.create_remote_file('/foo/qaz', 'xyz.img', 312) # prepare assert routines def assert_directory_not_downloaded(source, destination, name=None): if not name: name = PurePosixPath(source).name downloaded_directory_path = self.local_directory_path / destination / name self.assertFalse(downloaded_directory_path.exists()) def assert_directory_downloaded(source, destination, name=None): if not name: name = PurePosixPath(source).name # assert foo/ foo_directory_path = self.local_directory_path / destination / name self.assertTrue(foo_directory_path.is_dir()) # assert foo/bar.bin bar_file_path = self.local_directory_path / destination / name / 'bar.bin' self.assertTrue(bar_file_path.is_file()) self.assertEqual(bar_file_path.open('rb').read(), bar_file_data) # assert foo/qaz qaz_directory_path = self.local_directory_path / destination / name / 'qaz' self.assertTrue(qaz_directory_path.is_dir()) # assert foo/qaz/xyz.img xyz_file_path = self.local_directory_path / destination / name / 'qaz/xyz.img' self.assertTrue(xyz_file_path.is_file()) self.assertEqual(xyz_file_path.open('rb').read(), xyz_file_data) def delete_downloaded_directory(source, destination, name=None): if not name: name = PurePosixPath(source).name downloaded_directory_path = self.local_directory_path / destination / name shutil.rmtree(downloaded_directory_path) # prepare common variables source = '/foo' destination = 'bar' name = None chunk_size = 512 process_chunk = None # test downloading a directory with destination is a relative path assert_directory_not_downloaded(source, destination, name) client.download_directory(source, destination, name, chunk_size, process_chunk) assert_directory_downloaded(source, destination, name) delete_downloaded_directory(source, destination, name) # test downloading a directory with destination is an absolute path assert_directory_not_downloaded(source, destination, name) client.download_directory(source, self.local_directory_path / destination, name, chunk_size, process_chunk) assert_directory_downloaded(source, destination, name) delete_downloaded_directory(source, destination, name) # test downloading a directory with changing its name assert_directory_not_downloaded(source, destination, 'bar') client.download_directory(source, destination, 'bar', chunk_size, process_chunk) assert_directory_downloaded(source, destination, 'bar') delete_downloaded_directory(source, destination, 'bar') # test downloading a directory with source being a relative path with self.assertRaises(ValueError): client.download_directory('foo', destination, name, chunk_size, process_chunk) assert_directory_not_downloaded(source, destination, name) # test downloading a directory with a source directory that doesn't exist # (todo: make 2 versions of it, one with source exists but is # not a file) with self.assertRaises(SourceNotFound): client.download_directory('/bar', destination, name, chunk_size, process_chunk) # test downloading a directory with a destination directory that # doesn't exist (todo: make 2 versions of it, one with # destination exist but is not a directory) with self.assertRaises(DestinationNotFound): client.download_directory(source, 'foo', name, chunk_size, process_chunk) assert_directory_not_downloaded(source, 'foo', name) # test downloading a directory with a name that conflicts with an # existing file in the destination directory with self.assertRaises(FileExistsError): client.download_directory(source, 'qaz', name, chunk_size, process_chunk) # test downloading a directory with an invalid chunk size with self.assertRaises(ValueError): client.download_directory(source, destination, name, 0, process_chunk) assert_directory_not_downloaded(source, destination, name) # test downloading a directory again to ensure the previous operations # didn't corrupt the server state assert_directory_not_downloaded(source, destination, name) client.download_directory(source, destination, name, chunk_size, process_chunk) assert_directory_downloaded(source, destination, name) delete_downloaded_directory(source, destination, name)
class TestProtocol(unittest.TestCase): """ Test the transfer file protocol. It consists of testing all request methods and their possible responses. """ def setUp(self): # create remote working directory self.remote_directory = TemporaryDirectory() self.remote_directory_path = PosixPath(self.remote_directory.name) # start the server in an external thread self.server = Server(self.remote_directory_path, TOKEN) def server_loop(server): server.run(HOSTNAME, PORT) self.server_thread = threading.Thread(target=server_loop, args=(self.server,)) self.server_thread.start() def tearDown(self): # terminate the server and wait until it terminates self.server.terminate() self.server_thread.join() # delete all testing contents in served directory self.remote_directory.cleanup() def create_temporary_file(self, directory, name, size): """ Create a temporary file in the 'remote' directory. This function creates a temporary file with a given name in a given directory located in the temporary workinng 'remote' directory. It's filled with a given amount of random data. It returns a posix path of the created file and the generated data. """ assert os.path.isabs(directory) == True directory = directory[1:] file_data = os.urandom(size) temporary_file_path = self.remote_directory_path / directory / name temporary_file = temporary_file_path.open('wb') temporary_file.write(file_data) temporary_file.close() return temporary_file_path, file_data def create_temporary_directory(self, directory, name): """ Create a temporary directory in the 'remote' directory. This function creates a temporary directory with a given name in a given directory located in the temporary workinng 'remote' directory. It returns a posix path of the created directory. """ assert os.path.isabs(directory) == True directory = directory[1:] temporary_directory_path = self.remote_directory_path / directory / name temporary_directory_path.mkdir(exist_ok=False) return temporary_directory_path def test_list_files_request(self): """ Test the LIST_FILE request. It starts with constructing the following working tree and subsequently tests during the creation if listing files of these two folders return the correct list of files. /foo.bin bar/qaz.txt It ends with testing listing files of a non-existing directory. """ # create socket and connect to the server context = zmq.Context.instance() socket = context.socket(zmq.REQ) socket.setsockopt(zmq.IDENTITY, bytes(TOKEN, 'utf-8')) socket.connect('tcp://{0}:{1}'.format(HOSTNAME, str(PORT))) # test listing files of (empty) root directory expected_response = (Response.ACCEPTED, Reason.FILES_LISTED, {}) for list_directory in ('/', ''): request = make_list_files_request(list_directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test listing files of root directory after creating 'foo.bin' # and 'bar/' in it file_path, _ = self.create_temporary_file('/', 'foo.bin', 1052) directory_path = self.create_temporary_directory('/', 'bar') expected_files_list= { 'foo.bin' : (False, 1052, file_path.stat().st_atime), 'bar' : (True, 0, directory_path.stat().st_atime) } for list_directory in ('/', ''): request = make_list_files_request(list_directory) socket.send_pyobj(request) response = socket.recv_pyobj() response_type, reason_type, files_list = response self.assertEqual(response_type, Response.ACCEPTED) self.assertEqual(reason_type, Reason.FILES_LISTED) self.assertDictEqual(files_list, expected_files_list) # test listing files of (empty) bar/ directory expected_response = (Response.ACCEPTED, Reason.FILES_LISTED, {}) for list_directory in ('/bar', 'bar'): request = make_list_files_request(list_directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test listing files of bar/ directory after creating qaz.txt in # it file_path, _ = self.create_temporary_file('/bar', 'qaz.txt', 1024) expected_files_list= { 'qaz.txt' : (False, 1024, file_path.stat().st_atime), } for list_directory in ('/bar', 'bar'): request = make_list_files_request(list_directory) socket.send_pyobj(request) response = socket.recv_pyobj() response_type, reason_type, files_list = response self.assertEqual(response_type, Response.ACCEPTED) self.assertEqual(reason_type, Reason.FILES_LISTED) self.assertDictEqual(files_list, expected_files_list) # test listing files of a non-existing directory expected_response = (Response.REFUSED, Reason.NOT_A_DIRECTORY) for list_directory in ('/foo', 'foo'): request = make_list_files_request(list_directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) def test_create_file_request(self): """ Test the CREATE_FILE request. It starts with creating a temporary working tree of files. foo/ bar.bin Then, it attemps to create a file 'qaz.bin' in 'foo/' directory. But before, it tests the create file request by sending several invalid requests. * Send a bad request * Send the three invalid requests expecting the three variant of refused responses The last step is sending a valid request and check if the file has effectively been created at the right location. """ # create socket and connect to the server context = zmq.Context.instance() socket = context.socket(zmq.REQ) socket.setsockopt(zmq.IDENTITY, bytes(TOKEN, 'utf-8')) socket.connect('tcp://{0}:{1}'.format(HOSTNAME, str(PORT))) # create temporary working tree of files self.create_temporary_directory('/', 'foo') self.create_temporary_file('/foo', 'bar.bin', 1024) # prepare common variables name = 'qaz.bin' directory = '/foo' # test sending invalid create file request because it's badly # formatted expected_response = (Response.ERROR, Reason.BAD_REQUEST) request = make_bad_request(Request.CREATE_FILE) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid create file request because the file name # is invalid invalid_names = ['*baz', 'b"az', 'baz|'] expected_response = (Response.REFUSED, Reason.INVALID_FILE_NAME) for invalid_name in invalid_names: request = make_create_file_request(invalid_name, directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid create file request because it has a # non-existing directory incorrect_directory = '/bar' expected_response = (Response.REFUSED, Reason.NOT_A_DIRECTORY) request = make_create_file_request(name, incorrect_directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid create file request because it the file # name conflicts with an existing file (or directory) incorrect_name = 'bar.bin' expected_response = (Response.REFUSED, Reason.FILE_ALREADY_EXISTS) request = make_create_file_request(incorrect_name, directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending valid create file request and test if the file # has effectively been created before and after the request expected_response = (Response.ACCEPTED, Reason.FILE_CREATED) created_file_path = self.remote_directory_path / directory[1:] / name self.assertFalse(created_file_path.exists()) request = make_create_file_request(name, directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) self.assertTrue(created_file_path.is_file()) def test_make_directory_request(self): """ Test the MAKE_DIRECTORY request. It starts with creating a temporary working tree of files. foo/ bar/ Then, it attemps to create a directory 'qaz/' in 'foo/' directory. But before, it tests the create directory request by sending several invalid requests. - Send a bad request - Send the three invalid requests expecting the three variant of refused responses The last step is sending a valid request and check if the directory has effectively been created at the right location. """ # create socket and connect to the server context = zmq.Context.instance() socket = context.socket(zmq.REQ) socket.setsockopt(zmq.IDENTITY, bytes(TOKEN, 'utf-8')) socket.connect('tcp://{0}:{1}'.format(HOSTNAME, str(PORT))) # create temporary working tree of files self.create_temporary_directory('/', 'foo') self.create_temporary_directory('/foo', 'bar') # prepare common variables name = 'qaz' directory = '/foo' # test sending invalid make directory request because it's badly # formatted expected_response = (Response.ERROR, Reason.BAD_REQUEST) request = make_bad_request(Request.MAKE_DIRECTORY) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid make directory request because the # directory name is incorrect invalid_names = ['*baz', 'b"az', 'baz|'] expected_response = (Response.REFUSED, Reason.INVALID_FILE_NAME) for invalid_name in invalid_names: request = make_make_directory_request(invalid_name, directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid make directory request because it has a # non-existing directory incorrect_directory = '/bar' expected_response = (Response.REFUSED, Reason.NOT_A_DIRECTORY) request = make_make_directory_request(name, incorrect_directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid make directory request because the # directory name conflicts with an existing directory (or file) incorrect_name = 'bar' expected_response = (Response.REFUSED, Reason.FILE_ALREADY_EXISTS) request = make_make_directory_request(incorrect_name, directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending valid make directory request and check if the # directory has effectively been created at the right location expected_response = (Response.ACCEPTED, Reason.DIRECTORY_CREATED) created_directory_path = self.remote_directory_path / directory[1:] / name self.assertFalse(created_directory_path.exists()) request = make_make_directory_request(name, directory) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) self.assertTrue(created_directory_path.is_dir()) def test_upload_file_request(self): """ Test the upload request-response cycle. It starts with creating a temporary working tree of files. foo/ bar.bin Then, it attempts to upload a file 'qaz.bin' to the 'foo/' directory. But before, it tests the upload request by sending several invalid requests. - Send a bad request - Send the four invalid requests expecting the four variant of refused responses - Send a valid request, but send invalid chunks later - Send a valid request, but cancel transfer later The last step is sending a valid request and send send chunk requests until completion of the upload. It finishes with testing if the uploaded file has effectively been created at the right location and has the correct binary content. """ # create socket and connect to the server context = zmq.Context.instance() socket = context.socket(zmq.REQ) socket.setsockopt(zmq.IDENTITY, bytes(TOKEN, 'utf-8')) socket.connect('tcp://{0}:{1}'.format(HOSTNAME, str(PORT))) # create temporary working tree of files self.create_temporary_directory('/', 'foo') self.create_temporary_file('/foo', 'bar.bin', 1024) # prepare common variables name = 'qaz.bin' directory = '/foo' file_size = 1052 chunk_size = 512 # test sending invalid upload file request because it's badly # formatted expected_response = (Response.ERROR, Reason.BAD_REQUEST) request = make_bad_request(Request.UPLOAD_FILE) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid upload file request because it's has a # non-existing directory incorrect_directory = '/bar' expected_response = (Response.REFUSED, Reason.NOT_A_DIRECTORY) request = make_upload_file_request(name, incorrect_directory, file_size, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid upload file request because a file with # that name already exists incorrect_name = 'bar.bin' expected_response = (Response.REFUSED, Reason.FILE_ALREADY_EXISTS) request = make_upload_file_request(incorrect_name, directory, file_size, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid upload file request because the file size # is incorrect incorrect_file_sisze = 0 expected_response = (Response.REFUSED, Reason.INCORRECT_FILE_SIZE) request = make_upload_file_request(name, directory, incorrect_file_sisze, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid upload file request because it has an # incorrect chunk size incorrect_chunk_size = 0 expected_response = (Response.REFUSED, Reason.INCORRECT_CHUNK_SIZE) request = make_upload_file_request(name, directory, file_size, incorrect_chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending valid upload file request, then send one valid # chunk followed by one invalid chunk valid_chunk_data = bytes(chunk_size) invalid_chunk_data = bytes(chunk_size - 1) expected_responses = ( (Response.ACCEPTED, Reason.CHUNK_RECEIVED), (Response.ERROR, Reason.BAD_REQUEST) ) request = make_upload_file_request(name, directory, file_size, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, (Response.ACCEPTED, Reason.TRANSFER_ACCEPTED)) request = make_send_chunk_request(valid_chunk_data) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_responses[0]) request = make_send_chunk_request(invalid_chunk_data) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_responses[1]) # test sending valid upload file request, then send one valid # chunk followed by a cancel transfer request chunk_data = bytes(chunk_size) expected_responses = ( (Response.ACCEPTED, Reason.CHUNK_RECEIVED), (Response.ACCEPTED, Reason.TRANSFER_CANCELLED) ) request = make_upload_file_request(name, directory, file_size, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, (Response.ACCEPTED, Reason.TRANSFER_ACCEPTED)) request = make_send_chunk_request(chunk_data) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_responses[0]) request = make_cancel_transfer_request() socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_responses[1]) # test sending valid upload file request, send valid chunks # until completion of upload file_data = os.urandom(file_size) chunks = (file_data[:512], file_data[512:1024], file_data[1024:]) expected_responses = ( (Response.ACCEPTED, Reason.CHUNK_RECEIVED), (Response.ACCEPTED, Reason.CHUNK_RECEIVED), (Response.ACCEPTED, Reason.TRANSFER_COMPLETED) ) request = make_upload_file_request(name, directory, file_size, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, (Response.ACCEPTED, Reason.TRANSFER_ACCEPTED)) for i in range(3): request = make_send_chunk_request(chunks[i]) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_responses[i]) # verify if uploaded file is at the right location and has the # same binary data uploaded_file_path = self.remote_directory_path / directory[1:] / name self.assertTrue(uploaded_file_path.is_file()) uploaded_file = uploaded_file_path.open('rb') self.assertEqual(file_data, uploaded_file.read()) uploaded_file.close() def test_download_file_request(self): """ Test the download request-response cycle. It starts with creating a temporary working tree of files. foo/ bar.bin qaz/ Then, it attemps to download 'bar.bin' from 'foo/' directory. But before, it tests the download request by sending several invalid requests. - Send a bad request - Send the four invalid requests expecting the four variant of refused responses - Send a valid request, but send invalid chunks later - Send a valid request, but cancel transfer later The last step is sending a valid request and send receive chunk requests until completion of the upload. """ # create socket and connect to the server context = zmq.Context.instance() socket = context.socket(zmq.REQ) socket.setsockopt(zmq.IDENTITY, bytes(TOKEN, 'utf-8')) socket.connect('tcp://{0}:{1}'.format(HOSTNAME, str(PORT))) # create temporary working tree of files self.create_temporary_directory('/', 'foo') _, file_data = self.create_temporary_file('/foo', 'bar.bin', 1052) self.create_temporary_directory('/foo', 'qaz') # prepare common variables name = 'bar.bin' directory = '/foo' file_size = 1052 chunk_size = 512 # test sending invalid download file request because it's badly # formatted expected_response = (Response.ERROR, Reason.BAD_REQUEST) request = make_bad_request(Request.DOWNLOAD_FILE) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid download file request because the chunk # size is incorrect incorrect_chunk_size = 0 expected_response = (Response.REFUSED, Reason.INCORRECT_CHUNK_SIZE) request = make_download_file_request(name, directory, incorrect_chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid download file request because the file # name is incorrect invalid_names = ['*baz', 'b"az', 'baz|'] expected_response = (Response.REFUSED, Reason.INVALID_FILE_NAME) for invalid_name in invalid_names: request = make_download_file_request(invalid_name, directory, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid download file request because it has # a non-existing directory incorrect_directory = '/qaz' expected_response = (Response.REFUSED, Reason.NOT_A_DIRECTORY) request = make_download_file_request(name, incorrect_directory, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid download file request because it has a # file that doesn't exist incorrect_name = 'qaz.bin' expected_response = (Response.REFUSED, Reason.FILE_NOT_FOUND) request = make_download_file_request(incorrect_name, directory, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending invalid download file request because it has a # name that refers to a directory instead of a file incorrect_name = 'qaz' expected_response = (Response.REFUSED, Reason.NOT_A_FILE) request = make_download_file_request(incorrect_name, directory, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_response) # test sending valid download file request, then send one valid # receive request followed by a cancel transfer request expected_responses = ( (Response.ACCEPTED, Reason.CHUNK_SENT, file_data[:512]), (Response.ACCEPTED, Reason.TRANSFER_CANCELLED) ) request = make_download_file_request(name, directory, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, (Response.ACCEPTED, Reason.TRANSFER_ACCEPTED, file_size)) request = make_receive_chunk_request() socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_responses[0]) request = make_cancel_transfer_request() socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_responses[1]) # test sending valid download file request, send receive chunks # requests until completion of download expected_responses = ( (Response.ACCEPTED, Reason.CHUNK_SENT, file_data[:512]), (Response.ACCEPTED, Reason.CHUNK_SENT, file_data[512:1024]), (Response.ACCEPTED, Reason.TRANSFER_COMPLETED, file_data[1024:]) ) request = make_download_file_request(name, directory, chunk_size) socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, (Response.ACCEPTED, Reason.TRANSFER_ACCEPTED, file_size)) for i in range(3): request = make_receive_chunk_request() socket.send_pyobj(request) response = socket.recv_pyobj() self.assertTupleEqual(response, expected_responses[i]) def test_remove_file_request(self): """ Test the REMOVE_FILE request Long description. """ pass
class TestCLI(unittest.TestCase): """ Test the command-line interface. To be written. """ def setUp(self): # create local working directory self.local_directory = TemporaryDirectory() self.local_directory_path = PosixPath(self.local_directory.name) # create remote working directory self.remote_directory = TemporaryDirectory() self.remote_directory_path = PosixPath(self.remote_directory.name) # start the server in an external thread self.server = Server(self.remote_directory_path, TOKEN) def server_loop(server): server.run(HOSTNAME, PORT) self.server_thread = threading.Thread(target=server_loop, args=(self.server, )) self.server_thread.start() # change working direcory to local working directory self.last_working_directory = os.getcwd() os.chdir(self.local_directory_path) def tearDown(self): # restore current working directory os.chdir(self.last_working_directory) # terminate the server and wait until it terminates self.server.terminate() self.server_thread.join() # delete all testing contents in both local and remote working # directory self.local_directory.cleanup() self.remote_directory.cleanup() def _create_temporary_file(self, root, directory, name, size): """ Create a temporary file in the 'remote' directory. This function creates a temporary file with a given name in a given directory located in the temporary workinng 'remote' directory. It's filled with a given amount of random data. It returns a posix path of the created file and the generated data. """ assert os.path.isabs(directory) == True directory = directory[1:] file_data = os.urandom(size) temporary_file_path = root / directory / name temporary_file = temporary_file_path.open('wb') temporary_file.write(file_data) temporary_file.close() return temporary_file_path, file_data def _create_temporary_directory(self, root, directory, name): """ Create a temporary directory in the 'remote' directory. This function creates a temporary directory with a given name in a given directory located in the temporary workinng 'remote' directory. It returns a posix path of the created directory. """ assert os.path.isabs(directory) == True directory = directory[1:] temporary_directory_path = root / directory / name temporary_directory_path.mkdir(exist_ok=False) return temporary_directory_path def create_local_file(self, directory, name, size): return self._create_temporary_file(self.local_directory_path, directory, name, size) def create_local_directory(self, directory, name): return self._create_temporary_directory(self.local_directory_path, directory, name) def create_remote_file(self, directory, name, size): return self._create_temporary_file(self.remote_directory_path, directory, name, size) def create_remote_directory(self, directory, name): return self._create_temporary_directory(self.remote_directory_path, directory, name) def test_list_command(self): """ Test the upload command. Remote working directory. foo/ bar.bin qaz/xyz.img tox.iso Test invoking the following set of commands. rmf list rmf list / rmf list / -a rmf list / -r rmf list / -a -r rmf list /foo rmf list /foo -a rmf list /foo -r rmf list /foo -a -r Long description. """ # create remote working tree of files self.create_remote_directory('/', 'foo') self.create_remote_file('/foo', 'bar.bin', 1052) self.create_remote_directory('/foo', 'qaz') self.create_remote_file('/foo/qaz', 'xyz.img', 312) self.create_remote_file('/', 'tox.iso', 860) # test with incorrectly configured environment runner = CliRunner() result = runner.invoke(list_files, []) self.assertIn('Configure your environment and try again.', result.output) self.assertEqual(result.exit_code, 1) time.sleep(0.05) # configure the environment os.environ["REMOFILE_HOSTNAME"] = 'localhost' os.environ["REMOFILE_PORT"] = str(PORT) os.environ["REMOFILE_TOKEN"] = TOKEN # test invoking command with minimal parameter runner = CliRunner() result = runner.invoke(list_files, []) self.assertEqual(result.exit_code, 0) self.assertIn("foo", result.output) self.assertIn("tox.iso", result.output) self.assertNotIn("bar.bin", result.output) self.assertNotIn("qaz", result.output) self.assertNotIn("xyz.img", result.output) default_exit_code = result.exit_code default_output = result.output time.sleep(0.05) # test invoking command with default parameters runner = CliRunner() result = runner.invoke(list_files, ['/']) self.assertEqual(result.exit_code, default_exit_code) self.assertEqual(result.output, default_output) time.sleep(0.05) # test invoking command to list root with -a parameter runner = CliRunner() result = runner.invoke(list_files, ['/', '-a']) self.assertEqual(result.exit_code, 0) self.assertIn("[D]", result.output) self.assertIn("foo", result.output) self.assertIn("[F]", result.output) self.assertIn("tox.iso", result.output) self.assertNotIn("bar.bin", result.output) self.assertNotIn("qaz", result.output) self.assertNotIn("xyz.img", result.output) time.sleep(0.05) # test invoking command to list root with -r parameter runner = CliRunner() result = runner.invoke(list_files, ['/', '-r']) self.assertEqual(result.exit_code, 0) self.assertIn("foo", result.output) self.assertIn("tox.iso", result.output) self.assertIn("foo/bar.bin", result.output) self.assertIn("foo/qaz", result.output) self.assertIn("foo/qaz/xyz.img", result.output) self.assertNotIn("[F]", result.output) self.assertNotIn("[D]", result.output) time.sleep(0.05) # test invoking command to list root with -a and -r parameters runner = CliRunner() result = runner.invoke(list_files, ['/', '-a', '-r']) self.assertEqual(result.exit_code, 0) self.assertIn("foo", result.output) self.assertIn("tox.iso", result.output) self.assertIn("foo/bar.bin", result.output) self.assertIn("foo/qaz", result.output) self.assertIn("foo/qaz/xyz.img", result.output) self.assertIn("[F]", result.output) self.assertIn("[D]", result.output) time.sleep(0.05) # test invoking command to list a subdirectory runner = CliRunner() result = runner.invoke(list_files, ['/foo']) self.assertEqual(result.exit_code, 0) self.assertNotIn("foo", result.output) self.assertNotIn("tox.iso", result.output) self.assertIn("bar.bin", result.output) self.assertIn("qaz", result.output) self.assertNotIn("qaz/xyz.img", result.output) self.assertNotIn("[F]", result.output) self.assertNotIn("[D]", result.output) time.sleep(0.05) # test invoking command to list a subdirectory with -a parameter runner = CliRunner() result = runner.invoke(list_files, ['/foo', '-a']) self.assertEqual(result.exit_code, 0) self.assertNotIn("foo", result.output) self.assertNotIn("tox.iso", result.output) self.assertIn("bar.bin", result.output) self.assertIn("qaz", result.output) self.assertNotIn("qaz/xyz.img", result.output) self.assertIn("[F]", result.output) self.assertIn("[D]", result.output) time.sleep(0.05) # test invoking command to list a subdirectory with -r parameter runner = CliRunner() result = runner.invoke(list_files, ['/foo', '-r']) self.assertEqual(result.exit_code, 0) self.assertNotIn("foo", result.output) self.assertNotIn("tox.iso", result.output) self.assertIn("bar.bin", result.output) self.assertIn("qaz", result.output) self.assertIn("qaz/xyz.img", result.output) self.assertNotIn("[F]", result.output) self.assertNotIn("[D]", result.output) time.sleep(0.05) # test invoking command to list a subdirectory with -a and -r parameters runner = CliRunner() result = runner.invoke(list_files, ['/foo', '-a', '-r']) self.assertEqual(result.exit_code, 0) self.assertNotIn("foo", result.output) self.assertNotIn("tox.iso", result.output) self.assertIn("bar.bin", result.output) self.assertIn("qaz", result.output) self.assertIn("qaz/xyz.img", result.output) self.assertIn("[F]", result.output) self.assertIn("[D]", result.output) time.sleep(0.05) # unset the environment del os.environ["REMOFILE_HOSTNAME"] del os.environ["REMOFILE_PORT"] del os.environ["REMOFILE_TOKEN"] def test_file_command(self): """ Test the upload command. Long description. """ pass def test_folder_command(self): """ Test the upload command. Long description. """ pass def test_upload_command(self): """ Test the upload command. Local working directory. foo/ bar.bin qaz/xyz.img tox.iso To simplify tests, don't check binary content of uploaded files and subdirectories (this is covered by client tests). pass """ # create loal working directory self.create_local_directory('/', 'foo') self.create_local_file('/foo', 'bar.bin', 1052) self.create_local_directory('/foo', 'qaz') self.create_local_file('/foo/qaz', 'xyz.img', 312) self.create_local_file('/', 'tox.iso', 860) tox_file_path = self.remote_directory_path / 'tox.iso' foo_directory_path = self.remote_directory_path / 'foo' # prepare common variables pass # test with incorrectly configured environment runner = CliRunner() result = runner.invoke(upload_files, ['foo', 'tox.iso']) self.assertIn('Configure your environment and try again.', result.output) self.assertEqual(result.exit_code, 1) time.sleep(0.05) # set the environment os.environ["REMOFILE_HOSTNAME"] = 'localhost' os.environ["REMOFILE_PORT"] = str(PORT) os.environ["REMOFILE_TOKEN"] = TOKEN # test upload one file self.assertFalse(tox_file_path.exists()) runner = CliRunner() result = runner.invoke(upload_files, ['tox.iso', '/']) self.assertTrue(tox_file_path.is_file()) self.assertEqual(result.exit_code, 0) print(result.output) os.remove(tox_file_path) time.sleep(0.05) # test upload one directory self.assertFalse(foo_directory_path.exists()) runner = CliRunner() result = runner.invoke(upload_files, ['foo', '/']) self.assertEqual(result.exit_code, 0) # might change self.assertFalse(foo_directory_path.exists()) time.sleep(0.05) runner = CliRunner() result = runner.invoke(upload_files, ['foo', '/', '-r']) self.assertEqual(result.exit_code, 0) # might change self.assertTrue(foo_directory_path.is_dir()) shutil.rmtree(foo_directory_path) time.sleep(0.05) # test upload one file and one directory self.assertFalse(tox_file_path.exists()) self.assertFalse(foo_directory_path.exists()) runner = CliRunner() result = runner.invoke(upload_files, ['foo', 'tox.iso', '/']) self.assertEqual(result.exit_code, 0) # might change self.assertTrue(tox_file_path.is_file()) self.assertFalse(foo_directory_path.exists()) os.remove(tox_file_path) time.sleep(0.05) runner = CliRunner() result = runner.invoke(upload_files, ['foo', 'tox.iso', '/', '-r']) self.assertEqual(result.exit_code, 0) # might change self.assertTrue(tox_file_path.is_file()) self.assertTrue(foo_directory_path.is_dir()) os.remove(tox_file_path) shutil.rmtree(foo_directory_path) time.sleep(0.05) # test upload files with the progress flag runner = CliRunner() result = runner.invoke(upload_files, ['foo', 'tox.iso', '/', '-r']) self.assertEqual(result.exit_code, 0) # might change self.assertNotIn('bar.bin', result.output) self.assertNotIn('xyz.img', result.output) self.assertNotIn('tox.iso', result.output) self.assertEqual(result.output.count('100.00%'), 0) os.remove(tox_file_path) shutil.rmtree(foo_directory_path) time.sleep(0.05) runner = CliRunner() result = runner.invoke(upload_files, ['foo', 'tox.iso', '/', '-r', '-p']) self.assertEqual(result.exit_code, 0) # might change self.assertIn('bar.bin', result.output) self.assertIn('xyz.img', result.output) self.assertIn('tox.iso', result.output) self.assertEqual(result.output.count('100.00%'), 3) os.remove(tox_file_path) shutil.rmtree(foo_directory_path) time.sleep(0.05) # test upload files with invalid source runner = CliRunner() result = runner.invoke(upload_files, ['foo.bin', '/']) self.assertEqual(result.exit_code, 1) self.assertIn('Unable to upload file', result.output) self.assertIn('no such file or directory exists', result.output) time.sleep(0.2) ## test upload files with relative destination path #runner = CliRunner() #result = runner.invoke(upload_files, ['foo', 'tox.iso', 'foo', '-r']) #self.assertEqual(result.exit_code, 1) #self.assertIn('Unable to upload files', result.output) #self.assertIn('destination must be an absolute path', result.output) #time.sleep(0.05) ## test upload files with unexisting destination #runner = CliRunner() #result = runner.invoke(upload_files, ['foo', 'tox.iso', '/foo', '-r']) #print(result.output) #self.assertEqual(result.exit_code, 1) #self.assertIn('Unable to upload files', result.output) #self.assertIn('no such directory exists', result.output) #time.sleep(0.2) ## test upload files with conflicting files #self.create_remote_file('/', 'tox.iso', 1204) #runner = CliRunner() #result = runner.invoke(upload_files, ['tox.iso', '/']) #self.assertEqual(result.exit_code, 1) #self.assertIn('Unable to upload file', result.output) #self.assertIn("it's conflicting with an existing file", result.output) #time.sleep(0.05) # test upload files with invalid names (shouldn't happen) pass # test min-size and max-size options pass # create remote working directory tree # /foo/ # bar/ -> existing directory # qaz -> existing file # # test uploading directory with no recursive flag enabled # - bar # - foo # # test uploading to incorrect destination directory # - root directory (/) # - directory whose parent is an unexsiting directory (/foo/qaz/bar) # - directory whose parent is an existing directory but is an unexisting directory (/foo/qaz) # - directory whose parent is an existing directory but is a existing file (/foo/qaz) # # test uploading a file that conflict with existing file (or # directory) # - foo # - bar # pass def test_download_command(self): """ Test the upload command. Long description. """ pass def test_remove_command(self): """ Test the upload command. Long description. """ def test_remove_command(self): """ Test the upload command. Long description. """ pass def test_synchronize_local_command(self): """ Test the upload command. Long description. """ pass def test_synchronize_remote_command(self): """ Test the upload command. Long description. """ pass def test_generate_token_command(self): """ Test the upload command. Long description. """ pass def test_generate_keys_command(self): """ Test the upload command. Long description. """ pass