I am trying to test a subsystem in some smoke tests but cant find a clear way to get the substem from the entire system map? I for example build the system map and start the system usually in production, but in test i want to take this system map and only start one component or some nested components but all the dependents are nil. any way around this?
a system is a map
use select-keys to select the subparts you want
Or if you're trying to start just that component, remember to specify using
for its dependencies (and build those too).
im trying to start a component and all its dependents
in a map
so say i have a large map. ideally i would be able to do:
(component/start-system (:component-with-dependents (large-map)))
and that would work
If you only want the subcomponent, only build that. With its dependencies.
Don't try to use the whole system.
can i not reuse my whole system-map (not started yet) and then refine from there?
That's kind of the point of Component -- you can build only the piece you care about for your tests, and provide whatever dependencies you want. So you can mock things out for subcomponent testing.
right, im not building out or wanting to build oout anything else
but i do want to reuse the whole system map that is already defined
and just start subsections
That's not how it works and not how it's supposed to work.
If you tests are about a subcomponent, they shouldn't even reference the full system.
i see.
Component is intended to let you provide mock dependencies. That's part of its power for testing.
probably the best plan then is to build a separate test-system-map for each part im testing
For example, at World Singles Networks, we have an "Application" Component with dependencies on Environment, Datasource, Caches components. Datasource and Caches depend on Environment. For the tests on Environment-related stuff, we just build Environment, nothing else. For the tests on Caches, we build the Caches component with an Environment component.
yes that seems like good discrete separated unit tests
im smoke testing
in production
as part of a deploy step
Well then you probably want to build and start the whole application component and run tests on that?
Once it is started, you can reach in and pull components out to work with (and they will all be started and have their dependencies).
not necessarily. not wanting to take traffic just yet for example
from queues or an api
Then your smoke tests will have to build the parts they're interested in, with their dependencies.
yes. thats kind of where im at with my question hehe..
subsystems of a production system map
subcomponents rather
If you're not testing the complete system map, ignore it. Build the components you are interested in, with their dependents, and start just those parts.
yes. For example i have this:
(def test-dpp-client-system-map
(component/system-map
:cache-client (cache-client/make-component (:cache-client helpers/config))
:dpp-client (component/using (cpp/make-component (:dpp-client helpers/config))
[:cache-client])))
instead id like to:
def test-dpp-client-system-map
(some-how-start-dependents-with-this-top-level-component-in-a-cleaner-way (:dpp-client production-system-map))
but this is fine and explicit
i was just wondering if there were more concise albeit implicit ways of also starting the dependents of the thing you are starting
No.
ok thank you!
Your test-dpp-client-system-map
would need to create and hold the :cache-client
component since :dpp-client
depends on it. You can't get away from that.
Otherwise, Component has nothing to inject (& start) for that dependency.
right, i was just wondering if there were out of the box ways, say using the dependency-graph for component to intelligently infer that i want that started first
since thats kind of how start-system works
well
i guess its explicit as well
but we have the system map
which dependencies can be inferred.
But from :dpp-client
's value, that other data is not visible/accessible -- it's not part of that subcomponent.
i see, because we still need to pass in certain args
It's only when you start
things that the actual component values get injected -- which means that whatever is started has to have access to all those components. Until that point, the metadata is just keywords.
even though we are standardized here and can probably make a macro or something to do just that
ok this is beginning to make a lot more sense
(it would probably have helped you if component/start
threw an exception if a dependency could not be found/injected rather than just leaving things as nil
)
ah thats a good idea
if I recall, it does throw an exception
You are correct Missing dependency :b of clojure.lang.PersistentArrayMap expected in system at :b
annoyingly it does lose dependency information with select keys, but if you manually dissoc the components you don't want it works
user=>
(into {}
(component/start
(dissoc
(component/system-using
(component/system-map
:a {}
:b {}
:c {})
{:a [:b]
:b []})
:c)))
{:a {:b {}}, :b {}}
user=>