Esempio n. 1
0
def test_create_response_list(_clean_specs_table):
    """
    GIVEN database with single spec and list type request, authorization info and uri
    WHEN create_response is called with the type, uri and authorization info
    THEN a list response is returned.
    """
    spec_id = "spec 1"
    version = "version 1"
    uri = f"/{spec_id}/"
    sub = "sub 1"
    auth_info = types.CredentialsAuthInfo(
        sub=sub, secret_key_hash=b"secret key 1", salt=b"salt 1"
    )
    request_type = types.TRequestType.LIST
    package_database.get().create_update_spec(
        sub=sub, name=spec_id, version=version, model_count=1
    )
    public_key = "public key 1"
    secret_key = "secret key 1"
    authorization = types.TAuthorization(public_key=public_key, secret_key=secret_key)

    returned_response = library.create_response(
        authorization=authorization,
        request_type=request_type,
        uri=uri,
        auth_info=auth_info,
    )

    assert returned_response.type == request_type
    assert "<body>" in returned_response.value
    assert spec_id in returned_response.value
    assert version in returned_response.value
    assert public_key in returned_response.value
    assert secret_key in returned_response.value
Esempio n. 2
0
def sub():
    """Generates a sub and cleans up after any tests."""
    sub_value = f"test.{uuid.uuid4()}"

    yield sub_value

    package_database.get().delete_all(sub=sub_value)
Esempio n. 3
0
def test_put_too_many_models_error(monkeypatch, _clean_specs_table):
    """
    GIVEN body spec and spec id and user that already has too many models
    WHEN put is called with the body and spec id
    THEN a 402 with an invalid spec is returned.
    """
    mock_request = mock.MagicMock()
    mock_headers = {"X-LANGUAGE": "JSON"}
    mock_request.headers = mock_headers
    monkeypatch.setattr(server.Request, "request", mock_request)
    version = "1"
    schemas = {
        "Schema": {
            "type": "object",
            "x-tablename": "schema",
            "properties": {"id": {"type": "integer"}},
        }
    }
    body = json.dumps(
        {"info": {"version": version}, "components": {"schemas": schemas}}
    )
    spec_name_1 = "id 1"
    user = "******"
    package_database.get().create_update_spec(
        sub=user, name=spec_name_1, version="1", model_count=100
    )

    spec_name_2 = "id 2"
    response = specs.put(body=body.encode(), spec_name=spec_name_2, user=user)

    assert response.status_code == 402
    assert response.mimetype == "text/plain"
    assert "exceeded" in response.data.decode()
    assert ": 100," in response.data.decode()
    assert "spec: 1" in response.data.decode()
Esempio n. 4
0
def test_delete_storage_error(monkeypatch, _clean_specs_table):
    """
    GIVEN database and storage that raises a StorageError with spec and user and spec
        id
    WHEN put is called with the body and spec id
    THEN the spec is deleted from the database.
    """
    spec_name = "id 1"
    user = "******"
    version = "1"
    package_database.get().create_update_spec(
        sub=user, name=spec_name, version=version, model_count=1
    )
    mock_storage_delete_spec = mock.MagicMock()
    mock_storage_delete_spec.side_effect = storage.exceptions.StorageError
    monkeypatch.setattr(
        storage.get_storage_facade(),
        "delete_spec",
        mock_storage_delete_spec,
    )

    response = specs.delete(spec_name=spec_name, user=user)

    assert package_database.get().count_customer_models(sub=user) == 0
    assert response.status_code == 204
Esempio n. 5
0
def test_get(_clean_specs_table):
    """
    GIVEN user and database and storage with a single spec
    WHEN get is called with the user and spec id
    THEN the spec value is returned.
    """
    user = "******"
    spec_name = "spec name 1"
    version = "1"
    package_database.get().create_update_spec(
        sub=user, name=spec_name, version=version, model_count=1
    )
    spec = {"components": {}}
    storage.get_storage_facade().create_update_spec(
        user=user,
        name=spec_name,
        version=version,
        spec_str=json.dumps(spec, separators=(",", ":")),
    )

    response = specs.get(user=user, spec_name=spec_name)

    assert response.status_code == 200
    assert response.mimetype == "application/json"
    response_data_json = json.loads(response.data.decode())
    assert f"version: '{version}'" in response_data_json["value"]
    assert "components: {}" in response_data_json["value"]
    assert response_data_json["name"] == spec_name
    assert response_data_json["version"] == version
