This will let us pass overrides for each test. I switched from
`instance_for_test` to `instance_for_test_tempdir` because the former
was making it difficult to properly yield. We were basically running
into this
The `instance` fixture still provides our default instance:
```
import osdef test_instance(instance):
import tempfile assert isinstance(instance.run_launcher, EcsRunLauncher)
from contextlib import contextmanager```
import pytestBut tests can also use the lower level `instance_cm` fixture to
customize the Dagster Instance (while still reaping the benefit of
ignoring the minutia of the `stub_aws` and `metadata` test setup):
@contextmanager```
def yielder():test_instance(instance_cm):
with tempfile.TemporaryDirectory(instance_cm({"container_name": "foo"}) as temp_dir:instance:
assert os.path.isdir(temp_dirisinstance(instance.run_launcher, EcsRunLauncher)
yield temp_dirassert instance.container_name == "foo"
```
The reason `instance_cm` returns a contextmanager rather than yielding
the instance directly is because when you yield a function that yields,
it returns a generator and not the thing being yielded. So callers would
need to call `next(instance)` to actually get their instance. Rough.
Another approach I looked at was using pytest parameterization:
```
@pytest.fixture
def instance_config():
return {}
@pytest.fixture
def factory():instance(stub_aws, metadata, instance_config):
def inner():overrides = {
with yielder() as yielded:"run_launcher": {
return yielded"module": "dagster_aws.ecs",
"class": "EcsRunLauncher",
"config": {**(instance_config or {})},
}
}
with instance_for_test(overrides) as instance:
yield innerstance
def test_yielding(factory):instance(instance):
assert not os.path.isdir(factory())# If you don't parametrize, it uses the default `instance_config`.
``` assert isinstance(instance.run_launcher, EcsRunLauncher)
If we return `yielded`@pytest.mark.parametrize("instance_config", the contextmanager cleans up and the[{"container_name": "foo"})
temporary directory no longer exists.def test_instance_parametrized(instance):
assert isinstance(instance.run_launcher, EcsRunLauncher)
assert instance.container_name == "foo"
```
If we instead yield `yielded`While perhaps better adhering to pytest idioms, `factory()` returns a generator and weit's an inelegent
need to call `next()` on itsolution for it to be useful.two reasons:
By passing in our own temporary directory via1. You can't easily parametrize the same fixture multiple times. So a
`instance_for_test_tempdir`, we can ensure that the temporary directory test that needs multiple instances - each with their own config - is
still exists even when we return `instance`.
It might be useful to create fixture representations of many of the diffult to achieve.
2. There's not an easy way for the parameter itself to source from a
fixture (like if instead of `{"container_name": "foo"}`, we wanted
`{"container_name": foo_fixture}`. This means we cede control of the
fixture setup/teardown chain because we can't make our `instance`
functions in test_utils.py but that's out of scope for this change fixture depend on another fixture.