Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a32263d
test(jepsen): add ZSet safety workload with model-based checker
bootjp Apr 19, 2026
2693a30
ci(jepsen): run ZSet safety workload in per-push and scheduled jobs
bootjp Apr 19, 2026
94be1bd
fix(jepsen-zset-safety): plug checker false positives + add unit tests
bootjp Apr 19, 2026
9bfcc13
fix(jepsen-zset-safety): no-op-ZREM-only member must not trigger :sco…
bootjp Apr 20, 2026
6d0b4c3
fix(jepsen-zset-safety): address CodeRabbit checker soundness issues
bootjp Apr 20, 2026
86d23dd
Merge branch 'main' into feat/jepsen-zset-safety
bootjp Apr 21, 2026
ecb3983
fix(jepsen): correct ZSet checker for infinity, stale reads, and :inf…
bootjp Apr 22, 2026
2a194a4
fix(jepsen): accept linearization of concurrent ops and uncertain mut…
bootjp Apr 22, 2026
49c5e0c
Merge branch 'main' into feat/jepsen-zset-safety
bootjp Apr 22, 2026
0c0efc4
fix(jepsen): keep strict score check when concurrent ZINCRBY score is…
bootjp Apr 22, 2026
e5dcc34
fix(jepsen): exclude :fail completions from concurrent mutation uncer…
bootjp Apr 22, 2026
02a8adf
fix(jepsen): restrict committed ZINCRBY candidates to linearization-c…
bootjp Apr 22, 2026
da85560
fix(jepsen): restrict unknown-score? to :info zincrby, not any concur…
bootjp Apr 23, 2026
502f64a
fix(jepsen): guard setup! and ZINCRBY response parsing against nil/mi…
bootjp Apr 23, 2026
33d59c5
fix(jepsen): restrict can-be-present? existence evidence to ZADD/ZINCRBY
bootjp Apr 23, 2026
9535ff3
fix(jepsen): correct clojure.tools.logging/warn call style in zset wo…
bootjp Apr 23, 2026
fde116c
fix(jepsen): decode Redis ZSET member bytes as UTF-8 explicitly
bootjp Apr 23, 2026
0c948a2
fix(jepsen-zset): hard-fail setup! when :conn-spec is missing
bootjp Apr 23, 2026
84989f1
fix(jepsen-zset): prepend test subcommand only when absent or an option
bootjp Apr 23, 2026
7a7a218
fix(jepsen-zset): document why :final-generator is overridden to nil
bootjp Apr 23, 2026
6219831
fix(jepsen-zset): guard ZREM nil reply to avoid NPE in invoke!
bootjp Apr 23, 2026
e67d29f
fix(jepsen-zset): return :valid? :unknown when no successful reads
bootjp Apr 23, 2026
623d5c2
fix(jepsen-zset): hard-fail setup! when cleanup DEL errors
bootjp Apr 23, 2026
22e41e1
fix(jepsen-zset): guard nil .getMessage on exception :error fields
bootjp Apr 23, 2026
9f5e958
docs(jepsen-zset): strip LLM reviewer artifact markers from comments
bootjp Apr 23, 2026
d0c8a03
fix(jepsen-zset): let inner workload's :final-generator pass through
bootjp Apr 23, 2026
559e83d
fix(jepsen-zset): reject odd-length WITHSCORES replies
bootjp Apr 23, 2026
1a9370f
fix(jepsen-zset): coerce ZREM count across Long / string / bytes
bootjp Apr 23, 2026
ad9079c
fix(jepsen-zset): include full :allowed set in missing-member-range
bootjp Apr 23, 2026
69db24e
fix(jepsen-zset): catch Throwable in invoke! so Errors don't crash wo…
bootjp Apr 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/jepsen-test-scheduled.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ jobs:
--max-txn-length ${{ inputs.max-txn-length || '4' }} \
--ports 63791,63792,63793 \
--host 127.0.0.1
- name: Run Redis ZSet safety Jepsen workload against elastickv
working-directory: jepsen
timeout-minutes: 10
run: |
timeout 480 ~/lein run -m elastickv.redis-zset-safety-workload \
--time-limit ${{ inputs.time-limit || '150' }} \
--rate ${{ inputs.rate || '10' }} \
--concurrency ${{ inputs.concurrency || '8' }} \
--ports 63791,63792,63793 \
--host 127.0.0.1
- name: Run DynamoDB Jepsen workload against elastickv
working-directory: jepsen
timeout-minutes: 10
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/jepsen-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ jobs:
timeout-minutes: 3
run: |
timeout 120 ~/lein run -m elastickv.redis-workload --time-limit 5 --rate 5 --concurrency 5 --ports 63791,63792,63793 --host 127.0.0.1
- name: Run Redis ZSet safety Jepsen workload against elastickv
working-directory: jepsen
timeout-minutes: 3
run: |
timeout 120 ~/lein run -m elastickv.redis-zset-safety-workload --time-limit 5 --rate 5 --concurrency 5 --ports 63791,63792,63793 --host 127.0.0.1
- name: Run DynamoDB Jepsen workload against elastickv
working-directory: jepsen
timeout-minutes: 3
Expand Down
50 changes: 49 additions & 1 deletion jepsen/src/elastickv/jepsen_test.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(ns elastickv.jepsen-test
(:gen-class)
(:require [elastickv.redis-workload :as redis-workload]
[elastickv.redis-zset-safety-workload :as zset-safety-workload]
[elastickv.dynamodb-workload :as dynamodb-workload]
[elastickv.s3-workload :as s3-workload]
[jepsen.cli :as cli]))
Expand All @@ -14,6 +15,53 @@
(defn elastickv-s3-test []
(s3-workload/elastickv-s3-test {}))