Esempio n. 6
0
def test_check_within_limit(
    initial_items,
    user,
    spec_name,
    model_count,
    expected_result,
    expected_contents,
    _clean_specs_table,
):
    """
    GIVE database with initial items, a user, the name of a spec and a model count
    WHEN check_within_limit is called with the user, spec name and model count
    THEN the expected result and reason is returned.
    """
    free_tier_model_count = 10
    config.get().free_tier_model_count = free_tier_model_count
    for item in initial_items:
        package_database.get().create_update_spec(**item)

    returned_result = free_tier.check_within_limit(user=user,
                                                   spec_name=spec_name,
                                                   model_count=model_count)

    assert returned_result.value == expected_result
    if expected_result:
        assert returned_result.reason is None
    else:
        assert str(free_tier_model_count) in returned_result.reason
        for content in expected_contents:
            assert content in returned_result.reason
Esempio n. 7
0
def test_list_(_clean_specs_table):
    """
    GIVEN user and database with a single spec
    WHEN list_ is called with the user
    THEN all the specs stored on the user are returned.
    """
    user = "******"
    spec_name = "spec name 1"
    version = "1"
    model_count = 1
    package_database.get().create_update_spec(
        sub=user, name=spec_name, version=version, model_count=model_count
    )

    response = specs.list_(user=user)

    assert response.status_code == 200
    assert response.mimetype == "application/json"
    spec_infos = json.loads(response.data.decode())
    assert len(spec_infos) == 1
    spec_info = spec_infos[0]
    assert spec_info["name"] == spec_name
    assert spec_info["id"] == spec_name
    assert spec_info["version"] == version
    assert spec_info["model_count"] == model_count
    assert "updated_at" in spec_info
Esempio n. 8
0
def test_put_database_update_error(monkeypatch, _clean_specs_table):
    """
    GIVEN body and spec id
    WHEN put is called with the body and spec id
    THEN the spec is stored against the spec id.
    """
    mock_request = mock.MagicMock()
    mock_headers = {"X-LANGUAGE": "JSON"}
    mock_request.headers = mock_headers
    monkeypatch.setattr(server.Request, "request", mock_request)
    version = "1"
    spec = {
        "info": {
            "version": version
        },
        "components": {
            "schemas": {
                "Schema": {
                    "type": "object",
                    "x-tablename": "schema",
                    "properties": {
                        "id": {
                            "type": "integer"
                        }
                    },
                }
            }
        },
    }
    body = json.dumps(spec)
    spec_name = "id 1"
    user = "******"
    mock_database_create_update_spec = mock.MagicMock()
    mock_database_create_update_spec.side_effect = package_database.exceptions.BaseError
    monkeypatch.setattr(
        package_database.get(),
        "create_update_spec",
        mock_database_create_update_spec,
    )

    response = versions.put(body=body.encode(),
                            spec_name=spec_name,
                            version=version,
                            user=user)

    spec_str = storage.get_storage_facade().get_spec(user=user,
                                                     name=spec_name,
                                                     version=version)
    assert f'"{version}"' in spec_str
    assert '"Schema"' in spec_str
    assert '"x-tablename"' in spec_str
    assert '"schema"' in spec_str
    assert package_database.get().count_customer_models(sub=user) == 0
    assert response.status_code == 500
    assert response.mimetype == "text/plain"
    assert "database" in response.data.decode()
