Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a cog integration test for apt-packages #2104

Merged
merged 11 commits into from
Jan 13, 2025
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ install: $(COG_BINARIES)

.PHONY: clean
clean:
rm -rf build dist pkg/dockerfile/embed
rm -rf .tox build dist pkg/dockerfile/embed
rm -f $(COG_BINARIES)

.PHONY: test-go
Expand Down
18 changes: 9 additions & 9 deletions python/cog/server/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,22 +355,22 @@ def wait(self, timeout: Optional[float] = None) -> None:
self._fut.result(timeout=timeout)

def set_output_type(self, *, multi: bool) -> None:
assert (
self._output_type_multi is None
), "Predictor unexpectedly returned multiple output types"
assert (
self._p.output is None
), "Predictor unexpectedly returned output type after output"
assert self._output_type_multi is None, (
"Predictor unexpectedly returned multiple output types"
)
assert self._p.output is None, (
"Predictor unexpectedly returned output type after output"
)

if multi:
self._p.output = []

self._output_type_multi = multi

def append_output(self, output: Any) -> None:
assert (
self._output_type_multi is not None
), "Predictor unexpectedly returned output before output type"
assert self._output_type_multi is not None, (
"Predictor unexpectedly returned output before output type"
)

uploaded_output = self._upload_files(output)
if self._output_type_multi:
Expand Down
24 changes: 12 additions & 12 deletions python/tests/server/test_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,21 +134,21 @@
),
(
WorkerConfig("logging_async", setup=False, min_python=(3, 11), is_async=True),
("writing to stdout at import time\n" "setting up predictor\n"),
("writing to stdout at import time\nsetting up predictor\n"),
8W9aG marked this conversation as resolved.
Show resolved Hide resolved
"writing to stderr at import time\n",
),
]

PREDICT_LOGS_FIXTURES = [
(
WorkerConfig("logging"),
("writing from C\n" "writing with print\n"),
("WARNING:root:writing log message\n" "writing to stderr\n"),
("writing from C\nwriting with print\n"),
8W9aG marked this conversation as resolved.
Show resolved Hide resolved
("WARNING:root:writing log message\nwriting to stderr\n"),
8W9aG marked this conversation as resolved.
Show resolved Hide resolved
),
(
WorkerConfig("logging_async", min_python=(3, 11), is_async=True),
("writing with print\n"),
8W9aG marked this conversation as resolved.
Show resolved Hide resolved
("WARNING:root:writing log message\n" "writing to stderr\n"),
("WARNING:root:writing log message\nwriting to stderr\n"),
8W9aG marked this conversation as resolved.
Show resolved Hide resolved
),
]

Expand Down Expand Up @@ -214,14 +214,14 @@ def handle_event(self, event: _PublicEventType):
if self.output_type.multi:
self.output.append(event.payload)
else:
assert (
self.output is None
), "Should not get multiple outputs for output type single"
assert self.output is None, (
"Should not get multiple outputs for output type single"
)
self.output = event.payload
elif isinstance(event, PredictionOutputType):
assert (
self.output_type is None
), "Should not get multiple output type events"
assert self.output_type is None, (
"Should not get multiple output type events"
)
self.output_type = event
if self.output_type.multi:
self.output = []
Expand Down Expand Up @@ -863,7 +863,7 @@ def simulate_predict_success(self, state: PredictState):
events.append(PredictionOutputType(multi=True))
for i in range(steps):
events.append(
PredictionOutput(payload=f"NAME={name},STEP={i+1}"),
PredictionOutput(payload=f"NAME={name},STEP={i + 1}"),
)

events.append(Done(canceled=state.canceled))
Expand Down Expand Up @@ -909,7 +909,7 @@ def await_predict(self, state: PredictState):
assert state.result.output == f"NAME={name}"
else:
assert state.result.output == [
f"NAME={name},STEP={i+1}" for i in range(steps)
f"NAME={name},STEP={i + 1}" for i in range(steps)
]

assert state.result.done == Done()
Expand Down
90 changes: 45 additions & 45 deletions python/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ def test_predictor_predict_ref_env_var():
config = Config()
config_predict_ref = config.predictor_predict_ref
del os.environ[COG_PREDICT_TYPE_STUB_ENV_VAR]
assert (
config_predict_ref == predict_ref
), "Predict Reference should come from the environment variable."
assert config_predict_ref == predict_ref, (
"Predict Reference should come from the environment variable."
)


