From 67e479a4e2ddf4ce6a5fe4a46d01863279ef2727 Mon Sep 17 00:00:00 2001
From: Yaroslav Dynnikov <yaroslav.dynnikov@gmail.com>
Date: Tue, 22 Feb 2022 12:02:24 +0300
Subject: [PATCH] test: make luatest more concise

---
 test/couple_test.lua     | 22 ++--------------
 test/helper/picodata.lua | 55 ++++++++++++++++++++++++++++++++++++++++
 test/single_test.lua     | 37 +++++----------------------
 3 files changed, 63 insertions(+), 51 deletions(-)

diff --git a/test/couple_test.lua b/test/couple_test.lua
index d65b282110..5ac01d63a9 100644
--- a/test/couple_test.lua
+++ b/test/couple_test.lua
@@ -39,28 +39,10 @@ end)
 
 g.test = function()
     -- Speed up node election
-    g.cluster.i1:interact({
-        msg_type = "MsgTimeoutNow",
-        to = 1,
-        from = 0,
-    })
-
-    h.retrying({}, function()
-        t.assert_equals(
-            g.cluster.i2:connect():call('picolib.raft_status'),
-            {
-                id = 2,
-                leader_id = 1,
-                raft_state = "Follower",
-            }
-        )
-    end)
+    g.cluster.i1:try_promote()
 
     t.assert_equals(
-        g.cluster.i2:connect():call(
-            'picolib.raft_propose_eval',
-            {1, '_G.check = box.info.listen'}
-        ),
+        g.cluster.i2:raft_propose_eval(1, '_G.check = box.info.listen'),
         true
     )
     t.assert_equals(
diff --git a/test/helper/picodata.lua b/test/helper/picodata.lua
index 90eabb1502..275c8605fa 100644
--- a/test/helper/picodata.lua
+++ b/test/helper/picodata.lua
@@ -18,6 +18,7 @@ local Picodata = {
     command = 'target/debug/picodata',
     process = nil,
     __type = 'Picodata',
+    id = -1,
 }
 
 function Picodata:inherit(object)
@@ -82,6 +83,7 @@ function Picodata:start()
 
     luatest.helpers.retrying({}, function()
         self:connect()
+        self.id = self:raft_status().id
     end)
 
 end
@@ -124,6 +126,42 @@ function Picodata:stop()
     self.process = nil
 end
 
+--- Get the status of raft node.
+-- @function
+-- @return {id = number, leader_id = number, state = string}
+--   State can be one of "Follower", "Candidate", "Leader", "PreCandidate".
+function Picodata:raft_status()
+    checks('Picodata')
+    return self:connect():call('picolib.raft_status')
+end
+
+--- Assert raft status matches expectations.
+-- @function
+-- @tparam string raft_state
+-- @tparam[opt] number leader_id
+function Picodata:assert_raft_status(raft_state, leader_id)
+    checks('Picodata', 'string', '?number')
+    return luatest.assert_covers(
+        self:raft_status(),
+        {
+            leader_id = leader_id,
+            raft_state = raft_state,
+        }
+    )
+end
+
+--- Propose Lua code evaluation on every node in cluster.
+-- @tparam number timeout
+-- @tparam string code
+-- @treturn boolean whether proposal was committed on the current node.
+function Picodata:raft_propose_eval(timeout, code)
+    checks('Picodata', 'number', 'string')
+    return self:connect():call(
+        'picolib.raft_propose_eval',
+        {timeout, code}
+    )
+end
+
 function Picodata:interact(opts)
     checks('Picodata', {
         -- See picolib/traft/row/message.rs
@@ -156,4 +194,21 @@ function Picodata:interact(opts)
     })
 end
 
+--- Try forcing leader election when previous leader is dead.
+-- Wait for the node becoming a leader.
+-- Raise an exception if promotion fails.
+function Picodata:try_promote()
+    checks('Picodata')
+
+    self:interact({
+        msg_type = "MsgTimeoutNow",
+        to = self.id,
+        from = 0,
+    })
+
+    return luatest.helpers.retrying({}, function()
+        self:assert_raft_status("Leader", self.id)
+    end)
+end
+
 return Picodata
diff --git a/test/single_test.lua b/test/single_test.lua
index 470372faf8..47be6a3c7e 100644
--- a/test/single_test.lua
+++ b/test/single_test.lua
@@ -22,51 +22,26 @@ g.after_all(function()
 end)
 
 g.test = function()
-    local conn = g.node:connect()
+    g.node:assert_raft_status("Follower")
 
     t.assert_equals(
-        conn:call('picolib.raft_status'),
-        {
-            id = 1,
-            leader_id = 0,
-            raft_state = "Follower",
-        }
-    )
-
-    t.assert_equals(
-        conn:call('picolib.raft_propose_eval', {1, 'return'}),
+        g.node:raft_propose_eval(1, 'return'),
         false -- No leader is elected yet
     )
 
-    -- Speed up node election
-    g.node:interact({
-        msg_type = "MsgTimeoutNow",
-        to = 1,
-        from = 0,
-    })
-
-    h.retrying({}, function()
-        t.assert_equals(
-            conn:call('picolib.raft_status'),
-            {
-                id = 1,
-                leader_id = 1,
-                raft_state = "Leader",
-            }
-        )
-    end)
+    g.node:try_promote()
 
     t.assert_equals(
-        conn:call('picolib.raft_propose_eval', {0, 'return'}),
+        g.node:raft_propose_eval(0, 'return'),
         false -- Timeout
     )
 
     t.assert_equals(
-        conn:call('picolib.raft_propose_eval', {1, '_G.success = true'}),
+        g.node:raft_propose_eval(1, '_G.success = true'),
         true
     )
     t.assert_equals(
-        conn:eval('return success'),
+        g.node:connect():eval('return success'),
         true
     )
 end
-- 
GitLab