Esempio n. 9
0
def get(spec_name: types.TSpecId, user: types.TUser) -> server.Response:
    """
    Retrieve a spec for a user.

    Args:
        spec_name: The id of the spec.
        user: The user from the token.

    Returns:
        The response to the request.

    """
    try:
        version = package_database.get().get_latest_spec_version(
            sub=user, name=spec_name
        )
        spec_str = storage.get_storage_facade().get_spec(
            user=user, name=spec_name, version=version
        )
        prepared_spec_str = spec.prepare(spec_str=spec_str, version=version)
        spec_info = package_database.get().get_spec(sub=user, name=spec_name)

        response_data = json.dumps({**spec_info, "value": prepared_spec_str})

        return server.Response(
            response_data,
            status=200,
            mimetype="application/json",
        )
    except package_database.exceptions.NotFoundError:
        return server.Response(
            f"could not find the spec with id {spec_name}",
            status=404,
            mimetype="text/plain",
        )
    except package_database.exceptions.BaseError:
        return server.Response(
            "something went wrong whilst reading from the database",
            status=500,
            mimetype="text/plain",
        )
    except storage.exceptions.ObjectNotFoundError:
        return server.Response(
            f"could not find the spec with id {spec_name}",
            status=404,
            mimetype="text/plain",
        )
    except storage.exceptions.StorageError:
        return server.Response(
            "something went wrong whilst reading the spec",
            status=500,
            mimetype="text/plain",
        )
Esempio n. 10
0
def test_put(monkeypatch, _clean_specs_table):
    """
    GIVEN body, spec id and user
    WHEN put is called with the body, spec id and user
    THEN the spec is stored against the spec id.
    """
    mock_request = mock.MagicMock()
    mock_headers = {"X-LANGUAGE": "JSON"}
    mock_request.headers = mock_headers
    monkeypatch.setattr(server.Request, "request", mock_request)
    version = "1"
    title = "title 1"
    description = "description 1"
    spec = {
        "info": {"version": version, "title": title, "description": description},
        "components": {
            "schemas": {
                "Schema": {
                    "type": "object",
                    "x-tablename": "schema",
                    "properties": {"id": {"type": "integer"}},
                }
            }
        },
    }
    body = json.dumps(spec)
    spec_name = "id 1"
    user = "******"

    response = specs.put(body=body.encode(), spec_name=spec_name, user=user)

    spec_str = storage.get_storage_facade().get_spec(
        user=user, name=spec_name, version=version
    )
    assert f'"{version}"' in spec_str
    assert '"Schema"' in spec_str
    assert '"x-tablename"' in spec_str
    assert '"schema"' in spec_str

    assert package_database.get().count_customer_models(sub=user) == 1
    spec_infos = package_database.get().list_specs(sub=user)
    assert len(spec_infos) == 1
    spec_info = spec_infos[0]
    assert spec_info["name"] == spec_name
    assert spec_info["id"] == spec_name
    assert spec_info["version"] == version
    assert spec_info["title"] == title
    assert spec_info["description"] == description
    assert spec_info["model_count"] == 1
    assert "updated_at" in spec_info

    assert response.status_code == 204
Esempio n. 11
0
def delete(user: types.TUser) -> server.Response:
    """
    Retrieve the credentials for the user.

    Args:
        user: The user from the token.

    Returns:
        The credentials for the user.

    """
    package_database.get().delete_credentials(
        sub=user, id_=config.get().default_credentials_id)
    return server.Response(status=204)
Esempio n. 12
0
def test_credentials_create_list_delete_all(sub):
    """
    GIVEN credentials values
    WHEN credentials are created, listed and all are deleted
    THEN the credentials are returned in the list after creation but not after deletion.
    """
    id_ = "id 1"
    public_key = "public key 1"
    secret_key_hash = b"secret key has 1"
    salt = b"salt 1"

    database_instance = package_database.get()

    assert len(database_instance.list_credentials(sub=sub)) == 0

    database_instance.create_update_credentials(
        sub=sub,
        id_=id_,
        public_key=public_key,
        secret_key_hash=secret_key_hash,
        salt=salt,
    )

    infos = database_instance.list_credentials(sub=sub)
    assert len(infos) == 1
    info = infos[0]
    assert info["id"] == id_
    assert info["public_key"] == public_key
    assert info["salt"] == salt

    database_instance.delete_all_credentials(sub=sub)

    assert len(database_instance.list_credentials(sub=sub)) == 0
