component

jimbob 2018-12-07T20:56:33.001Z

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?

2018-12-07T21:01:17.001300Z

a system is a map

2018-12-07T21:01:30.001700Z

use select-keys to select the subparts you want

seancorfield 2018-12-07T21:02:46.002500Z

Or if you're trying to start just that component, remember to specify using for its dependencies (and build those too).

jimbob 2018-12-07T21:06:55.002800Z

im trying to start a component and all its dependents

jimbob 2018-12-07T21:06:57.003Z

in a map

jimbob 2018-12-07T21:07:44.004Z

so say i have a large map. ideally i would be able to do: (component/start-system (:component-with-dependents (large-map)))

jimbob 2018-12-07T21:07:50.004300Z

and that would work

seancorfield 2018-12-07T21:09:01.005200Z

If you only want the subcomponent, only build that. With its dependencies.

seancorfield 2018-12-07T21:09:09.005600Z

Don't try to use the whole system.

jimbob 2018-12-07T21:09:36.006700Z

can i not reuse my whole system-map (not started yet) and then refine from there?

seancorfield 2018-12-07T21:09:45.006900Z

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.

jimbob 2018-12-07T21:10:00.007200Z

right, im not building out or wanting to build oout anything else

jimbob 2018-12-07T21:10:09.007500Z

but i do want to reuse the whole system map that is already defined

jimbob 2018-12-07T21:10:14.007700Z

and just start subsections

seancorfield 2018-12-07T21:10:27.008100Z

That's not how it works and not how it's supposed to work.

seancorfield 2018-12-07T21:10:41.008500Z

If you tests are about a subcomponent, they shouldn't even reference the full system.

jimbob 2018-12-07T21:11:01.009Z

i see.

seancorfield 2018-12-07T21:11:08.009400Z

Component is intended to let you provide mock dependencies. That's part of its power for testing.

jimbob 2018-12-07T21:11:13.009700Z

probably the best plan then is to build a separate test-system-map for each part im testing

seancorfield 2018-12-07T21:12:43.011400Z

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.

jimbob 2018-12-07T21:13:07.012100Z

yes that seems like good discrete separated unit tests

jimbob 2018-12-07T21:13:09.012400Z

im smoke testing

jimbob 2018-12-07T21:13:11.012600Z

in production

jimbob 2018-12-07T21:13:33.012900Z

as part of a deploy step

seancorfield 2018-12-07T21:14:07.013600Z

Well then you probably want to build and start the whole application component and run tests on that?

seancorfield 2018-12-07T21:14:34.014400Z

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).

jimbob 2018-12-07T21:14:36.014600Z

not necessarily. not wanting to take traffic just yet for example

jimbob 2018-12-07T21:14:51.014900Z

from queues or an api

seancorfield 2018-12-07T21:15:36.015700Z

Then your smoke tests will have to build the parts they're interested in, with their dependencies.

jimbob 2018-12-07T21:15:59.016200Z

yes. thats kind of where im at with my question hehe..

jimbob 2018-12-07T21:16:05.016500Z

subsystems of a production system map

jimbob 2018-12-07T21:16:10.016800Z

subcomponents rather

seancorfield 2018-12-07T21:16:49.017800Z

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.

jimbob 2018-12-07T21:18:15.019700Z

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))

jimbob 2018-12-07T21:18:31.020100Z

but this is fine and explicit

jimbob 2018-12-07T21:19:04.020800Z

i was just wondering if there were more concise albeit implicit ways of also starting the dependents of the thing you are starting

seancorfield 2018-12-07T21:19:09.021Z

No.

jimbob 2018-12-07T21:19:13.021300Z

ok thank you!

seancorfield 2018-12-07T21:20:11.022200Z

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.

seancorfield 2018-12-07T21:20:47.022800Z

Otherwise, Component has nothing to inject (& start) for that dependency.

jimbob 2018-12-07T21:20:59.023200Z

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

jimbob 2018-12-07T21:21:11.023700Z

since thats kind of how start-system works

jimbob 2018-12-07T21:21:20.024200Z

well

jimbob 2018-12-07T21:21:23.024400Z

i guess its explicit as well

jimbob 2018-12-07T21:21:27.024700Z

but we have the system map

jimbob 2018-12-07T21:21:37.025400Z

which dependencies can be inferred.

seancorfield 2018-12-07T21:21:39.025600Z

But from :dpp-client's value, that other data is not visible/accessible -- it's not part of that subcomponent.

jimbob 2018-12-07T21:22:41.026600Z

i see, because we still need to pass in certain args

seancorfield 2018-12-07T21:22:52.027100Z

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.

👍 1
jimbob 2018-12-07T21:22:54.027300Z

even though we are standardized here and can probably make a macro or something to do just that

jimbob 2018-12-07T21:23:48.027700Z

ok this is beginning to make a lot more sense

seancorfield 2018-12-07T21:25:02.028500Z

(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)

jimbob 2018-12-07T21:26:36.028700Z

ah thats a good idea

2018-12-07T21:43:57.029Z

if I recall, it does throw an exception

seancorfield 2018-12-07T21:46:12.029300Z

You are correct Missing dependency :b of clojure.lang.PersistentArrayMap expected in system at :b

2018-12-07T21:49:41.030200Z

annoyingly it does lose dependency information with select keys, but if you manually dissoc the components you don't want it works

2018-12-07T21:50:03.030400Z

user=> 
(into {}
      (component/start
       (dissoc
        (component/system-using
         (component/system-map
          :a {}
          :b {}
          :c {})
         {:a [:b]
          :b []})
        :c)))
{:a {:b {}}, :b {}}
user=>