|
12 | 12 | [control :as c]
|
13 | 13 | [independent :as independent]
|
14 | 14 | [generator :as gen]
|
15 |
| - [nemesis :as nemesis] |
16 | 15 | [tests :as tests]
|
17 | 16 | [util :refer [timeout meh]]]
|
18 | 17 | [jepsen.checker.timeline :as timeline]
|
|
21 | 20 | [tarantool [db :as db]
|
22 | 21 | [register :as register]
|
23 | 22 | [sets :as sets]
|
24 |
| - [counter :as counter]])) |
| 23 | + [counter :as counter] |
| 24 | + [nemesis :as nemesis]])) |
25 | 25 |
|
26 | 26 | (def workloads
|
27 | 27 | "A map of workload names to functions that can take opts and construct
|
|
48 | 48 | ;:pages pages/workload
|
49 | 49 | :register register/workload})
|
50 | 50 |
|
| 51 | +(def standard-workloads |
| 52 | + "The workload names we run for test-all by default." |
| 53 | + (keys workloads)) |
| 54 | + |
51 | 55 | (def workload-options
|
52 | 56 | "For each workload, a map of workload options to all the values that option
|
53 | 57 | supports."
|
|
64 | 68 | ;:pages {:serialized-indices [true false]}
|
65 | 69 | :register {}})
|
66 | 70 |
|
| 71 | +(def nemeses |
| 72 | + "Types of faults a nemesis can create." |
| 73 | + #{:pause :kill :partition :clock}) |
| 74 | + |
| 75 | +(def standard-nemeses |
| 76 | + "Combinations of nemeses for tests" |
| 77 | + [[] |
| 78 | + [:pause] |
| 79 | + [:kill] |
| 80 | + [:partition] |
| 81 | + [:pause :kill :partition :clock]]) |
| 82 | + |
| 83 | +(def special-nemeses |
| 84 | + "A map of special nemesis names to collections of faults" |
| 85 | + {:none [] |
| 86 | + :standard [:pause :kill :partition :clock :member] |
| 87 | + :all [:pause :kill :partition :clock :member]}) |
| 88 | + |
| 89 | +(defn parse-nemesis-spec |
| 90 | + "Takes a comma-separated nemesis string and returns a collection of keyword |
| 91 | + faults." |
| 92 | + [spec] |
| 93 | + (->> (str/split spec #",") |
| 94 | + (map keyword) |
| 95 | + (mapcat #(get special-nemeses % [%])))) |
| 96 | + |
67 | 97 | (def cli-opts
|
68 | 98 | "Options for test runners."
|
69 | 99 | [["-v" "--version VERSION"
|
|
73 | 103 | :parse-fn keyword
|
74 | 104 | :missing (str "--workload " (cli/one-of workloads))
|
75 | 105 | :validate [workloads (cli/one-of workloads)]]
|
| 106 | + [nil "--nemesis FAULTS" "A comma-separated list of nemesis faults to enable" |
| 107 | + :parse-fn parse-nemesis-spec |
| 108 | + :validate [(partial every? (into nemeses (keys special-nemeses))) |
| 109 | + (str "Faults must be one of " nemeses " or " |
| 110 | + (cli/one-of special-nemeses))]] |
| 111 | + [nil "--nemesis-interval SECONDS" "How long to wait between nemesis faults" |
| 112 | + :default 3 |
| 113 | + :parse-fn read-string |
| 114 | + :validate [#(and (number? %) (pos? %)) "must be a positive number"]] |
76 | 115 | ["-e" "--engine NAME"
|
77 | 116 | "What Tarantool data engine should we use?"
|
78 | 117 | :default "memtx"]])
|
79 | 118 |
|
80 | 119 | (def crash-pattern
|
81 | 120 | "An egrep pattern we use to find crashes in the Tarantool logs."
|
82 |
| - "Segmentation fault|too long WAL write|F>") |
| 121 | + "Segmentation fault|too long WAL write|F>|ER_TUPLE_FOUND") |
83 | 122 |
|
84 | 123 | (defn logged-crashes
|
85 | 124 | "Takes a test, and returns a map of nodes to strings from their Tarantool logs
|
|
112 | 151 | (defn tarantool-test
|
113 | 152 | [opts]
|
114 | 153 | (let [workload ((get workloads (:workload opts)) opts)
|
115 |
| - nemesis nemesis/noop |
| 154 | + nemesis (nemesis/nemesis-package |
| 155 | + {:db db/db |
| 156 | + :nodes (:nodes opts) |
| 157 | + :faults (:nemesis opts) |
| 158 | + :partition {:targets [:primaries]} |
| 159 | + :pause {:targets [nil :one :primaries :majority :all]} |
| 160 | + :kill {:targets [nil :one :primaries :majority :all]} |
| 161 | + :interval (:nemesis-interval opts)}) |
| 162 | + _ (info (pr-str nemesis)) |
116 | 163 | gen (->> (:generator workload)
|
117 | 164 | (gen/nemesis (:generator nemesis))
|
118 | 165 | (gen/time-limit (:time-limit opts)))
|
|
126 | 173 | (merge tests/noop-test
|
127 | 174 | opts
|
128 | 175 | {:client (:client workload)
|
129 |
| - :nemesis nemesis |
| 176 | + :nemesis (:nemesis nemesis) |
130 | 177 | :name (str "tarantool-" (:version opts))
|
131 | 178 | :os ubuntu/os
|
132 | 179 | :db (db/db (:version opts))
|
133 | 180 | :engine (:engine opts)
|
134 | 181 | :pure-generators true
|
135 | 182 | :generator gen
|
136 |
| - :checker (checker/compose {:perf (checker/perf) |
| 183 | + :checker (checker/compose {:perf (checker/perf {:nemeses (:perf nemesis)}) |
137 | 184 | :clock-skew (checker/clock-plot)
|
138 | 185 | :crash (crash-checker)
|
139 | 186 | :timeline (timeline/html)
|
140 | 187 | :stats (checker/stats)
|
141 | 188 | :exceptions (checker/unhandled-exceptions)
|
142 | 189 | :workload (:checker workload)})})))
|
143 | 190 |
|
| 191 | +(defn all-tests |
| 192 | + "Takes parsed CLI options and constructs a sequence of test options, by |
| 193 | + combining all workloads and nemeses." |
| 194 | + [opts] |
| 195 | + (let [nemeses (if-let [n (:nemesis opts)] [n] standard-nemeses) |
| 196 | + workloads (if-let [w (:workload opts)] [w] standard-workloads) |
| 197 | + counts (range (:test-count opts))] |
| 198 | + (->> (for [i counts, n nemeses, w workloads] |
| 199 | + (assoc opts :nemesis n :workload w)) |
| 200 | + (map tarantool-test)))) |
| 201 | + |
144 | 202 | (defn -main
|
145 | 203 | "Handles command line arguments."
|
146 | 204 | [& args]
|
147 | 205 | (cli/run! (merge (cli/single-test-cmd {:test-fn tarantool-test
|
148 | 206 | :opt-spec cli-opts})
|
| 207 | + (cli/test-all-cmd {:test-fn all-tests |
| 208 | + :opt-spec cli-opts}) |
149 | 209 | (cli/serve-cmd))
|
150 | 210 | args))
|
0 commit comments