Esempio n. 13
0
def test_count_customer_models(_clean_specs_table):
    """
    GIVEN sub, name, version and model count
    WHEN create_update_spec is called with the spec info and count_customer_models is
        called
    THEN the model count is returned.
    """
    sub = "sub 1"
    database_instance = package_database.get()

    assert database_instance.count_customer_models(sub=sub) == 0

    name = "name 1"
    version = "version 1"
    model_count_1 = 1
    database_instance.create_update_spec(
        sub=sub, name=name, version=version, model_count=model_count_1
    )

    assert database_instance.count_customer_models(sub=sub) == model_count_1

    model_count_2 = 2
    database_instance.create_update_spec(
        sub=sub, name=name, version=version, model_count=model_count_2
    )

    assert database_instance.count_customer_models(sub=sub) == model_count_2

    assert database_instance.count_customer_models(sub="sub 2") == 0
Esempio n. 14
0
def test_get_latest_spec_version(_clean_specs_table):
    """
    GIVEN sub, name, version and model count
    WHEN create_update_spec is called with the spec info and get_latest_spec_version is
        called
    THEN the latest version is returned.
    """
    sub = "sub 1"
    name = "name 1"
    database_instance = package_database.get()

    with pytest.raises(package_database.exceptions.BaseError):
        database_instance.get_latest_spec_version(sub=sub, name=name)

    version_1 = "version 1"
    model_count = 1
    database_instance.create_update_spec(
        sub=sub, name=name, version=version_1, model_count=model_count
    )

    assert database_instance.get_latest_spec_version(sub=sub, name=name) == version_1

    version_2 = "version 2"
    database_instance.create_update_spec(
        sub=sub, name=name, version=version_2, model_count=model_count
    )

    assert database_instance.get_latest_spec_version(sub=sub, name=name) == version_2

    with pytest.raises(package_database.exceptions.BaseError):
        database_instance.get_latest_spec_version(sub=sub, name="name 2")

    with pytest.raises(package_database.exceptions.BaseError):
        database_instance.get_latest_spec_version(sub="sub 2", name=name)
Esempio n. 15
0
def test_delete_all(_clean_specs_table, _clean_credentials_table):
    """
    GIVEN database with spec and credentials
    WHEN delete_all is called
    THEN all spec and credentials are deleted.
    """
    sub = "sub 1"

    database_instance = package_database.get()
    database_instance.create_update_credentials(
        sub=sub,
        id_="id 1",
        public_key="public key 1",
        secret_key_hash=b"secret key hash 1",
        salt=b"salt 1",
    )
    database_instance.create_update_spec(
        sub=sub, name="name 1", version="version 1", model_count=1
    )

    assert len(database_instance.list_specs(sub=sub)) == 1
    assert len(database_instance.list_credentials(sub=sub)) == 1

    database_instance.delete_all(sub=sub)

    assert len(database_instance.list_specs(sub=sub)) == 0
    assert len(database_instance.list_credentials(sub=sub)) == 0
Esempio n. 16
0
def test_delete_spec(_clean_specs_table):
    """
    GIVEN sub, name, version and model count
    WHEN create_update_spec is called with the spec info and delete_spec is called
    THEN the spec is deleted.
    """
    sub = "sub 1"
    name = "name 1"
    version = "version 1"
    model_count = 1
    database_instance = package_database.get()
    database_instance.create_update_spec(
        sub=sub, name=name, version=version, model_count=model_count
    )

    assert len(database_instance.list_specs(sub=sub)) == 1
    assert database_instance.count_customer_models(sub=sub) == model_count
    assert database_instance.get_latest_spec_version(sub=sub, name=name) == version

    database_instance.delete_spec(sub=sub, name=name)

    assert len(database_instance.list_specs(sub=sub)) == 0
    assert database_instance.count_customer_models(sub=sub) == 0
    with pytest.raises(package_database.exceptions.NotFoundError):
        database_instance.get_latest_spec_version(sub=sub, name=name)
