#generate python dagger sdk from within Dagger functions?
1 messages · Page 1 of 1 (latest)
Hi. Would this function receive an arbitrary module as input? Or is it just testing the Dagger functions next to it?
It's just testing the Dagger functions next to it
Same module or a dedicated "test" sub-module?
Same module
With a sub-module you'll be able to use your functions from dag like an external module would. Won't that be closer to what you want to test?
Basically the code looks like this:
@function
def uv_container(self) -> dagger.Container:
"""Base container with uv installed for caching"""
return (
dag.container()
.from_('python:3.12-slim')
.with_exec(['apt-get', 'update'])
.with_exec(['apt-get', 'install', '-y', 'curl'])
.with_exec(['bash', '-c', 'curl -LsSf https://astral.sh/uv/install.sh | sh'])
.with_env_variable('PATH', '/root/.local/bin:$PATH')
.with_mounted_cache('/root/.cache/uv', dag.cache_volume('uv-cache'))
.with_exec(['uv', 'tool', 'install', 'ruff'])
)
@function
async def test_dagger(self, repo_root: dagger.Directory, dagger_sdk: dagger.Directory | None = None) -> str:
"""Run pytest for .dagger package"""
return await (
self.uv_container()
.with_mounted_directory('/workspace', repo_root)
.with_workdir('/workspace/.dagger')
.with_exec(['uv', 'run', 'pytest'])
.stdout()
)
What do the pytest test functions look like?
Usually they are just simple unit tests. So in theory I can move the logic to standalone library. But it'll add more complexity.
Just curious how your pytest functions are testing the dagger functions, and instantiating their parent objects.
It would be fun to have a possibility to call Dagger from within Dagger so we can write integration tests.
But it's beginning to look scary
I don't intend to test Dagger objects with unit tests (but now I'm a little interested. Maybe I will try some mocks)
You can, I'm just gathering the full context of what you're trying to do before I make my suggestion.
I can show examples a little later.
I'm from my phone at the moment.
Yeah, that would be great. You can do unit tests and integration tests. Easiest way to do integration tests is by creating a sub Dagger module specifically for testing. That is described in general terms in #1403159511182872637 message.
You can see an example of this in our repo, specifically using pytest to do integration tests on a Dagger module's functions: https://github.com/dagger/dagger/blob/2cee53d1d3e19fa5203b7dd91c9468d45ae04886/core/integration/testdata/modules/python/ifaces/.dagger/src/caller/test_main.py
The way that works is by calling "pytest" as subprocess in a function: https://github.com/dagger/dagger/blob/2cee53d1d3e19fa5203b7dd91c9468d45ae04886/core/integration/testdata/modules/python/ifaces/.dagger/src/caller/main.py#L12-L16
No need to create a container and mount the repo and sdk since this works off of the generated client bindings that are generated already for a module's dependencies.
Similarly for unit tests in the main module, you can also just subprocess it since the module already runs in an ephemeral Python container with uv and your source code.
Note that the need for a sub-module to run integration tests will soon not be necessary because of https://github.com/dagger/dagger/pull/10584, which will allow calling functions from a Dagger module through dag, without having to go through a dependency. This feature will start out as experimental, but until it's production ready the sub-module route is the current best practice.
Note also that running "pytest" doesn't need to be through subprocess. You can call it programmatically with pytest.main() but you'll need a bit more boilerplate.
Some simple unit tests:
import pytest
def test_original_repo_path(self, test_workdir):
"""Test original repository path method."""
orig_path = test_workdir.original_repo_path()
assert orig_path.name == "original-repo"
assert orig_path.parent == test_workdir.base_path
assert orig_path.exists()
assert orig_path.is_dir()
Nothing crazy.
Integration test example:
"""Integration tests for main.py Dagger functions using real Dagger CLI."""
import pytest
from pathlib import Path
import tempfile
import shutil
class TestValidateWorkdirIntegration:
"""Integration tests for validate_workdir function via Dagger CLI."""
def test_validate_valid_workdir(self, dagger_cli):
"""Test validation of a valid workdir via real Dagger CLI."""
result = dagger_cli("call validate-workdir", directory="tests/data/test_workdir")
assert result['success'], f"Command failed: {result['stderr']}"
output = result['stdout']
# Check that all required components are validated successfully
assert "✅ workdir" in output
assert "✅ config.yaml" in output
assert "✅ Dockerfile" in output
assert "✅ Valid migration workdir: True" in output
def test_validate_workdir_missing_directory(self, dagger_cli):
"""Test validation when directory doesn't exist."""
result = dagger_cli("call validate-workdir", directory="tests/data/nonexistent")
# Should fail because directory doesn't exist
assert not result['success']