riemann/riemann

NPE with Riemann 0.3.0 and inject!

jochenehret opened this issue · 6 comments

Hi,

we've just updated from Riemann 0.2.14 to 0.3.0 and now several of our tests are failing with an NPE. We've stripped the problem down to the following example stream and test:

reinject-stream.clj

(ns reinject-stream
    (:use riemann.config
          riemann.streams
          [riemann.test :only (tap)]
    )
)

(def reinject-stream
    (let [reinject (tap :reinject_test reinject)]
        (where (service "some_service")
            (with {:host nil :service "some_new_service"}
                reinject
            )
        )
    )
)

reinject-stream-test.clj

(include "reinject-stream.clj")

(ns reinject-stream-test
    (:use clojure.test
          reinject-stream
          [riemann.test :only (inject!)]
    )
)

(deftest reinject-stream-test
    (let [received-events (inject! [reinject-stream] [{:service "some_service" :time 0 :ttl 60 :metric 1000}])
          expected [{:service "some_new_service" :time 0 :ttl 60 :metric 1000}]
         ]
        (is (= expected (:reinject_test received-events)))
    )
)

Running the test with Riemann 0.2.14 works. With 0.3.0, we get:

Run clojure tests...
INFO [2018-04-10 08:45:30,821] main - riemann.bin - Loading /home/<...>/reinject-stream-test.clj

Testing reinject-stream-test
WARN [2018-04-10 08:45:30,945] main - riemann.streams - riemann.test$tap_stream$stream__9674@7f0766ef threw
java.lang.NullPointerException: null
	at clojure.core$swap_BANG_.invokeStatic(core.clj:2345)
	at clojure.core$swap_BANG_.invoke(core.clj:2337)
	at riemann.test$tap_stream$stream__9674.invoke(test.clj:41)
	at riemann.streams$with$stream__8692$fn__8731.invoke(streams.clj:1343)
	at riemann.streams$with$stream__8692.invoke(streams.clj:1343)
	at reinject_stream$fn__180$stream__9097__auto____181$fn__186.invoke(reinject-stream.clj:10)
	at reinject_stream$fn__180$stream__9097__auto____181.invoke(reinject-stream.clj:10)
	at riemann.test$inject_BANG_.invokeStatic(test.clj:142)
	at riemann.test$inject_BANG_.invoke(test.clj:127)
	at reinject_stream_test$fn__253.invokeStatic(reinject-stream-test.clj:11)
	at reinject_stream_test$fn__253.invoke(reinject-stream-test.clj:10)
	at clojure.test$test_var$fn__9209.invoke(test.clj:716)
	at clojure.test$test_var.invokeStatic(test.clj:716)
	at clojure.test$test_var.invoke(test.clj:707)
	at clojure.test$test_vars$fn__9235$fn__9240.invoke(test.clj:734)
	at clojure.test$default_fixture.invokeStatic(test.clj:686)
	at clojure.test$default_fixture.invoke(test.clj:682)
	at clojure.test$test_vars$fn__9235.invoke(test.clj:734)
	at clojure.test$default_fixture.invokeStatic(test.clj:686)
	at clojure.test$default_fixture.invoke(test.clj:682)
	at clojure.test$test_vars.invokeStatic(test.clj:730)
	at clojure.test$test_all_vars.invokeStatic(test.clj:736)
	at clojure.test$test_ns.invokeStatic(test.clj:757)
	at clojure.test$test_ns.invoke(test.clj:742)
	at clojure.core$map$fn__5587.invoke(core.clj:2745)
	at clojure.lang.LazySeq.sval(LazySeq.java:40)
	at clojure.lang.LazySeq.seq(LazySeq.java:49)
	at clojure.lang.Cons.next(Cons.java:39)
	at clojure.lang.RT.boundedLength(RT.java:1785)
	at clojure.lang.RestFn.applyTo(RestFn.java:130)
	at clojure.core$apply.invokeStatic(core.clj:659)
	at clojure.test$run_tests.invokeStatic(test.clj:767)
	at clojure.test$run_tests.doInvoke(test.clj:767)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:657)
	at clojure.test$run_all_tests.invokeStatic(test.clj:779)
	at clojure.test$run_all_tests.invoke(test.clj:779)
	at riemann.bin$run_tests_with_format.invokeStatic(bin.clj:97)
	at riemann.bin$run_tests_with_format.invoke(bin.clj:88)
	at riemann.bin$run_tests.invokeStatic(bin.clj:107)
	at riemann.bin$run_tests.invoke(bin.clj:99)
	at riemann.bin$_main$fn__14022.invoke(bin.clj:144)
	at clojure.core$with_redefs_fn.invokeStatic(core.clj:7434)
	at clojure.core$with_redefs_fn.invoke(core.clj:7418)
	at riemann.bin$_main.invokeStatic(bin.clj:138)
	at riemann.bin$_main.doInvoke(bin.clj:116)
	at clojure.lang.RestFn.invoke(RestFn.java:425)
	at clojure.lang.AFn.applyToHelper(AFn.java:156)
	at clojure.lang.RestFn.applyTo(RestFn.java:132)
	at riemann.bin.main(Unknown Source)