Esempio n. 17
0
def test_get_spec(_clean_specs_table):
    """
    GIVEN sub, name, version and model count
    WHEN create_update_spec is called with the spec info and get_spec is called
    THEN the spec info is returned.
    """
    sub = "sub 1"
    name = "name 1"
    database_instance = package_database.get()

    with pytest.raises(package_database.exceptions.NotFoundError):
        database_instance.get_spec(sub=sub, name=name)

    version = "version 1"
    model_count = 1
    database_instance.create_update_spec(
        sub=sub, name=name, version=version, model_count=model_count
    )

    returned_info = database_instance.get_spec(sub=sub, name=name)

    assert returned_info["name"] == name
    assert returned_info["id"] == name
    assert returned_info["version"] == version
    assert returned_info["model_count"] == model_count
Esempio n. 18
0
def list_(spec_name: types.TSpecId, user: types.TUser) -> server.Response:
    """
    List all available versions of a spec.

    Args:
        spec_name: The id of the spec.
        user: The user from the token.

    Returns:
        The response to the request.

    """
    try:
        return server.Response(
            json.dumps(package_database.get().list_spec_versions(
                sub=user, name=spec_name)),
            status=200,
            mimetype="application/json",
        )
    except package_database.exceptions.NotFoundError:
        return server.Response(
            f"could not find spec with id {spec_name}",
            status=404,
            mimetype="text/plain",
        )
    except package_database.exceptions.BaseError:
        return server.Response(
            "something went wrong whilst reading from the database",
            status=500,
            mimetype="text/plain",
        )
Esempio n. 19
0
def test_delete_database_error(monkeypatch, _clean_specs_table):
    """
    GIVEN database that raises a DatabaseError and storage with spec and user and spec
        id
    WHEN put is called with the body and spec id
    THEN the spec is deleted from the storage.
    """
    spec_name = "id 1"
    user = "******"
    version = "1"
    mock_database_delete_spec = mock.MagicMock()
    mock_database_delete_spec.side_effect = package_database.exceptions.BaseError
    monkeypatch.setattr(
        package_database.get(),
        "delete_spec",
        mock_database_delete_spec,
    )
    storage.get_storage_facade().create_update_spec(
        user=user, name=spec_name, version=version, spec_str="spec str 1"
    )

    response = specs.delete(spec_name=spec_name, user=user)

    with pytest.raises(storage.exceptions.StorageError):
        storage.get_storage_facade().get_spec(
            user=user, name=spec_name, version=version
        )
    assert response.status_code == 204
Esempio n. 20
0
def test_main_list(_clean_credentials_table, _clean_specs_table):
    """
    GIVEN list event and database with the spec
    WHEN main is called with the event
    THEN a list response is returned.
    """
    secret_key = "secret key 1"
    salt = b"salt 1"
    secret_key_hash = package_security.calculate_secret_key_hash(
        secret_key=secret_key, salt=salt)
    credentials = factory.CredentialsFactory(secret_key_hash=secret_key_hash,
                                             salt=salt)
    credentials.save()
    token = base64.b64encode(
        f"{credentials.public_key}:{secret_key}".encode()).decode()
    authorization_value = f"Basic {token}"
    spec_id = "spec 1"
    version = "version 1"
    uri = f"/{spec_id}/"
    package_database.get().create_update_spec(sub=credentials.sub,
                                              name=spec_id,
                                              version=version,
                                              model_count=1)
    request = {
        "headers": {
            "authorization": [{
                "key": "Authorization",
                "value": authorization_value
            }]
        },
        "uri": uri,
    }
    event = {"Records": [{"cf": {"request": copy.deepcopy(request)}}]}

    returned_response = app.main(event, None)

    assert returned_response["status"] == "200"
    assert returned_response["statusDescription"] == "OK"
    assert returned_response["headers"]["cache-control"][0][
        "value"] == "max-age=0"
    assert returned_response["headers"]["content-type"][0][
        "value"] == "text/html"
    assert spec_id in returned_response["body"]
    assert version in returned_response["body"]
    assert credentials.public_key in returned_response["body"]
    assert secret_key in returned_response["body"]
