Skip to content
This repository was archived by the owner on Oct 28, 2024. It is now read-only.

Commit 8622032

Browse files
authored
Merge pull request #12 from circleci/retest
Add retest.
2 parents 5f73df2 + c0aa307 commit 8622032

File tree

8 files changed

+92
-28
lines changed

8 files changed

+92
-28
lines changed

README.md

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ Add `[circleci/circleci.test "0.2.0"]` to your dev dependencies.
1010

1111
Run specific test namespaces with `lein run -m circleci.test my.first.test.ns my.second.test.ns`.
1212

13+
Run all loaded test namespaces from a repl with `(circleci.test/run-tests)` or
14+
pass in a list of symbols to just test a few namespaces.
15+
1316
Run individiual tests from a repl with `(circleci.test/test-var #'my.test.ns/my-test)`.
1417

15-
Alternatively you can add a Leiningen alias to test your whole test directory:
18+
It's more convenient to a Leiningen alias to test your whole test directory:
1619

1720
```clj
1821
:aliases {"test" ["run" "-m" "circleci.test/dir" :project/test-paths]}
@@ -40,7 +43,7 @@ selector functions in `dev-resources/circleci_test/config.clj`:
4043
:default (complement :flaky)}}
4144
```
4245

43-
If you have the `circleci.test/dir` alias set up as per above, you can pass
46+
If you have the Leiningen `:aliases` set up as per above, you can pass
4447
in a test selector as a command-line argument:
4548

4649
$ lein test :acceptance
@@ -55,16 +58,26 @@ putting this in your `dev-resources/circleci_test/config.clj` file:
5558
```clj
5659
(require '[circleci.test.report.junit :as junit])
5760

58-
{:reporters [(circleci.test.report/clojure-test-reporter)
59-
(junit/reporter "target/test-results")]}
61+
{:test-results-dir "target/test-results"
62+
:reporters [circleci.test.report/clojure-test-reporter
63+
junit/reporter]}
6064
```
6165

62-
Unlike `clojure.test`, you can use more than one reporter at a time. The
63-
argument to the `junit/reporter` function indicates which directory you
64-
want your test output in. It's best to ignore this directory in your version
65-
control system configuration.
66+
Unlike `clojure.test`, you can use more than one reporter at a time. It's
67+
recommended to add your `:test-results-dir` directory to the ignored list of
68+
your version control system.
69+
70+
If you use the junit test reporter, you can run `circleci.test.retest/-main` to
71+
re-run only the set of tests which previously failed. Adding an alias in
72+
`project.clj` is recommended:
73+
74+
```clj
75+
:aliases {"test" ["run" "-m" "circleci.test/dir" :project/test-paths]
76+
"retest" ["run" "-m" "circleci.test.retest"]}
77+
```
6678