def test_predictor_predict_ref_no_env_var():
Expand All @@ -40,9 +40,9 @@ def test_predictor_predict_ref_no_env_var():
""")
config = Config()
config_predict_ref = config.predictor_predict_ref
assert (
config_predict_ref == "predict.py:Predictor"
), "Predict Reference should come from the cog config file."
assert config_predict_ref == "predict.py:Predictor", (
"Predict Reference should come from the cog config file."
)
os.chdir(pwd)


Expand All @@ -59,9 +59,9 @@ def test_config_initial_values():
del os.environ[COG_PREDICT_TYPE_STUB_ENV_VAR]
config = Config(config={"predict": "predict.py:Predictor"})
config_predict_ref = config.predictor_predict_ref
assert (
config_predict_ref == "predict.py:Predictor"
), "Predict Reference should come from the initial config dictionary."
assert config_predict_ref == "predict.py:Predictor", (
"Predict Reference should come from the initial config dictionary."
)


def test_predictor_train_ref_env_var():
Expand All @@ -70,9 +70,9 @@ def test_predictor_train_ref_env_var():
config = Config()
config_train_ref = config.predictor_train_ref
del os.environ[COG_TRAIN_TYPE_STUB_ENV_VAR]
assert (
config_train_ref == train_ref
), "Train Reference should come from the environment variable."
assert config_train_ref == train_ref, (
"Train Reference should come from the environment variable."
)


def test_predictor_train_ref_no_env_var():
Expand All @@ -81,9 +81,9 @@ def test_predictor_train_ref_no_env_var():
del os.environ[COG_TRAIN_TYPE_STUB_ENV_VAR]
config = Config(config={"train": train_ref})
config_train_ref = config.predictor_train_ref
assert (
config_train_ref == train_ref
), "Train Reference should come from the initial config dictionary."
assert config_train_ref == train_ref, (
"Train Reference should come from the initial config dictionary."
)


def test_requires_gpu_env_var():
Expand All @@ -100,27 +100,27 @@ def test_requires_gpu_no_env_var():
del os.environ[COG_GPU_ENV_VAR]
config = Config(config={"build": {"gpu": False}})
config_gpu = config.requires_gpu
assert (
not config_gpu
), "Requires GPU should come from the initial config dictionary."
assert not config_gpu, (
"Requires GPU should come from the initial config dictionary."
)


def test_get_predictor_ref_predict():
train_ref = "predict.py:Predictor"
config = Config(config={"train": train_ref})
config_train_ref = config.get_predictor_ref(Mode.TRAIN)
assert (
train_ref == config_train_ref
), "The train ref should equal the config train ref."
assert train_ref == config_train_ref, (
"The train ref should equal the config train ref."
)


def test_get_predictor_ref_train():
predict_ref = "predict.py:Predictor"
config = Config(config={"predict": predict_ref})
config_predict_ref = config.get_predictor_ref(Mode.PREDICT)
assert (
predict_ref == config_predict_ref
), "The predict ref should equal the config predict ref."
assert predict_ref == config_predict_ref, (
"The predict ref should equal the config predict ref."
)


def test_get_predictor_types_with_env_var():
Expand All @@ -144,9 +144,9 @@ def predict(self, msg: str) -> ModelOutput:
input_type, output_type, is_async = config.get_predictor_types(Mode.PREDICT)
del os.environ[COG_PREDICT_CODE_STRIP_ENV_VAR]
del os.environ[COG_PREDICT_TYPE_STUB_ENV_VAR]
assert (
str(input_type) == "<class 'cog.predictor.Input'>"
), "Predict input type should be the predictor Input."
assert str(input_type) == "<class 'cog.predictor.Input'>", (
"Predict input type should be the predictor Input."
)
assert (
str(output_type) == "<class 'cog.predictor.get_output_type.<locals>.Output'>"
), "Predict output type should be the predictor Output."
Expand Down Expand Up @@ -179,9 +179,9 @@ def predict(self, msg: str) -> ModelOutput:
predict_ref = f"{predict_python_file}:Predictor"
config = Config(config={"predict": predict_ref})
input_type, output_type, is_async = config.get_predictor_types(Mode.PREDICT)
assert (
str(input_type) == "<class 'cog.predictor.Input'>"
), "Predict input type should be the predictor Input."
assert str(input_type) == "<class 'cog.predictor.Input'>", (
"Predict input type should be the predictor Input."
)
assert (
str(output_type)
== "<class 'cog.predictor.get_output_type.<locals>.Output'>"
Expand Down Expand Up @@ -215,9 +215,9 @@ async def predict(self, msg: str) -> ModelOutput:
predict_ref = f"{predict_python_file}:Predictor"
config = Config(config={"predict": predict_ref})
input_type, output_type, is_async = config.get_predictor_types(Mode.PREDICT)
assert (
str(input_type) == "<class 'cog.predictor.Input'>"
), "Predict input type should be the predictor Input."
assert str(input_type) == "<class 'cog.predictor.Input'>", (
"Predict input type should be the predictor Input."
)
assert (
str(output_type)
== "<class 'cog.predictor.get_output_type.<locals>.Output'>"
Expand Down Expand Up @@ -249,12 +249,12 @@ def train(
train_ref = f"{predict_python_file}:train"
config = Config(config={"train": train_ref})
input_type, output_type, is_async = config.get_predictor_types(Mode.TRAIN)
assert (
str(input_type) == "<class 'cog.predictor.TrainingInput'>"
), "Predict input type should be the training Input."
assert str(output_type).endswith(
"TrainingOutput'>"
), "Predict output type should be the training Output."
assert str(input_type) == "<class 'cog.predictor.TrainingInput'>", (
"Predict input type should be the training Input."
)
assert str(output_type).endswith("TrainingOutput'>"), (
"Predict output type should be the training Output."
)
assert not is_async, "is_async should be False for normal functions"


Expand Down Expand Up @@ -282,10 +282,10 @@ async def train(
train_ref = f"{predict_python_file}:train"
config = Config(config={"train": train_ref})
input_type, output_type, is_async = config.get_predictor_types(Mode.TRAIN)
assert (
str(input_type) == "<class 'cog.predictor.TrainingInput'>"
), "Predict input type should be the training Input."
assert str(output_type).endswith(
"TrainingOutput'>"
), "Predict output type should be the training Output."
assert str(input_type) == "<class 'cog.predictor.TrainingInput'>", (
"Predict input type should be the training Input."
)
assert str(output_type).endswith("TrainingOutput'>"), (
"Predict output type should be the training Output."
)
assert is_async, "is_async should be True for async functions"
18 changes: 9 additions & 9 deletions python/tests/test_wait.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,19 @@ def test_wait_for_env_no_env_vars():
if COG_EAGER_IMPORTS_ENV_VAR in os.environ:
del os.environ[COG_EAGER_IMPORTS_ENV_VAR]
result = wait_for_env()
assert (
result
), "We should return true if we have no env vars associated with the wait."
assert result, (
"We should return true if we have no env vars associated with the wait."
)


def test_wait_for_env():
with tempfile.NamedTemporaryFile() as tmpfile:
os.environ[COG_WAIT_FILE_ENV_VAR] = tmpfile.name
os.environ[COG_EAGER_IMPORTS_ENV_VAR] = "pytest,pathlib,time"
result = wait_for_env()
assert (
result
), "We should return true if we have waited for the right environment."
assert result, (
"We should return true if we have waited for the right environment."
)
del os.environ[COG_EAGER_IMPORTS_ENV_VAR]
del os.environ[COG_WAIT_FILE_ENV_VAR]

Expand Down Expand Up @@ -118,6 +118,6 @@ def test_wait_inserts_pythonpath():
expected_path = ":".join(
original_sys_path + [pyenv_path + "/lib/python3.11/site-packages"]
)
assert (
expected_path == current_python_path
), "Our python path should be updated with the pyenv path."
assert expected_path == current_python_path, (
"Our python path should be updated with the pyenv path."
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
build:
gpu: true
python_version: "3.9"
system_packages:
- "git"
run:
- command: git --version
predict: "predict.py:Predictor"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from cog import BasePredictor


class Predictor(BasePredictor):
def predict(self, s: str) -> str:
return "hello " + s
17 changes: 17 additions & 0 deletions test-integration/test_integration/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,20 @@ def test_pip_freeze(docker_image):
pip_freeze
== "anyio==4.4.0\nattrs==23.2.0\ncertifi==2024.8.30\ncharset-normalizer==3.3.2\nclick==8.1.7\nexceptiongroup==1.2.2\nfastapi==0.98.0\nh11==0.14.0\nhttptools==0.6.1\nidna==3.8\npydantic==1.10.18\npython-dotenv==1.0.1\nPyYAML==6.0.2\nrequests==2.32.3\nsniffio==1.3.1\nstarlette==0.27.0\nstructlog==24.4.0\ntyping_extensions==4.12.2\nurllib3==2.2.2\nuvicorn==0.30.6\nuvloop==0.20.0\nwatchfiles==0.24.0\nwebsockets==13.0.1\n"
)


def test_cog_installs_apt_packages(docker_image):
project_dir = Path(__file__).parent / "fixtures/apt-packages"
build_process = subprocess.run(
[
"cog",
"build",
"-t",
docker_image,
],
cwd=project_dir,
capture_output=True,
)
# Test that the build completes successfully.
# If the apt-packages weren't installed the run command would fail.
assert build_process.returncode == 0
8W9aG marked this conversation as resolved.
Show resolved Hide resolved
Loading