Fork me on GitHub
#polylith
<
2021-09-30
>
Andrés Rodríguez17:09:35

Hi everyone! I've been migrating a codebase to Polylith and ran into a particularly annoying issue. The codebase uses Malli for validation and makes use of a custom default registry. Now the way that works in Malli is that you have to set a JVM opt -Dmalli.registry/type=custom that seemingly clears the registry on start, and then allows you to override the default registry without throwing an exception. Now the problem is that when I go and run poly test, Malli fails with an invalid-schema error because... the Polylith CLI also uses Malli for validation and of course doesn't initialize our custom registry. Unless there's a better solution, my question would be: Is there a way that I can pass JVM opts to the JVM running the tests and not the one running the Polylith CLI?

seancorfield17:09:39

poly test uses a single JVM but creates isolated classloaders for each project when running tests.

seancorfield17:09:52

You would need to specify that JVM option in a way that the poly script's JVM will pick up. I use the tool via a :poly alias in deps.edn so I can easily add JVM options there. I haven't looked at the poly script but I suspect there is an environment variable you can set for that...

Andrés Rodríguez17:09:47

I'm afraid that's how I'm reproducing issue. I first tried setting JVM_OPTS as suggested in the readme, and it didn't work (Malli threw an exception because it wasn't picking up the option), but overriding my local _JAVA_OPTIONS did which led to the error. Then I tried using Polylith from a deps.edn alias, where I can set :jvm-opts, but that leads to the same error.

seancorfield17:09:50

Gotcha. Hmm, I guess that's the problem with a global registry and the ability to customize it in ways that are incompatible with other tooling 😞

seancorfield17:09:02

Perhaps Polylith should consider migrating off Malli to avoid this sort of conflict?

furkan3ayraktar17:09:51

There is no option at the moment to pass JVM options to the test runner’s classloader. I haven’t thought about this need before. I also don’t understand why it collides with Polylith’s use of malli since the classloader we create supposed to be isolated.

Andrés Rodríguez17:09:00

@U04V70XH6 Global state sucks, but who could've seen that one coming? 😂 . By the way, thank you for helping me again with another issue related to the same underlying problem. I was the guy who tried to pass JVM opts to tools.build to get Malli to compile with our custom registry the other day. @U2BDZ9JG3 They're probably correctly isolated, it's just that the only way I can set JVM opts is globally, affecting the Polylith CLI probably way before it has a chance to spawn a classloader for testing our code. If a way to set opts specific to our classloader were to appear, that'd be great for this kind of usecase. Right now I think I'll just have to rip out the problem at its root: avoid mutating global state and pass in the custom registry manually wherever it's needed.

furkan3ayraktar17:09:18

Yeah, I think avoiding global state is always a good thing, when possible. I’ll look into the classloader to see if we can pass jvm options to it

seancorfield17:09:12

@U02FU034U15 What you might be able to do is write a "test fixture" that sets that JVM property directly at runtime. You can have per-project test fixtures now in Polylith.

seancorfield17:09:48

For example, in our workspace.edn file we have:

"worldsingles"      {:alias "ws"
                                 :test {:setup-fn    worldsingles.application.fixtures/pre-test
                                        :teardown-fn worldsingles.application.fixtures/post-test}}

Andrés Rodríguez18:09:13

@U2BDZ9JG3 Thank you! @U04V70XH6 I'll try doing that in the setup function just in case, we do have a commented out line that does it right before setting the registry and that does not work for whatever reason.

Andrés Rodríguez18:09:29

I assume something that Malli does on init is the problem.

seancorfield18:09:48

That's why I suggested the Polylith :setup-fn approach -- it's run independently before your tests are loaded. But you might still need to somehow force Malli to reinitialize?

Andrés Rodríguez18:09:47

There's the chance that if the setup-fn is executed before Malli runs, that might just do it. Because I'm not sure if there's a way to reload Malli unless there's a way I can hack it on the JVM side. I'll give the test-setup approach a go and report back 👍

1
Andrés Rodríguez18:09:41

Y'all are great you know that? One (System/setProperty "malli.registry/type" "custom") later inside the test setup and the suite is all green. Thank you so much!

❤️ 9
Andrés Rodríguez18:09:30

@U2BDZ9JG3 This also means that instead of adding features to the classloading code, a small note on the test setup section of the README could work in its stead!

furkan3ayraktar18:09:10

Awesome! I’m glad that its resolved already 🎉

seancorfield20:09:55

@U02FU034U15 Really glad to hear that worked! We do some heavy-lifting in our :setup-fn (and undo it in :teardown-fn) which helps our test suite run a lot faster, compared to running that setup/teardown around each ns of tests or even, heaven forbid, around each individual test!

tengstrand07:10:41

A happy ending and really great work guys!

ikitommi07:10:12

most likely will change the default in malli so one can plug in a custom registry without the JVM/compiler-option. It bites 90% of the time.

👍 17
1