Fork me on GitHub
#clojure
<
2020-05-17
>
jdkealy01:05:42

I am porting a clojure project over to a new framework and I’m getting Unable to resolve symbol: inst-ms when trying to run a repl. Why would that be, it’s part of clojure.core no ?

hiredman01:05:02

Old version of clojure

hiredman01:05:28

Likely your project is not explicitly specifying what version of clojure it wants you you just end up running with anything, and something is causing that to be an old enough version of clojure that inst-ms doesn't exist

👍 4
dpsutton01:05:36

i see there's a call to push-thread-bindings in tools.deps.alpha without an associated call to pop-thread-bindings. this would be worrying except the person who wrote this code is also possibly the one who wrote the docstring of push-thread-bindings to never use it without the pop. Its on a fixed thread pool executor service so it seems like it should slowly be poisoning the threads?

dpsutton02:05:11

i'm wondering what i'm missing. i figured if the threads could die it wouldn't matter but these are in a pool so presumably they are just in a bad state after its first use?

dpsutton02:05:20

(defn submit-task
  ^Future [^ExecutorService executor f]
  (let [bindings (get-thread-bindings)
        task #(do
                (push-thread-bindings bindings)
                (f))]
    (.submit executor ^Callable task)))

Alex Miller (Clojure team)02:05:48

Probably should be a pop, but the bindings being pushed in in each case are replacing the previous so there’s no functional issue

Alex Miller (Clojure team)02:05:38

Just memory leak, but not one big enough to be noticed typically

dpsutton02:05:40

oh thanks alex. i hope i didn't interrupt your night.

craftybones10:05:33

What is the canonical way to test state in Clojure? Assuming you have some atom that contains the app-state and there are a bunch of handlers that manipulate it and you want to test the handlers, do you use with-redefs to set the app-state?

vemv13:05:35

I tend to do it like this:

(def global-state (atom ...))

(defn handler [{:keys [state]
                :or {state global-state}}]
  ...)

vemv13:05:55

the idea being, I can test handler isolatedly, passing an atom as an arg. Same for each handler - I test them individually, without having to set up something more elaborate. with-redefs is not exactly clean (for one thing it's not thread-safe, if you were to run tests in parallel)

craftybones13:05:17

@U45T93RA6 - thanks, injection was the other option

craftybones13:05:38

The broader question is, mock function or mock state?

vemv13:05:56

Personally I tend to do both. For example a test-only protocol implementation ("mock function") could write to an atom ("mock data") At the same time I consider mocking some sort of last resource - the idea being to favor hitting pure functions instead

craftybones13:05:17

agreed. Though, when one tests a stateful application it is almost impossible to avoid either setting state up or mocking some function

craftybones13:05:02

There’s a certain class of bugs that are entirely based on how state is setup and with Clojure, it seems a lot easier to test state than it is in other systems where state is spread across objects or other such systems

👍 4
vemv13:05:38

an alternative (or at least addition) that comes to mind is doing heavy validation of state in all relevant/possible places e.g. for an atom, use :validator or place :pre in defns asserting that the received state is valid and consistent of course most web apps aren't atom-based, but it's a trick I occasionally use This way, one doesn't necessarily write state-related tests, but instead writes higher-level tests (a user story) and relies in the preconditions being exercised

craftybones13:05:19

Yeah, I was just discussing this with someone and we arrived upon spec + state based tests being a pretty solid guard

✌️ 4
noisesmith15:05:43

regarding mocks / with-redefs, the more reliable option is to make update functions that simply take a map and return a map, you test them by offering a map and inquiring about the map that comes back

noisesmith15:05:23

then, in the actual app, you can use that function as an arg to swap! , but there's no need to attach the state update to the state management code

craftybones22:05:13

@U051SS2EU - fair, but how would you test the fn that’s calling swap! ?

noisesmith22:05:58

by giving it different (limited and testable) functions to call, or limit tests of that function to full integration tests

noisesmith22:05:56

I would consider it a code smell if the swap! call is nested deep - I expect global effects and mutation to happen at the top of the stack if it needs to happen

noisesmith22:05:22

(aside from debugging etc.)

craftybones22:05:16

Yeah, all the swap! calls here are only in the handlers of a server

craftybones22:05:28

The general popular option to test db integrations etc tends to be to pull out a protocol and test it with something reified

craftybones22:05:03

with app state, as you say, unit test the individual fns that work on the fragments of the global object and then write integration tests on the swap!/reset! calls to it

noisesmith22:05:37

yeah, so if your api is atom + fn + swap! your "reified object" is just a simple function

noisesmith22:05:08

or going the other way, for testing an individual handler, the "test harness" is just a data literal

craftybones11:05:54

I’m doing something like this at the moment

craftybones11:05:59

(with-redefs [d/user-present? (constantly true)]
      (let [response (s/signup (-> (mock/request :post "/signup/boo")))
            body (:body response)]
        (t/is (= 200 (:status response)))
        (t/is (= "Already signed up" body))))

vemv13:05:18

Anyone has https://github.com/lambdaisland/deep-diff2 set up against clojure.test? For comparing expected vs actual I reckon it's not too hard to accomplish, I'm just curious if someone has a polished defmethod snippet already

vemv13:05:38

currently I grab the expected and actual vals by hand and paste them against a diff invocation that I have as an IDE snippet Not too cumbersome, but of course a built-in integration would be nicer

orestis14:05:03

Kaocha probably uses that...

👀 4
vemv15:05:04

Yeah I can dive into it :) but other than that I tend to be careful around the idea of depending completely in an alternative runner. Same for eftest. Both projects rock tbh, but tests are too important for me to make a migration without some prior study

cantdoart15:05:49

first time trying to use clojure and i'm looking to set up vim+clojure-lsp. i've cloned a github project to test this out with, but clojure-lsp is giving me an unknown symbol for just about everything in this file: https://github.com/andeemarks/shokunin-august/blob/master/src/shokunin/august.clj. is this because of the clara.rules macros?

lilactown15:05:53

@cantdoart5 yes that’s very likely. static analysis struggles with macros that implicitly provide/allow symbols inside their body

lilactown15:05:38

it’s not very common in Clojure to do this, but clara happens to 🙂

cantdoart15:05:58

thanks, @lilactown for the insight

coby18:05:04

what's the idiomatic way to take a vector like [:a "A" :b "B"] and get a map like {:a "A" :b "B"}? I think I want something like (into {} (something v)) but I can't remember the something I'm looking for 🙂

andy.fingerhut18:05:43

One way:

user=> (def v1 [:a "A" :b  "B"])
#'user/v1
user=> (apply hash-map v1)
{:b "B", :a "A"}

👍 12
coby18:05:23

nice! Thanks

orestis18:05:02

Something with partition?

hindol19:05:14

That something is (partition 2 coll)?

didibus20:05:06

apply hash-map I'd say is what I've seen most often