schireson / pytest-mock-resources

Pytest Fixtures that let you actually test against external resource (Postgres, Mongo, Redshift...) dependent code.
https://pytest-mock-resources.readthedocs.io/en/latest/quickstart.html
MIT License
179 stars 19 forks source link

Expose mechanism for customizing container-level configuration #79

Closed DanCardin closed 3 years ago

DanCardin commented 4 years ago

Is your feature request related to a problem? Please describe. Today we have a general assumption of things like host, port, and lack of configuration on other container-specific-things. Implementing something like a vault resource requires more configuration, which is hard to reliably predict will work in all circumstances.

Furthermore, we make basic assumptions about things like the container version, which would be the first thing I'd personally want to customize to match our deployed resource version.

Describe the solution you'd like Option 1: Expose a pmr_<resources>_config fixture for each fixture type which describes resource-level configuration for that resource, for example:

@pytest.fixture('session')
def pmr_postgres_config():
    return {'host': 'localhost', 'image': 'postgres:tag', ...}

We can start with a dict, but it might be advantageous to preemptively use a class of some type. potentially resource-specific. It probably makes sense to use this as an override to the default on a per-config-option basis.

Additionally, this would make making use of the config in tests for e.g. custom connections a lot more straightforward, compared to what we do today.

Option 1b: same thing but a global pmr_config fixture. I think this might be objectively worse because it's far more janky when considering using it inside a test for a manual connection.

Option 2: Accept PMR (i.e. PMR_POSTGRES_PORT) for all the various configuration values that are available for each resource type. Presumably we'd do this dynamically and on-demand (rather than module-level, as is the case now), rather than having them all statically defined.

Option 3: Do both.

Things like image (and other resource-specific settings) would tend to be static and system dependent. I wouldn't want to have to specific it in my env, as it ought to be tied to the version you're using at any given time for that project.

Things like port, or host are going to be more specific to the environment in which you're running them (CI, or just ephemeral port conflicts)

DanCardin commented 4 years ago

it occurs to me that it might actually be possible to only produce <foo>_config fixtures on demand after the first test has requested a foo resources, so you wouldn't, for example see any config fixtures for fixtures you haven't requested

oakhan3 commented 4 years ago

I like the idea of a class for option 1 +3 but it would have to be well documented!

I'm imagining a config class per container with corresponding config fixture like the following to keep overriding minimal:

@dataclass
class PMRPostgresConfig:
    host: Optional[str] = None

    def get_host(self):
        if self.host:
            return host

        host = os.environ.get("PMR_POSTGRES_HOST")
        if host:
            return host

        if IN_DOCKER
            return "host.external.docker"

        return "localhost"

@pytest.fixture(scope="session")
def pmr_postgres_config():
    return PMRPostgresConfig()

And if someone wants to override something they would define a new fixture like:

@pytest.fixture(scope="session")
def pmr_postgres_config():
    host = some_logic_to_get_host()  # or they could just set it to some string
    return PMRPostgresConfig(host=host)
DanCardin commented 4 years ago

I was thinking all in dicts originally, but yea a class is going go provide much better safety as an interface.

DanCardin commented 4 years ago

Implementation for postgres(/redshift) https://github.com/schireson/pytest-mock-resources/pull/81

DanCardin commented 3 years ago

Should be fixed as of 1.5.0