(defn elastickv-zset-safety-test []
(zset-safety-workload/elastickv-zset-safety-test {}))

(def ^:private test-fns
"Map of user-facing test names to their constructor fns. The first
positional CLI arg selects which workload runs; if absent or unknown,
we default to `elastickv-test` for backward compatibility with
pre-existing invocations."
{"elastickv-test" elastickv-test
"elastickv-zset-safety-test" elastickv-zset-safety-test
"elastickv-dynamodb-test" elastickv-dynamodb-test
"elastickv-s3-test" elastickv-s3-test})

(defn -main
"Dispatch to a named workload. Usage:

lein run -m elastickv.jepsen-test <test-name> [jepsen-subcmd] [jepsen-opts ...]

Supported <test-name>s: elastickv-test, elastickv-zset-safety-test,
elastickv-dynamodb-test, elastickv-s3-test. When the first positional
arg is not a known test name, we default to `elastickv-test` for
backward compatibility and forward ALL args to jepsen.cli/run!.

The jepsen subcommand (`test` or `analyze`) is auto-prepended when
missing, so `lein run elastickv-zset-safety-test --nodes n1,n2` works
without the user repeating `test`."
[& args]
(cli/run! (cli/single-test-cmd {:test-fn elastickv-test}) args))
(let [[head & tail] args
[selected-fn remaining-args] (if-let [f (get test-fns head)]
[f tail]
[elastickv-test args])
;; jepsen.cli/run! requires a subcommand ("test" or "analyze")
;; as the first arg. Insert "test" only when the user clearly
;; did NOT supply a subcommand:
;; - remaining-args is empty, OR
;; - the first token is an option (starts with "-")
;; If the first token looks like a subcommand (any non-option
;; word, e.g. "test", "analyze", "serve", or a future jepsen.cli
;; subcommand we don't hard-code), leave it alone and let
;; jepsen.cli/run! handle it (including producing a better
;; error message for unknown subcommands than we could here).
[next-head & _] remaining-args
prepend-test? (or (empty? remaining-args)
(and (string? next-head)
(.startsWith ^String next-head "-")))
final-args (if prepend-test?
(cons "test" remaining-args)
remaining-args)]
(cli/run! (cli/single-test-cmd {:test-fn selected-fn})
final-args)))
Loading
Loading