FAIL in (reinject-stream-test) (reinject-stream-test.clj:14)
expected: (= expected (:reinject_test received-events))
  actual: (not (= [{:service "some_new_service", :time 0, :ttl 60, :metric 1000}] nil))

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.

Can you please check?

Thanks and Best Regards,

Jochen.

Hi,

This code/test in riemann.config works:

(def reinject-stream
    (let [reinject (tap :reinject_test reinject)]
        (where (service "some_service")
            (with {:host nil :service "some_new_service"}
                reinject))))

(tests
 (deftest reinject-stream-test
   (let [received-events (inject! [riemann.config/reinject-stream]
                                  [{:service "some_service"
                                    :time 0
                                    :ttl 60
                                    :metric 1000}])
         expected [{:service "some_new_service" :time 0 :ttl 60 :metric 1000}]]
     (is (= expected (:reinject_test received-events))))))

I launched the tests with riemann test /etc/riemann/riemann.config

Could you describe how exactly you launch your tests ? We changed several things in 0.3.0 in the riemann.test namespace, so if you have your own test framework for Riemann maybe it broke something.

Hi,

we are launching the tests with:

./bin/riemann test clojure/reinject-stream-test.clj

I can confirm that everything works when I move test and code under test into one riemann.config file. Now this is not an option as we have several test files.

Is there something wrong with our imports or namespaces? Do we need (tests ...) in addition to (deftest ...)?

Thanks for the quick reply,

Jochen.

Is there something wrong with our imports or namespaces? Do we need (tests ...) in addition to (deftest ...)?

Not necessary, tests is just a helper.

Could you try to wrap your reinject calls wih riemann.test/io ? cf the Riemann 0.3.0 changelog:

We've also refactoring Riemann tests. Now, when you test your configuration, a full Riemann core is started. So streams like "reinject", indexing events, querying the index, and event expiration will now work in test mode and you can validate these streams. Don't forget you can use the io stream to suppress events in tests, so you can wrap index with it if you don't want to index events in tests.

Maybe your events are reinjected and caused a weird side effect.

I've wrapped reinject with io like this (before tap):

(def reinject-stream
    (let [reinject (tap :reinject_test (io reinject))]
        (where (service "some_service")
            (with {:host nil :service "some_new_service"}
               reinject
            )
        )
    )
)

Results:
0.2.14: Test green
0.3.0: NPE as above

Next I've tried to wrap the new reinject binding (after tap):

(def reinject-stream
    (let [reinject (tap :reinject_test reinject)]
        (where (service "some_service")
            (with {:host nil :service "some_new_service"}
               (io reinject)
            )
        )
    )
)

Results:
0.2.14: tap not working (empty vector [ ])
0.3.0: tap returns nil (but no NPE)

So that didn't help... for this kind of test it shouldn't matter if events are reinjected or not. We just want to check the newly generated events with a tap.

I noticed that in the inject! function the following line has been removed in 0.3.0:

(binding [*results* (fresh-results @*taps*)]

Could that cause our problems?

I noticed that in the inject! function the following line has been removed in 0.3.0:

Indeed, it's now in riemann.test/deftest: https://github.com/riemann/riemann/blob/master/src/riemann/test.clj#L179

Could you try to use it instead of clojure deftest ?

That was the problem.... it turned out that we had a mix of clojure.test/deftest and riemann.test/deftest. I've changed all tests to riemann.test/deftest and now things work again.

Thanks a lot for your quick assistance!

Best Regards,

Jochen.