Esempio n. 21
0
def test_list_miss(_clean_specs_table):
    """
    GIVEN user and database with a single spec for a different user
    WHEN list_ is called with the user
    THEN empty list is returned.
    """
    user = "******"
    spec_name = "spec name 1"
    package_database.get().create_update_spec(
        sub="user 2", name=spec_name, version="1", model_count=1
    )

    response = specs.list_(user=user)

    assert response.status_code == 200
    assert response.mimetype == "application/json"
    assert json.loads(response.data.decode()) == []
Esempio n. 22
0
def test_list_spec_versions(monkeypatch, _clean_specs_table):
    """
    GIVEN sub, name, version and model count
    WHEN create_update_spec is called with the spec info and list_spec_versions is
        called
    THEN all specs for the customer are returned or NotFoundError is raised.
    """
    mock_time = mock.MagicMock()
    monkeypatch.setattr(time, "time", mock_time)
    sub = "sub 1"
    name = "name 1"
    database_instance = package_database.get()

    with pytest.raises(package_database.exceptions.NotFoundError):
        database_instance.list_spec_versions(sub=sub, name=name)

    mock_time.return_value = 1000000
    version_1 = "version 1"
    title = "title 1"
    description = "description 1"
    model_count_1 = 1
    database_instance.create_update_spec(
        sub=sub,
        name=name,
        version=version_1,
        model_count=model_count_1,
        title=title,
        description=description,
    )

    spec_infos = database_instance.list_spec_versions(sub=sub, name=name)
    assert len(spec_infos) == 1
    spec_info = spec_infos[0]
    assert spec_info["name"] == name
    assert spec_info["id"] == name
    assert spec_info["version"] == version_1
    assert spec_info["title"] == title
    assert spec_info["description"] == description
    assert spec_info["model_count"] == model_count_1
    assert "updated_at" in spec_info

    mock_time.return_value = 2000000
    version_2 = "version 2"
    model_count_2 = 2
    database_instance.create_update_spec(
        sub=sub, name=name, version=version_2, model_count=model_count_2
    )

    spec_infos = database_instance.list_spec_versions(sub=sub, name=name)
    assert len(spec_infos) == 2
    assert spec_infos[0]["name"] == name
    assert spec_infos[0]["id"] == name
    spec_info = spec_infos[1]
    assert spec_info["name"] == name
    assert spec_info["id"] == name
    assert spec_info["version"] == version_2
    assert spec_info["model_count"] == model_count_2
    assert "updated_at" in spec_info
Esempio n. 23
0
def test_list_delete_all_spec(_clean_specs_table):
    """
    GIVEN sub, name, version and model count
    WHEN create_update_spec is called with the spec info and list_specs is called
    THEN all specs for the customer are returned.
    """
    sub = "sub 1"
    database_instance = package_database.get()

    assert database_instance.list_specs(sub=sub) == []

    name_1 = "name 1"
    version_1 = "version 1"
    title = "title 1"
    description = "description 1"
    model_count_1 = 1
    database_instance.create_update_spec(
        sub=sub,
        name=name_1,
        version=version_1,
        model_count=model_count_1,
        title=title,
        description=description,
    )

    spec_infos = database_instance.list_specs(sub=sub)
    assert len(spec_infos) == 1
    spec_info = spec_infos[0]
    assert spec_info["name"] == name_1
    assert spec_info["id"] == name_1
    assert spec_info["version"] == version_1
    assert spec_info["title"] == title
    assert spec_info["description"] == description
    assert spec_info["model_count"] == model_count_1
    assert "updated_at" in spec_info

    name_2 = "name 2"
    version_2 = "version 2"
    model_count_2 = 2
    database_instance.create_update_spec(
        sub=sub, name=name_2, version=version_2, model_count=model_count_2
    )

    spec_infos = database_instance.list_specs(sub=sub)
    assert len(spec_infos) == 2
    assert spec_infos[0]["name"] == name_1
    assert spec_infos[0]["id"] == name_1
    spec_info = spec_infos[1]
    assert spec_info["name"] == name_2
    assert spec_info["id"] == name_2
    assert spec_info["version"] == version_2
    assert spec_info["model_count"] == model_count_2
    assert "updated_at" in spec_info

    database_instance.delete_all_specs(sub=sub)

    assert database_instance.list_specs(sub=sub) == []