6779
### Running tests from a repl
80+
6881
Use `circleci.test/test-var` to run a single test fn:
6982
```clojure
7083
(circleci.test/test-var #'my.test.ns/my-test)
@@ -82,7 +95,10 @@ running all tests that exist on disk.
8295

8396
### Global fixtures
8497

85-
In addition to `:once` and `:each` fixtures from `clojure.test`, you can define global fixtures that are only run once for the entire test run, no matter how many namespaces you run. This should be declared in your config file rather in any one individual test file though; otherwise it may not get loaded:
98+
In addition to `:once` and `:each` fixtures from `clojure.test`, you can define
99+
global fixtures that are only run once for the entire test run, no matter how
100+
many namespaces you run. This should be declared in your config file rather in
101+
any one individual test file though; otherwise it may not get loaded:
86102

87103
```clj
88104
{:global-fixture (fn [f]
@@ -164,13 +180,16 @@ and will not work with code that assumes it has control of that class.
164180
## Design goals
165181

166182
#### Compatibility with tests written using `clojure.test`
183+
167184
Don't force people to re-write tests just to use a different test runner.
168185

169-
Maintain compatibility with the `clojure.test` assertion expansions such as [slingshot.test](https://github.com/scgilardi/slingshot/blob/release/src/slingshot/test.clj)
186+
Maintain compatibility with the `clojure.test` assertion expansions such as
187+
[slingshot.test](https://github.com/scgilardi/slingshot/blob/release/src/slingshot/test.clj)
170188

171189
#### Extensible test reporting
172-
Must be possible to use more than one test reporter at a time, for instance it's desirable to produce Junit XML and console output during a test run.
173190

191+
Must be possible to use more than one test reporter at a time, for instance it's
192+
desirable to produce Junit XML and console output during a test run.
174193

175194
## License
176195

dev-resources/circleci_test/config.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
{:selectors {:all (constantly true)
77
:default (complement :failing)}
8-
:reporters [(clojure-test-reporter)
9-
(junit/reporter (or (System/getenv "CIRCLE_TEST_REPORTS")
10-
"test-results"))]
8+
:test-results-dir (or (System/getenv "CIRCLE_TEST_REPORTS")
9+
"test-results")
10+
:reporters [clojure-test-reporter junit/reporter]
1111
:global-fixture (fn [f]
1212
(assert (not *inside-global*))
1313
(binding [*inside-global* true]

project.clj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
:pedantic? :abort
77
:dependencies [[org.clojure/clojure "1.8.0"]
88
[org.clojure/data.xml "0.0.8"]]
9-
:aliases {"test" ["run" "-m" "circleci.test/dir" :project/test-paths]}
9+
:aliases {"test" ["run" "-m" "circleci.test/dir" :project/test-paths]
10+
"retest" ["run" "-m" "circleci.test.retest"]}
1011
:profiles {:uberjar {:aot :all}})

src/circleci/test.clj

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
(ns circleci.test
22
(:require [circleci.test.report :as report]
33
[clojure.test :as test]
4-
[clojure.java.io :as io]))
4+
[clojure.java.io :as io])
5+
(:import (clojure.lang LineNumberingPushbackReader)))
56

67
;; Once fixtures should be run exactly once regardless of which entry-point
78
;; into circleci.test is used
@@ -23,10 +24,14 @@
2324
;; dummy once-fixture.
2425
(def ^:dynamic *once-fixtures* {})
2526

26-
(defn- read-config! []
27-
(if-let [r (io/resource "circleci_test/config.clj")]
28-
(load-reader (clojure.lang.LineNumberingPushbackReader. (io/reader r)))
29-
{}))
27+
(def ^:private default-config {:test-results-dir "test-results"
28+
:reporters [report/clojure-test-reporter]})
29+
30+
(defn read-config! []
31+
(let [config (if-let [r (io/resource "circleci_test/config.clj")]
32+
(load-reader (LineNumberingPushbackReader. (io/reader r)))
33+
{})]
34+
(merge default-config config)))
3035

3136
(defn- make-once-fixture-fn
3237
[ns]
@@ -53,6 +58,11 @@
5358

5459
;; Running tests; low-level fns
5560

61+
(defn- get-reporters [config]
62+
(or report/*reporters*
63+
(for [make-reporter (:reporters config)]
64+
(make-reporter config))))
65+
5666
(defn- nanos->seconds
5767
[nanos]
5868
(/ nanos 1e9))
@@ -105,7 +115,7 @@
105115
;; entrypoints into the test runner
106116
(binding [test/test-var (partial test-var* config)
107117
test/report report/report
108-
report/*reporters* (:reporters config report/*reporters*)]
118+
report/*reporters* (get-reporters config)]
109119
(test-var* config v))))
110120

111121

@@ -129,7 +139,7 @@
129139
([ns selector config]
130140
(binding [test/*report-counters* (ref test/*initial-report-counters*)
131141
test/report report/report
132-
report/*reporters* (:reporters config report/*reporters*)]
142+
report/*reporters* (get-reporters config)]
133143
(let [ns-obj (the-ns ns)
134144
global-fixture-fn (make-global-fixture config)
135145
once-fixture-fn (once-fixtures ns-obj)]

src/circleci/test/report.clj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,14 @@
8181

8282
(end-test-var [this m]))
8383

84-
(defn clojure-test-reporter
85-
[]
84+
(defn clojure-test-reporter [_config]
8685
(->ClojureDotTestReporter))
8786

8887
(def ^:dynamic *reporters*
8988
"The sequence of currently configured test reporters. Consumers of the
9089
circleci.test library should not bind this var, set the :reporters key in
9190
test runner config instead."
92-
[(clojure-test-reporter)])
91+
nil)
9392

9493
;; Test result reporting
9594
(defmulti

src/circleci/test/report/junit.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,5 @@
112112
(defn reporter
113113
"Create a TestReporter that writes Junit compatible XML reports to
114114
`out-dir`."
115-
[out-dir]
116-
(->JunitReporter out-dir (atom []) (atom [])))
115+
[config]
116+
(->JunitReporter (:test-results-dir config) (atom []) (atom [])))

src/circleci/test/retest.clj

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
(ns circleci.test.retest
2+
(:require [clojure.data.xml :as xml]
3+
[clojure.java.io :as io]
4+
[circleci.test :as test]))
5+
6+
(defn- failed-tests-from [root]
7+
(let [suite (:name (:attrs root))]
8+
(for [test-case (:content root)
9+
:when (some #(= :failure (:tag %)) (:content test-case))]
10+
(symbol suite (:name (:attrs test-case))))))
11+
12+
(def ^:private missing-junit-msg
13+
"Previous test report files not found. Is the junit reporter configured?")
14+
15+
(defn- failed-tests [report-dir]
16+
(when-not (.exists (io/file report-dir))
17+
(throw (Exception. missing-junit-msg)))
18+
(for [report-file (.listFiles (io/file report-dir))
19+
test (failed-tests-from (xml/parse (io/reader report-file)))]
20+
test))
21+
22+
(defn- make-selector [tests]
23+
(comp (set (map name tests)) str :name))
24+
25+
(defn -main []
26+
(let [{:keys [test-results-dir] :as config} (test/read-config!)]
27+
(when-not (.exists (io/file test-results-dir))
28+
(binding [*out* *err*]
29+
(println missing-junit-msg)
30+
(System/exit 1)))
31+
(if-let [failed (seq (failed-tests test-results-dir))]
32+
(doseq [[test-ns tests] (group-by (comp symbol namespace) failed)]
33+
(require test-ns)
34+
(test/test-ns test-ns (make-selector tests) config))
35+
(println "No failed tests."))))

test/circleci/test/report/test_junit.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@
4949
;; `lein test` assumes tests return a map.
5050
(let [tempdir (Files/createTempDirectory "circleci.test.report.test-junit" (into-array FileAttribute []))]
5151
(-> tempdir .toFile .deleteOnExit)
52-
(binding [circleci.test.report/*reporters* [(junit/reporter (str tempdir))]]
52+
(binding [circleci.test.report/*reporters* [(junit/reporter {:test-results-dir (str tempdir)})]]
5353
(is (map? (circleci.test/run-tests 'circleci.test-config))))))

0 commit comments

Comments
 (0)