Esempio n. 1
0
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"
Esempio n. 2
0
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",
Esempio n. 3
0
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)
Esempio n. 4
0
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
Esempio n. 5
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