class TestJobs(object): EXPECTED_STDOUT_WITH_WRONG_API_TOKEN = "Failed to fetch data: Invalid API token\n" RESPONSE_JSON_WITH_WRONG_API_TOKEN = { "status": 400, "message": "Invalid API token" } EXPECTED_HEADERS = default_headers.copy() EXPECTED_HEADERS_WITH_CHANGED_API_KEY = default_headers.copy() EXPECTED_HEADERS_WITH_CHANGED_API_KEY["X-API-Key"] = "some_key"
import sys import mock from click.testing import CliRunner from gradient.api_sdk.clients.http_client import default_headers from gradient.cli import cli from tests import MockResponse EXPECTED_HEADERS = default_headers.copy() EXPECTED_HEADERS["ps_client_name"] = "gradient-cli" EXPECTED_HEADERS_WITH_CHANGED_API_KEY = EXPECTED_HEADERS.copy() EXPECTED_HEADERS_WITH_CHANGED_API_KEY["X-API-Key"] = "some_key" class TestRunCommand(object): command_name = 'run' common_commands = [ "--name", "test", "--projectId", "projectId", "--apiKey", "some_key", "--machineType", "G1", ] COMMAND_WITH_OPTIONS_FILE = [ "run", "--optionsFile",
class TestRunCommand(object): command_name = 'run' common_commands = [ "--name", "test", "--projectId", "projectId", "--apiKey", "some_key", "--machineType", "G1", ] url = "https://api.paperspace.io/jobs/createJob/" headers = default_headers.copy() headers["X-API-Key"] = "some_key" @mock.patch("gradient.api_sdk.clients.http_client.requests.post") @mock.patch("gradient.workspace.WorkspaceHandler._zip_workspace") @mock.patch("gradient.workspace.MultipartEncoder.get_monitor") @mock.patch("gradient.commands.jobs.CreateJobCommand._get_files_dict") def test_run_simple_file_with_args(self, get_files_patched, get_moniror_patched, workspace_zip_patched, post_patched): get_files_patched.return_value = mock.MagicMock() workspace_zip_patched.return_value = '/foo/bar' post_patched.return_value = MockResponse(status_code=200) mock_monitor = mock.MagicMock() mock_monitor.content_type = "mock/multipart" get_moniror_patched.return_value = mock_monitor runner = CliRunner() result = runner.invoke(cli.cli, [self.command_name] + self.common_commands + ["/myscript.py", "a", "b"]) expected_headers = self.headers.copy() expected_headers.update({'Content-Type': "mock/multipart"}) post_patched.assert_called_with(self.url, params={ 'name': u'test', 'projectId': u'projectId', 'workspaceFileName': 'bar', 'command': 'python{} myscript.py a b'.format( str(sys.version_info[0])), 'container': u'paperspace/tensorflow-python', 'machineType': 'G1', }, data=mock.ANY, files=None, headers=expected_headers, json=None) assert result.exit_code == 0 @mock.patch("gradient.api_sdk.clients.http_client.requests.post") def test_run_python_command_with_args_and_no_workspace(self, post_patched): post_patched.return_value = MockResponse(status_code=200) runner = CliRunner() result = runner.invoke(cli.cli, [self.command_name] + self.common_commands + ["-c", "print(foo)", "--workspace", "none"]) expected_headers = self.headers.copy() post_patched.assert_called_with(self.url, params={ 'name': u'test', 'projectId': u'projectId', 'workspaceFileName': 'none', 'workspace': 'none', 'command': 'python{} -c print(foo)'.format( str(sys.version_info[0])), 'container': u'paperspace/tensorflow-python', 'machineType': 'G1', }, data=None, files=None, headers=expected_headers, json=None) @mock.patch("gradient.api_sdk.clients.http_client.requests.post") @mock.patch("gradient.workspace.WorkspaceHandler._zip_workspace") def test_run_shell_command_with_args_with_s3_workspace( self, workspace_zip_patched, post_patched): workspace_zip_patched.return_value = '/foo/bar' post_patched.return_value = MockResponse(status_code=200) runner = CliRunner() result = runner.invoke( cli.cli, [self.command_name] + self.common_commands + ["-s", "echo foo", "--workspaceUrl", "s3://bucket/object"]) expected_headers = self.headers.copy() post_patched.assert_called_with(self.url, params={ 'name': u'test', 'projectId': u'projectId', 'workspaceFileName': 's3://bucket/object', 'workspaceUrl': 's3://bucket/object', 'command': 'echo foo', 'container': u'paperspace/tensorflow-python', 'machineType': 'G1', }, data=None, files=None, headers=expected_headers, json=None)
class TestJobsCreate(object): URL = "https://api.paperspace.io" EXPECTED_HEADERS = default_headers.copy() EXPECTED_HEADERS_WITH_CHANGED_API_KEY = default_headers.copy() EXPECTED_HEADERS_WITH_CHANGED_API_KEY["X-API-Key"] = "some_key" BASIC_OPTIONS_COMMAND = [ "jobs", "create", "--name", "exp1", "--projectId", "testHandle", "--container", "testContainer", "--machineType", "testType", "--command", "testCommand", "--workspace", "https://github.com/Paperspace/gradient-cli.git", ] FULL_OPTIONS_COMMAND = [ "jobs", "create", "--name", "exp1", "--ports", 4567, "--workspaceUrl", "wsp.url", "--workingDirectory", "/work/dir/", "--artifactDirectory", "/artifact/dir/", "--clusterId", 42, "--experimentEnv", '{"key":"val"}', "--projectId", "testHandle", "--container", "testContainer", "--machineType", "testType", "--command", "testCommand", "--containerUser", "conUser", "--registryUsername", "userName", "--registryPassword", "passwd", "--apiKey", "some_key", ] BASIC_OPTIONS_REQUEST = { "name": u"exp1", "projectId": u"testHandle", "container": u"testContainer", "machineType": u"testType", "command": u"testCommand", "workspace": u"https://github.com/Paperspace/gradient-cli.git", "workspaceFileName": u"https://github.com/Paperspace/gradient-cli.git", } FULL_OPTIONS_REQUEST = { "name": u"exp1", "ports": 4567, "workspaceUrl": u"wsp.url", "workingDirectory": u"/work/dir/", "artifactDirectory": u"/artifact/dir/", "clusterId": 42, "experimentEnv": { u"key": u"val" }, "projectHandle": u"testHandle", "container": u"testContainer", "machineType": u"testType", "command": u"testCommand", "containerUser": u"conUser", "registryUsername": u"userName", "registryPassword": u"passwd", } RESPONSE_JSON_200 = {"id": "sadkfhlskdjh", "message": "success"} RESPONSE_CONTENT_200 = b'{"handle":"sadkfhlskdjh","message":"success"}\n' EXPECTED_STDOUT = u'New job created with ID: sadkfhlskdjh\n' RESPONSE_JSON_404_PROJECT_NOT_FOUND = { "details": { "handle": "wrong_handle" }, "error": "Project not found" } RESPONSE_CONTENT_404_PROJECT_NOT_FOUND = b'{"details":{"handle":"wrong_handle"},"error":"Project not found"}\n' EXPECTED_STDOUT_PROJECT_NOT_FOUND = "Project not found\nhandle: wrong_handle\n" @mock.patch("gradient.api_sdk.clients.http_client.requests.post") def test_should_send_proper_data_and_print_message_when_create_job_was_run_with_basic_options( self, post_patched): post_patched.return_value = MockResponse(self.RESPONSE_JSON_200, 200, self.RESPONSE_CONTENT_200) runner = CliRunner() result = runner.invoke(cli.cli, self.BASIC_OPTIONS_COMMAND) post_patched.assert_called_once_with(self.URL + '/jobs/createJob/', headers=self.EXPECTED_HEADERS, json=None, params=self.BASIC_OPTIONS_REQUEST, files=None, data=None) assert self.EXPECTED_STDOUT in result.output assert result.exit_code == 0
class TestListProjects(object): URL = "https://api.paperspace.io/projects/" EXPECTED_HEADERS = default_headers.copy() BASIC_COMMAND = ["projects", "list"] # TODO: change to `REQUEST_JSON = None` or whatever works when PS_API is fixed EXPECTED_RESPONSE_JSON = example_responses.LIST_PROJECTS_RESPONSE EXPECTED_STDOUT = """+-----------+-------------------+------------+----------------------------+ | ID | Name | Repository | Created | +-----------+-------------------+------------+----------------------------+ | prq70zy79 | test_project | None | 2019-03-18 13:24:46.666000 | | prmr22ve0 | keton | None | 2019-03-25 14:50:43.202000 | | przhbct98 | paperspace-python | None | 2019-04-04 15:12:34.229000 | +-----------+-------------------+------------+----------------------------+ """ BASIC_COMMAND_WITH_API_KEY = ["projects", "list", "--apiKey", "some_key"] EXPECTED_HEADERS_WITH_CHANGED_API_KEY = gradient.api_sdk.clients.http_client.default_headers.copy( ) EXPECTED_HEADERS_WITH_CHANGED_API_KEY["X-API-Key"] = "some_key" RESPONSE_JSON_WITH_WRONG_API_TOKEN = { "status": 400, "message": "Invalid API token" } EXPECTED_STDOUT_WITH_WRONG_API_TOKEN = "Failed to fetch data: Invalid API token\n" RESPONSE_JSON_WHEN_NO_PROJECTS_WERE_FOUND = { "data": [], "meta": { "totalItems": 0 } } EXPECTED_STDOUT_WHEN_NO_PROJECTS_WERE_FOUND = "No data found\n" @mock.patch("gradient.api_sdk.clients.http_client.requests.get") def test_should_send_valid_post_request_and_print_table_when_projects_list_was_used( self, get_patched): get_patched.return_value = MockResponse( json_data=self.EXPECTED_RESPONSE_JSON, status_code=200) cli_runner = CliRunner() result = cli_runner.invoke(cli.cli, self.BASIC_COMMAND) assert result.output == self.EXPECTED_STDOUT, result.exc_info get_patched.assert_called_with(self.URL, headers=self.EXPECTED_HEADERS, json=None, params=None) assert result.exit_code == 0 @mock.patch("gradient.api_sdk.clients.http_client.requests.get") def test_should_send_valid_post_request_when_projects_list_was_used_with_api_key_option( self, get_patched): get_patched.return_value = MockResponse( json_data=self.EXPECTED_RESPONSE_JSON, status_code=200) cli_runner = CliRunner() result = cli_runner.invoke(cli.cli, self.BASIC_COMMAND_WITH_API_KEY) get_patched.assert_called_with( self.URL, headers=self.EXPECTED_HEADERS_WITH_CHANGED_API_KEY, json=None, params=None) assert result.output == self.EXPECTED_STDOUT assert result.exit_code == 0 @mock.patch("gradient.api_sdk.clients.http_client.requests.get") def test_should_send_valid_post_request_when_projects_list_was_used_with_wrong_api_key( self, get_patched): get_patched.return_value = MockResponse( json_data=self.RESPONSE_JSON_WITH_WRONG_API_TOKEN, status_code=400) cli_runner = CliRunner() result = cli_runner.invoke(cli.cli, self.BASIC_COMMAND_WITH_API_KEY) get_patched.assert_called_with( self.URL, headers=self.EXPECTED_HEADERS_WITH_CHANGED_API_KEY, json=None, params=None) assert result.output == self.EXPECTED_STDOUT_WITH_WRONG_API_TOKEN assert result.exit_code == 0 @mock.patch("gradient.api_sdk.clients.http_client.requests.get") def test_should_print_error_message_when_no_project_was_not_found( self, get_patched): get_patched.return_value = MockResponse( json_data=self.RESPONSE_JSON_WHEN_NO_PROJECTS_WERE_FOUND, status_code=200) cli_runner = CliRunner() result = cli_runner.invoke(cli.cli, self.BASIC_COMMAND) get_patched.assert_called_with(self.URL, headers=self.EXPECTED_HEADERS, json=None, params=None) assert result.output == self.EXPECTED_STDOUT_WHEN_NO_PROJECTS_WERE_FOUND assert result.exit_code == 0 @mock.patch("gradient.api_sdk.clients.http_client.requests.get") def test_should_print_error_message_when_error_status_code_received_but_no_content_was_provided( self, get_patched): get_patched.return_value = MockResponse(status_code=400) cli_runner = CliRunner() result = cli_runner.invoke(cli.cli, self.BASIC_COMMAND) get_patched.assert_called_with(self.URL, headers=self.EXPECTED_HEADERS, json=None, params=None) assert result.output == "Failed to fetch data\n" assert result.exit_code == 0