Add sequential test (#66)

This commit is contained in:
antonio2368 2020-12-18 12:19:30 +01:00 committed by Antonio Andelic
parent adc355a22a
commit 855c2ea9ca
2 changed files with 164 additions and 1 deletions

View File

@ -12,6 +12,7 @@
[slingshot.slingshot :refer [try+ throw+]]
[jepsen.memgraph [basic :as basic]
[bank :as bank]
[sequential :as sequential]
[support :as s]
[nemesis :as nemesis]
[edn :as e]]))
@ -19,7 +20,8 @@
(def workloads
"A map of workload names to functions that can take opts and construct
workloads."
{:bank bank/workload})
{:bank bank/workload
:sequential sequential/workload})
(def nemesis-configuration
"Nemesis configuration"

View File

@ -0,0 +1,161 @@
(ns jepsen.memgraph.sequential
"Sequential test"
(:require [neo4j-clj.core :as dbclient]
[clojure.tools.logging :refer [info]]
[jepsen [client :as client]
[checker :as checker]
[generator :as gen]]
[jepsen.checker.timeline :as timeline]
[jepsen.memgraph.client :as c]))
(dbclient/defquery get-all-nodes
"MATCH (n:Node) RETURN n;")
(dbclient/defquery get-max-id
"MATCH (n:Node)
RETURN n.id AS id
ORDER BY id DESC
LIMIT 1;")
(dbclient/defquery get-min-id
"MATCH (n:Node)
RETURN n.id AS id
ORDER BY id
LIMIT 1;")
(dbclient/defquery create-node
"CREATE (n:Node {id: $id});")
(dbclient/defquery delete-node-with-id
"MATCH (n:Node {id: $id}) DELETE n;")
(defn add-next-node
"Add a new node with its id set to the next highest"
[conn]
(dbclient/with-transaction conn tx
(let [max-id (-> (get-max-id tx) first :id)]
(create-node tx {:id (inc max-id)}))))
(defn delete-oldest-node
"Delete a node with the lowest id"
[conn]
(dbclient/with-transaction conn tx
(let [min-id (-> (get-min-id tx) first :id)]
(delete-node-with-id tx {:id min-id}))))
(c/replication-client Client []
(open! [this test node]
(c/replication-open-connection this node node-config))
(setup! [this test]
(when (= replication-role :main)
(c/with-session conn session
(c/detach-delete-all session)
(create-node session {:id 0}))))
(invoke! [this test op]
(c/replication-invoke-case (:f op)
:read (c/with-session conn session
(assoc op
:type :ok
:value {:ids (->> (get-all-nodes session)
(map #(-> % :n :id))
(reduce conj []))
:node node}))
:add (if (= replication-role :main)
(try
(assoc op :type (if (add-next-node conn) :ok :fail))
(catch Exception e
; Transaction can fail on serialization errors
(assoc op :type :fail :info (str e))))
(assoc op :type :fail))
:delete (if (= replication-role :main)
(try
(assoc op :type (if (delete-oldest-node conn) :ok :fail))
(catch Exception e
; Transaction can fail on serialization errors
(assoc op :type :fail :info (str e))))
(assoc op :type :fail))))
(teardown! [this test]
(when (= replication-role :main)
(c/with-session conn session
(c/detach-delete-all session))))
(close! [_ est]
(dbclient/disconnect conn)))
(defn add-node
"Add node with id set to current_max_id + 1"
[test process]
{:type :invoke :f :add :value nil})
(defn read-ids
"Read all current ids of nodes"
[test process]
{:type :invoke :f :read :value nil})
(defn delete-node
"Delete node with the lowest id"
[test process]
{:type :invoke :f :delete :value nil})
(defn strictly-increasing
[coll]
(every?
#(< (first %) (second %))
(partition 2 1 coll)))
(defn increased-by-1
[coll]
(every?
#(= (inc (first %)) (second %))
(partition 2 1 coll)))
(defn sequential-checker
"Check if all nodes have nodes with ids that are strictly increasing by 1.
All nodes need to have at leas 1 non-empty read."
[]
(reify checker/Checker
(check [this test history opts]
(let [ok-reads (->> history
(filter #(= :ok (:type %)))
(filter #(= :read (:f %))))
bad-reads (->> ok-reads
(map (fn [op]
(let [ids (-> op :value :ids)]
(when (not-empty ids)
(cond ((complement strictly-increasing) ids)
{:type :not-increasing-ids
:op op}
((complement increased-by-1) ids)
{:type :ids-missing
:op op})))))
(filter identity)
(into []))
empty-nodes (let [all-nodes (->> ok-reads
(map #(-> % :value :node))
(reduce conj #{}))]
(->> all-nodes
(filter (fn [node]
(every?
empty?
(->> ok-reads
(map :value)
(filter #(= node (:node %)))
(map :ids)))))
(filter identity)
(into [])))]
{:valid? (and
(empty? bad-reads)
(empty? empty-nodes))
:empty-nodes empty-nodes
:bad-reads bad-reads}))))
(defn workload
[opts]
{:client (Client. nil nil nil (:node-config opts))
:checker (checker/compose
{:sequential (sequential-checker)
:timeline (timeline/html)})
:generator (c/replication-gen
(gen/phases (cycle [(gen/time-limit 1 (gen/mix [read-ids add-node]))
(gen/once delete-node)])))
:final-generator (gen/once read-ids)})