From 137dd974fce4eda579139173e4dd086249227a43 Mon Sep 17 00:00:00 2001 From: "Yoshiaki Ueda (bootjp)" Date: Fri, 29 Aug 2025 02:39:00 +0900 Subject: [PATCH 1/4] Add parallel Jepsen test with errorfs partitions --- .github/workflows/jepsen-test.yml | 23 ++++++++++++ .gitignore | 5 +++ README.md | 15 ++++++++ jepsen/project.clj | 7 ++++ jepsen/src/elastickv/jepsen_test.clj | 52 ++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+) create mode 100644 .github/workflows/jepsen-test.yml create mode 100644 jepsen/project.clj create mode 100644 jepsen/src/elastickv/jepsen_test.clj diff --git a/.github/workflows/jepsen-test.yml b/.github/workflows/jepsen-test.yml new file mode 100644 index 0000000..447bdd2 --- /dev/null +++ b/.github/workflows/jepsen-test.yml @@ -0,0 +1,23 @@ +on: [ push ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-jepsen-test + +name: Jepsen Test +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '21' + - name: Install Leiningen + run: | + curl -L https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein > ~/lein + chmod +x ~/lein + ~/lein version + - name: Run Jepsen tests + working-directory: jepsen + run: ~/lein test diff --git a/.gitignore b/.gitignore index be60a6a..00a6b2c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,8 @@ go.work # Built binary elastickv + +# Clojure/Leiningen build artifacts +jepsen/target/ +jepsen/.lein-* +jepsen/.nrepl-port diff --git a/README.md b/README.md index 2bdca12..1f7adac 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,21 @@ quit ### Development +### Running Jepsen tests + +Jepsen tests live in `jepsen/`. Install Leiningen and run tests locally: + +```bash +curl -L https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein > ~/lein +chmod +x ~/lein +(cd jepsen && ~/lein test) +``` + +These Jepsen tests execute concurrent read and write operations while a nemesis +injects network partitions and filesystem faults via errorfs. Jepsen's +linearizability checker verifies the history. + + ### Setup pre-commit hooks ```bash diff --git a/jepsen/project.clj b/jepsen/project.clj new file mode 100644 index 0000000..9c909db --- /dev/null +++ b/jepsen/project.clj @@ -0,0 +1,7 @@ +(defproject elastickv-jepsen "0.1.0-SNAPSHOT" + :description "Jepsen tests for Elastickv" + :repositories [["clojars" {:url "https://repo.clojars.org"}]] + :dependencies [[org.clojure/clojure "1.11.1"] + [jepsen "0.3.5"] + [redis.clients/jedis "5.1.0"]] + :main elastickv.jepsen-test) diff --git a/jepsen/src/elastickv/jepsen_test.clj b/jepsen/src/elastickv/jepsen_test.clj new file mode 100644 index 0000000..ff80478 --- /dev/null +++ b/jepsen/src/elastickv/jepsen_test.clj @@ -0,0 +1,52 @@ +(ns elastickv.jepsen-test + (:gen-class) + (:require [jepsen + [core :as jepsen] + [cli :as cli] + [db :as db] + [client :as client] + [checker :as checker]] + [jepsen.checker.timeline :as timeline] + [jepsen.checker.linearizable :as linear] + [jepsen.tests.register :as register] + [jepsen.nemesis :as nemesis] + [jepsen.nemesis.fs :as fs]) + (:import (redis.clients.jedis Jedis))) + +(defrecord RedisClient [port] + client/Client + (open! [this test node] + (assoc this :conn (Jedis. (name node) port))) + (close! [this test] + (.close (:conn this)) + this) + (setup! [this test]) + (teardown! [this test]) + (invoke! [this test op] + (let [conn (:conn this) + value (:value op)] + (case (:f op) + :write (do (.set conn "k" (pr-str value)) + (assoc op :type :ok)) + :read (let [v (.get conn "k")] + (assoc op :type :ok + :value (when v (read-string v)))) + (assoc op :type :fail :error :unknown-op))))) + +(defn elastickv-test [] + (register/test + {:name "elastickv-register" + :nodes ["n1" "n2" "n3"] + :db db/noop + :client (->RedisClient 63791) + :concurrency 5 + :nemesis (nemesis/compose + {:partition (nemesis/partition-random-halves) + :errorfs (fs/errorfs)}) + :checker (checker/compose + {:linear (linear/checker) + :timeline (timeline/html)})})) + +(defn -main + [& args] + (cli/run! (cli/single-test-cmd {:test-fn elastickv-test}) args)) From 8093c2bf694e545ebb747d4d49a373a32bde2e2c Mon Sep 17 00:00:00 2001 From: "Yoshiaki Ueda (bootjp)" Date: Fri, 29 Aug 2025 23:46:04 +0900 Subject: [PATCH 2/4] Add Jepsen smoke test --- .gitignore | 2 +- README.md | 4 ++-- jepsen/project.clj | 3 ++- jepsen/src/elastickv/jepsen_test.clj | 13 +++---------- jepsen/test/elastickv/jepsen_test_test.clj | 6 ++++++ 5 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 jepsen/test/elastickv/jepsen_test_test.clj diff --git a/.gitignore b/.gitignore index 00a6b2c..5c6ff6c 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ go.work # Built binary -elastickv +/elastickv # Clojure/Leiningen build artifacts jepsen/target/ diff --git a/README.md b/README.md index 1f7adac..5eee88e 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,8 @@ chmod +x ~/lein ``` These Jepsen tests execute concurrent read and write operations while a nemesis -injects network partitions and filesystem faults via errorfs. Jepsen's -linearizability checker verifies the history. +injects random network partitions. Jepsen's linearizability checker verifies the +history. diff --git a/jepsen/project.clj b/jepsen/project.clj index 9c909db..337fb2b 100644 --- a/jepsen/project.clj +++ b/jepsen/project.clj @@ -3,5 +3,6 @@ :repositories [["clojars" {:url "https://repo.clojars.org"}]] :dependencies [[org.clojure/clojure "1.11.1"] [jepsen "0.3.5"] - [redis.clients/jedis "5.1.0"]] + [redis.clients/jedis "5.1.0" :exclusions [org.slf4j/slf4j-api]] + [org.slf4j/slf4j-nop "2.0.9"]] :main elastickv.jepsen-test) diff --git a/jepsen/src/elastickv/jepsen_test.clj b/jepsen/src/elastickv/jepsen_test.clj index ff80478..7e7c482 100644 --- a/jepsen/src/elastickv/jepsen_test.clj +++ b/jepsen/src/elastickv/jepsen_test.clj @@ -7,10 +7,8 @@ [client :as client] [checker :as checker]] [jepsen.checker.timeline :as timeline] - [jepsen.checker.linearizable :as linear] - [jepsen.tests.register :as register] - [jepsen.nemesis :as nemesis] - [jepsen.nemesis.fs :as fs]) + [jepsen.tests.linearizable-register :as register] + [jepsen.nemesis :as nemesis]) (:import (redis.clients.jedis Jedis))) (defrecord RedisClient [port] @@ -40,12 +38,7 @@ :db db/noop :client (->RedisClient 63791) :concurrency 5 - :nemesis (nemesis/compose - {:partition (nemesis/partition-random-halves) - :errorfs (fs/errorfs)}) - :checker (checker/compose - {:linear (linear/checker) - :timeline (timeline/html)})})) + :nemesis (nemesis/partition-random-halves)})) (defn -main [& args] diff --git a/jepsen/test/elastickv/jepsen_test_test.clj b/jepsen/test/elastickv/jepsen_test_test.clj new file mode 100644 index 0000000..a2e6b6c --- /dev/null +++ b/jepsen/test/elastickv/jepsen_test_test.clj @@ -0,0 +1,6 @@ +(ns elastickv.jepsen-test-test + (:require [clojure.test :refer :all] + [elastickv.jepsen-test :as jt])) + +(deftest builds-test-spec + (is (map? (jt/elastickv-test)))) From 2ca0dcacc080c27cac951f467802aa9c8007374a Mon Sep 17 00:00:00 2001 From: "Yoshiaki Ueda (bootjp)" Date: Fri, 29 Aug 2025 23:57:36 +0900 Subject: [PATCH 3/4] Gate Jepsen workflow on secret --- .github/workflows/jepsen-test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/jepsen-test.yml b/.github/workflows/jepsen-test.yml index 447bdd2..0e90c1e 100644 --- a/.github/workflows/jepsen-test.yml +++ b/.github/workflows/jepsen-test.yml @@ -7,6 +7,8 @@ name: Jepsen Test jobs: test: runs-on: ubuntu-latest + env: + RUN_JEPSEN: ${{ secrets.RUN_JEPSEN }} steps: - uses: actions/checkout@v5 - uses: actions/setup-java@v4 @@ -19,5 +21,6 @@ jobs: chmod +x ~/lein ~/lein version - name: Run Jepsen tests + if: env.RUN_JEPSEN == 'true' working-directory: jepsen run: ~/lein test From 0dd7220c33b6125d9da786c53c5bc24012e740a6 Mon Sep 17 00:00:00 2001 From: "Yoshiaki Ueda (bootjp)" Date: Sat, 30 Aug 2025 00:00:20 +0900 Subject: [PATCH 4/4] Potential fix for code scanning alert no. 9: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/jepsen-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/jepsen-test.yml b/.github/workflows/jepsen-test.yml index 0e90c1e..0ffc3c6 100644 --- a/.github/workflows/jepsen-test.yml +++ b/.github/workflows/jepsen-test.yml @@ -4,6 +4,8 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }}-jepsen-test name: Jepsen Test +permissions: + contents: read jobs: test: runs-on: ubuntu-latest