Esempio n. 24
0
def check_within_limit(
    *, user: types.TUser, spec_name: types.TSpecName, model_count: types.TSpecModelCount
) -> types.TResult:
    """
    Check whether adding a spec would exceed the free tier limit.

    Algorithm:
        1. retrieve the information for the spec,
        2. retrieve the model count for the user and
        3. return whether the user model count plus the new model count minus the
            existing model count would exceed the free tier.

    Args:
        user: The user to run the check for
        spec_name: The name of the spec
        model_count: The new model count of the spec

    Returns:
        The result and the reason if the result is true.

    """
    current_spec_model_count = 0
    try:
        spec_info = package_database.get().get_spec(sub=user, name=spec_name)
        current_spec_model_count = spec_info["model_count"]
    except package_database.exceptions.BaseError:
        pass
    user_model_count = package_database.get().count_customer_models(sub=user)

    new_user_model_count = user_model_count + model_count - current_spec_model_count

    result = new_user_model_count <= config.get().free_tier_model_count
    reason: typing.Optional[str] = None
    if not result:
        reason = (
            "with this spec the maximum number of "
            f"{config.get().free_tier_model_count} models for the free "
            f"tier would be exceeded, current models count: {user_model_count}, "
            f"current models in the spec: {current_spec_model_count}, "
            f"models in the new version of th spec: {model_count}, "
            f"new total model count: {new_user_model_count}, "
        )

    return types.TResult(value=result, reason=reason)
Esempio n. 25
0
def test_get_storage_facade_miss(_clean_specs_table):
    """
    GIVEN user and database with a spec but empty storage
    WHEN get is called with the user and spec id
    THEN a 404 is returned.
    """
    user = "******"
    spec_name = "spec name 1"
    version = "1"
    package_database.get().create_update_spec(
        sub=user, name=spec_name, version=version, model_count=1
    )

    response = specs.get(user=user, spec_name=spec_name)

    assert response.status_code == 404
    assert response.mimetype == "text/plain"
    assert spec_name in response.data.decode()
    assert "not find" in response.data.decode()
Esempio n. 26
0
def get(user: types.TUser) -> server.Response:
    """
    Retrieve the credentials for the user.

    Args:
        user: The user from the token.

    Returns:
        The credentials for the user.

    """
    public_key: str
    secret_key: str
    id_ = config.get().default_credentials_id

    # Retrieve or create credentials
    stored_credentials = package_database.get().get_credentials(sub=user,
                                                                id_=id_)
    if stored_credentials is not None:
        public_key = stored_credentials["public_key"]
        secret_key = package_security.retrieve_secret_key(
            sub=user, salt=stored_credentials["salt"])
    else:
        created_credentials = package_security.create(sub=user)
        public_key = created_credentials.public_key
        secret_key = created_credentials.secret_key
        package_database.get().create_update_credentials(
            sub=user,
            id_=id_,
            public_key=public_key,
            secret_key_hash=created_credentials.secret_key_hash,
            salt=created_credentials.salt,
        )

    return server.Response(
        json.dumps({
            "public_key": public_key,
            "secret_key": secret_key,
        }),
        status=200,
        mimetype="application/json",
    )
