A POC by @Shimon_Shtein to introduce Molecule role-level testing for foremanctl installer.
This POC focused on two things:
- Theoretical part: how to organize tests and what is the scope for per-role tests.
- Practical part: how to connect the dots, and make sure molecule tests are enabled and working in the repo.
Theoretical part:
Problem definition
- Currently foremanctl is tested by two options:
- The existing e2e pytest suite
- Robottelo high level scenario testing
- Each role has a lot of parameters that change the behavior of the role. For example the certificates role has three possible operation modes:
- locally generated certificates
- Custom certificates
- foreman-installer inherited certificates
- Roles rely on previous roles to be executed (for example foreman role will require a running database to spin up a proper foreman container)
- Testing all the permutations for all the roles quickly becomes too hard.
- Currently there is no way to get a quick answer to a question “did I break something with my latest change”, which is really important for agentic development.
Assumption:
I see the foremanctl flow as a chain of transformations to a base server that result in a configuration to that server in such a way that it has foreman (or proxy, but I’m leaving the proxy out of the scope right now) responding on the machine.
It can be represented by: <clean server> => T1 => T2 => ... => Tn => <a server with foreman configured on it>, where each Tn is an ansible role applied to the server.
Given this representation, we can extract invariants. Those invariants are the contract between different transformations (roles). These contracts are a set of artifacts on the server that are always produced by the role Tn and are consumed by T(n+1). In addition each transformation can change the contents of produced artifacts according to the input parameter values.
Permutations problem solution:
For each role we make sure that for any input, the role maintains the invariant.
For each input we validate that the output configuration changes according to the input parameters.
This solution confines each role in a set of boundaries, where as long as the invariants are preserved, the next transformation can happen. This reduces the complexity from <input variants for T1>*<input variants for T2>*...*<input variants for Tn> to <input variants for T1>+<input variants for T2>+...+<input variants for Tn>.
Quick answer solution:
While the e2e tests can validate that the server that is configured is fully functional, I suggest using mocking for testing individual roles. This will give some confidence that the transformation still confined in the invariant and the configuration changes according to the input parameters, but without the cost of running the full installation process.
Since we will use mock objects for containers instead of actual containers, we won’t need the actual prerequisites for the role, but on the other hand, we will still be able to inspect that the configuration objects that are expected from the role exist and contain the correct data.
The practical part:
- The POC code: GitHub - ShimShtein/foremanctl at molecule_poc · GitHub and Add molecule tests to certificates role by ShimShtein · Pull Request #548 · theforeman/foremanctl · GitHub
It contains molecule tests with multiple scenarios for the certificates role, where each scenario represents a different input variant (custom certs, generated certs). The scenarios are structured to test a common validation (invariant) and a set of input-specific checks. - The tests can be called by running
molecule testfrom the role’s folder. - The tests are also embedded into the general pytest suite (with an opt-in switch
--molecule)
Open discussion:
Is mocking the correct way to go forward.
Decision Outcome
Should we proceed with this effort?
Is it something useful?
Are there alternatives?