Some thoughts and ideas on test refactor:
-
Review folder structure - will it still make sense after the refactor?
-
Try to eliminate as much as possible any mutable global state. This will make it easier to refactor. I'm thinking e.g. the config or a start.
-
Wrap the resource managers in interfaces.
Suggested a single interface per folder in
pkg/resourcemanager
. E.g.EventhubManager
for eventhubs.Then we only expose the resource managers to the controllers via these interfaces (rather than globally accessible methods).
This should be a straightforward refactoring exercise.
-
Modify the controllers to use these interfaces.
This should be quite straightforward in the existing code - we just need to add the appropriate resource managers to the respective reconcilers as required. For example:
EventhubReconciler
becomes:type EventhubReconciler struct { client.Client Log logr.Logger Recorder record.EventRecorder Scheme *runtime.Scheme EventhubManager *eventhubManager }
The controller code should need to change very little.
-
Create mock resource managers.
I'm not quite sure how these will look. Do we want to use a mocking framework? Or simply create by hand alternative minimal implementations of the
*Manager
interfaces?Considerations/comments:
- Will this speed up things sufficiently so we can do full setup and teardown in individual test cases, or will we still want common setup and teardown (e.g. create a resource manager)?
- With the tests running in parallel the tests run in separate memory space. So there has to be some kind of remote support. Unless we can speed things up enough to no longer need parallel controller tests.
- Do we want/need to verify the interactions with the resource manager in the unit tests? Or do we just verify the state of the services?
- Do we need to be able to support the webhook scenario (even though we are removing them)? In this case, the webhook may need to have the same idea of azure service state as the controller. Again some kind of remote service with shared state is required for this.
Alternatives:
-
Mock the resource managers in the unit tests as and when needed, probably via a mocking framework Advantages:
- Provide the implementations required in the test case itself.
- Can verify the service mananger interactions explicitly.
Disadvantages:
- Frameworky. Can be fiddly.
- Will not support shared remote state scenario.
Libraries - alternatives to consider:
-
Create a mock (or maybe the right name is a stub) service that provides implementations of the resource managers.
- If remoting is needed, can expose an http service, but that might be overkill, something like https://golang.org/pkg/net/rpc/ might be suitable.
- A bit of extra work. An additional executable service.
-
Dependency injection.
Do we need some kind of DI framework (e.g. https://github.com/google/wire ) to wire up the dependencies (specifically create and configure the resource managers and provide them to the controllers)?
Or will this be simple enough to do by hand?
-
Implementation strategy / roadmap.
Goals:
- Minimise impact on other development
- Avoid as much as possible complex merges
- Parallelize development effort
Strategies:
- Refactor (steps 1-4 above) to enable, then add test service as a next step.
- Big bang approach?