Esempio n. 27
0
def create_list_response_value(
    *,
    authorization: types.TAuthorization,
    uri: types.TUri,
    auth_info: types.CredentialsAuthInfo,
) -> types.TResponseValue:
    """
    Calculate the response for a list type response.

    Raises NotFoundError when the uri is not linked to a known spec.

    Args:
        uri: The requested uri.
        auth_info: Information about the user.

    Returns:
        The html to return to the user for the request.

    """
    assert uri.startswith("/")
    assert uri.endswith("/")
    spec_id = uri[1:-1]

    try:
        version_infos = package_database.get().list_spec_versions(
            sub=auth_info.sub, name=spec_id
        )
    except package_database.exceptions.NotFoundError as exc:
        raise exceptions.NotFoundError(
            f"could not find package with {spec_id=}"
        ) from exc

    host = "index.package.openalchemy.io"

    def package_name(version: str) -> str:
        """Calculate the name of the package."""
        return f"{spec_id.replace('-', '_')}-{version}.tar.gz"

    install_links = list(
        map(
            lambda version_info: (
                f'<a href="https://'
                f"{authorization.public_key}:{authorization.secret_key}"
                f"@{host}/{spec_id}/"
                f'{package_name(version_info["version"])}">'
                f'{package_name(version_info["version"])}</a><br>'
            ),
            version_infos,
        )
    )
    joined_install_links = "\n".join(install_links)

    return f"""
Esempio n. 28
0
def test_get_storage_facade_error(_clean_specs_table, monkeypatch):
    """
    GIVEN user and database with a spec but storage that raises an error
    WHEN get is called with the user and spec id
    THEN a 500 is returned.
    """
    user = "******"
    spec_name = "spec name 1"
    version = "1"
    package_database.get().create_update_spec(
        sub=user, name=spec_name, version=version, model_count=1
    )
    mock_storage_get_spec = mock.MagicMock()
    mock_storage_get_spec.side_effect = storage.exceptions.StorageError
    monkeypatch.setattr(storage.get_storage_facade(), "get_spec", mock_storage_get_spec)

    response = specs.get(user=user, spec_name=spec_name)

    assert response.status_code == 500
    assert response.mimetype == "text/plain"
    assert "reading" in response.data.decode()
Esempio n. 29
0
def delete(spec_name: types.TSpecId, user: types.TUser) -> server.Response:
    """
    Delete a spec for a user.

    Args:
        spec_name: The id of the spec.
        user: The user from the token.

    Returns:
        The response to the request.

    """
    try:
        package_database.get().delete_spec(sub=user, name=spec_name)
    except package_database.exceptions.BaseError:
        pass
    try:
        storage.get_storage_facade().delete_spec(user=user, name=spec_name)
    except storage.exceptions.StorageError:
        pass

    return server.Response(status=204)
Esempio n. 30
0
def test_spec_create_count_models_get_latest_version_list_versions_delete(sub):
    """
    GIVEN spec values
    WHEN the models are counted, the latest version is retrieved, versions are listed
        and deleted
    THEN the model count for the spec is returned, the version of the spec is returned,
        the version of the spec is listed after creation but not after deletion.
    """
    name = "name 1"
    model_count = 1
    version = "version 1"

    database_instance = package_database.get()

    assert len(database_instance.list_specs(sub=sub)) == 0

    database_instance.create_update_spec(sub=sub,
                                         name=name,
                                         model_count=model_count,
                                         version=version)

    assert database_instance.count_customer_models(sub=sub) == model_count

    info = database_instance.get_spec(sub=sub, name=name)

    assert info["name"] == name
    assert info["id"] == name
    assert info["version"] == version
    assert info["model_count"] == model_count

    assert database_instance.get_latest_spec_version(sub=sub,
                                                     name=name) == version

    infos = database_instance.list_spec_versions(sub=sub, name=name)
    assert len(infos) == 1
    info = infos[0]
    assert info["name"] == name
    assert info["id"] == name
    assert info["model_count"] == model_count
    assert info["version"] == version

    database_instance.delete_spec(sub=sub, name=name)

    assert database_instance.count_customer_models(sub=sub) == 0

    with pytest.raises(package_database.exceptions.NotFoundError):
        database_instance.get_latest_spec_version(sub=sub, name=name)

    with pytest.raises(package_database.exceptions.NotFoundError):
        database_instance.list_spec_versions(sub=sub, name=name)