diff --git a/conda-store-server/tests/user_journeys/test_data/simple_environment2.yaml b/conda-store-server/tests/user_journeys/test_data/simple_environment2.yaml new file mode 100644 index 000000000..2af46c1fb --- /dev/null +++ b/conda-store-server/tests/user_journeys/test_data/simple_environment2.yaml @@ -0,0 +1,7 @@ +name: simple-test-environment +channels: + - conda-forge +dependencies: + - python ==3.10 + - fastapi + - numpy diff --git a/conda-store-server/tests/user_journeys/test_user_journeys.py b/conda-store-server/tests/user_journeys/test_user_journeys.py index 7ccc24ba9..78f3664a5 100644 --- a/conda-store-server/tests/user_journeys/test_user_journeys.py +++ b/conda-store-server/tests/user_journeys/test_user_journeys.py @@ -104,29 +104,54 @@ def test_user_login_and_create_shared_environment( @pytest.mark.user_journey -def test_admin_delete_environment(base_url: str): +def test_admin_set_active_build(base_url: str): """Test that an admin can delete environments.""" - specs = ["tests/user_journeys/test_data/simple_environment.yaml"] + specs = [ + "tests/user_journeys/test_data/simple_environment.yaml", + "tests/user_journeys/test_data/simple_environment2.yaml", + ] api = utils.API(base_url=base_url) - - # Create a shared namespace; default permissions for namepace/environment - # */* is admin namespace = api.create_namespace().json()["data"]["name"] - - envs = [] + envs = set() for spec in specs: - envs.append( + envs.add( api.create_environment(namespace, spec).json()["data"]["specification"][ "name" ] ) - assert len(api.list_environments(namespace).json()["data"]) == len(specs) + environment = list(envs)[0] + builds = api.get_builds( + namespace=namespace, + environment=environment, + ) + + # The environment in the two specs has the same name, so there should be + # two builds for this environment in this namespace + assert len(builds) == 2 + + build_ids = [build["id"] for build in builds] + + assert api.get_environment( + namespace=namespace, + environment=environment, + )[ + "current_build_id" + ] == max(build_ids) + + api.set_active_build( + namespace=namespace, environment=environment, build_id=min(build_ids) + ) + + assert api.get_environment( + namespace=namespace, + environment=environment, + )[ + "current_build_id" + ] == min(build_ids) for env in envs: api.delete_environment(namespace, env) - - assert len(api.list_environments(namespace).json()["data"]) == 0 api.delete_namespace(namespace) @@ -145,3 +170,8 @@ def test_failed_build_logs(base_url: str): "invalidpackagenamefaasdfagksdjfhgaskdf" in api.get_logs(build_request["data"]["id"]).text ) + + api.delete_environment( + namespace, + build_request["data"]["specification"]["name"], + ) diff --git a/conda-store-server/tests/user_journeys/utils/api_utils.py b/conda-store-server/tests/user_journeys/utils/api_utils.py index 6b7572d38..38c35a4a7 100644 --- a/conda-store-server/tests/user_journeys/utils/api_utils.py +++ b/conda-store-server/tests/user_journeys/utils/api_utils.py @@ -4,7 +4,7 @@ import uuid from enum import Enum -from typing import Union +from typing import Any, Optional, Union import requests import utils.time_utils as time_utils @@ -205,22 +205,25 @@ def delete_environment( f"api/v1/environment/{namespace}/{environment_name}", method="DELETE" ) - def list_environments(self, namespace: str) -> requests.Response: + def list_environments(self, namespace: Optional[str] = None): """List the environments in the given namespace. Parameters ---------- - namespace : str - Name of the namespace for which environments are to be retrieved + namespace : Optional[str] + Name of the namespace for which environments are to be retrieved. + If None, all environments are retrieved. Returns ------- requests.Response Response from the server containing the list of environments """ - return self._make_request( - f"api/v1/environment/?namespace={namespace}", method="GET" - ) + if namespace: + return self._make_request( + f"api/v1/environment/?namespace={namespace}", method="GET" + ) + return self._make_request("api/v1/environment/", method="GET") def delete_namespace(self, namespace: str) -> requests.Response: """Delete a namespace.""" @@ -230,3 +233,79 @@ def delete_namespace(self, namespace: str) -> requests.Response: def gen_random_namespace() -> str: """Generate a random namespace.""" return uuid.uuid4().hex + + def set_active_build( + self, namespace: str, environment: str, build_id: int + ) -> requests.Response: + """Set the active build for a given environment. + + Parameters + ---------- + namespace : str + Name of the namespace in which the environment lives + environment : str + Environment to set the build for + build_id : int + ID of the build to be activated for the given environment + + Returns + ------- + requests.Response + Response from the conda-store server. + """ + return self._make_request( + f"api/v1/environment/{namespace}/{environment}", + method="PUT", + json_data={"build_id": build_id}, + ) + + def get_builds( + self, + environment: Optional[str] = None, + namespace: Optional[str] = None, + ) -> dict[str, Any]: + """Get information about an environment. + + Parameters + ---------- + namespace : Optional[str] + Name of a namespace + environment : Optional[str] + Name of an environment + + Returns + ------- + dict[str, Any] + Dict of build properties; see API docs for + api/v1/build/ for more information. + """ + query_params = [] + if environment: + query_params.append(f"name={environment}") + + if namespace: + query_params.append(f"namespace={namespace}") + + return self._make_request(f'api/v1/build/?{"&".join(query_params)}').json()[ + "data" + ] + + def get_environment(self, namespace: str, environment: str) -> dict[str, Any]: + """Get information about an environment. + + Parameters + ---------- + namespace : str + Name of the namespace in which the environment lives + environment : str + Name of the environment + + Returns + ------- + dict[str, Any] + Dict of environment properties; see API docs for + api/v1/environment/{namespace}/{environment}/ for more information. + """ + return self._make_request( + f"api/v1/environment/{namespace}/{environment}/" + ).json()["data"]