Skip to content

Commit 9518b20

Browse files
authored
[SHIP-535] test needed ensure deployments cannot leak (#471)
Tests the requirements isolation of concurrent deployments.
1 parent 3c572d6 commit 9518b20

3 files changed

Lines changed: 97 additions & 3 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from steamship.invocable import PackageService, get
2+
3+
4+
class RequirementIsolationPackage(PackageService):
5+
"""This package is specially designed to allow testing of requirements installation isolation. It should NOT be
6+
used as a template for any development."""
7+
8+
@get("try_pillow")
9+
def try_pillow(self) -> str:
10+
import PIL
11+
12+
return PIL.__name__
13+
14+
@get("try_pandas")
15+
def try_pandas(self) -> str:
16+
import pandas
17+
18+
return pandas.__name__
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import json
2+
from typing import List
3+
4+
import pytest
5+
from steamship_tests import TEST_ASSETS_PATH
6+
from steamship_tests.utils.deployables import zip_deployable
7+
8+
from steamship import Package, PackageInstance, PackageVersion, Steamship, SteamshipError
9+
from steamship.data.package.package_version import CreatePackageVersionRequest
10+
from steamship.utils.url import Verb
11+
12+
13+
@pytest.mark.usefixtures("client")
14+
def test_install_two_packages_at_once(client: Steamship):
15+
16+
pillow_version_task = create_version(client, additional_requirements=["pillow"])
17+
pandas_version_task = create_version(client, additional_requirements=["pandas"])
18+
19+
pillow_version = pillow_version_task.wait()
20+
pandas_version = pandas_version_task.wait()
21+
22+
pillow_instance = PackageInstance.create(
23+
client, package_id=pillow_version.package_id, package_version_id=pillow_version.id
24+
)
25+
pandas_instance = PackageInstance.create(
26+
client, package_id=pandas_version.package_id, package_version_id=pandas_version.id
27+
)
28+
29+
# Pillow version should be able to run the method that imports pillow locally
30+
assert pillow_instance.invoke("try_pillow", verb=Verb.GET) == "PIL"
31+
32+
# Pillow version should NOT be able to run the method that imports pandas locally
33+
with pytest.raises(SteamshipError):
34+
_ = pillow_instance.invoke("try_pandas", verb=Verb.GET)
35+
36+
# Pandas version should be able to run the method that imports pandas locally
37+
assert pandas_instance.invoke("try_pandas", verb=Verb.GET) == "pandas"
38+
39+
# Pandas version should NOT be able to run the method that imports pillow locally
40+
with pytest.raises(SteamshipError):
41+
_ = pandas_instance.invoke("try_pillow", verb=Verb.GET)
42+
43+
pillow_version.delete()
44+
pandas_version.delete()
45+
46+
47+
def create_version(client: Steamship, additional_requirements: List[str]):
48+
"""Separate implementation of create version so that we can not wait on the task, and run multiple at once."""
49+
package = Package.create(client)
50+
51+
zip_bytes = zip_deployable(
52+
TEST_ASSETS_PATH / "packages" / "requirement_isolation_package.py",
53+
additional_requirements=additional_requirements,
54+
)
55+
hosting_handler = "steamship.invocable.entrypoint.safe_handler"
56+
57+
req = CreatePackageVersionRequest(
58+
handle="handle",
59+
package_id=package.id,
60+
config_template=json.dumps({}),
61+
hosting_handler=hosting_handler,
62+
)
63+
64+
task = client.post(
65+
"package/version/create",
66+
payload=req,
67+
file=("package.zip", zip_bytes, "multipart/form-data"),
68+
expect=PackageVersion,
69+
)
70+
return task

tests/steamship_tests/utils/deployables.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import os
44
import zipfile
55
from pathlib import Path
6-
from typing import Any, Dict, Optional
6+
from typing import Any, Dict, List, Optional
77

88
from steamship_tests import ROOT_PATH, SRC_PATH, TEST_ASSETS_PATH
99

@@ -14,7 +14,7 @@
1414
from steamship.data.user import User
1515

1616

17-
def zip_deployable(file_path: Path) -> bytes:
17+
def zip_deployable(file_path: Path, additional_requirements: Optional[List[str]] = None) -> bytes:
1818
"""Prepare and zip a Steamship plugin."""
1919

2020
package_paths = [
@@ -33,7 +33,13 @@ def zip_deployable(file_path: Path) -> bytes:
3333
for file in files:
3434
pypi_file = Path(root) / file
3535
zip_file.write(pypi_file, pypi_file.relative_to(package_path.parent))
36-
zip_file.write(ROOT_PATH / "requirements.txt", "requirements.txt")
36+
if additional_requirements is None:
37+
zip_file.write(ROOT_PATH / "requirements.txt", "requirements.txt")
38+
else:
39+
with open(ROOT_PATH / "requirements.txt", "r") as file:
40+
requirements_string = file.read()
41+
requirements_string += "\n" + "\n".join(additional_requirements)
42+
zip_file.writestr("requirements.txt", requirements_string)
3743

3844
# Now we'll copy in the whole assets directory so that our test files can access things there..
3945
for root, _, files in os.walk(TEST_ASSETS_PATH):

0 commit comments

Comments
 (0)