Add basic state machine test etc.
This commit is contained in:
parent
0f5ce4687b
commit
7017e9fc69
|
@ -42,10 +42,10 @@ type
|
|||
|
||||
|
||||
# Raft Node Abstract State Machine type
|
||||
RaftNodeStateMachine*[SmCommandType, SmStateType] = object # Some opaque State Machine Impelementation to be used by the Raft Node
|
||||
RaftNodeStateMachine*[SmCommandType, SmStateType] = ref object # Some opaque State Machine Impelementation to be used by the Raft Node
|
||||
# providing at minimum operations for initialization, querying the current state
|
||||
# and RaftNodeLogEntry (SmCommandType) application
|
||||
state: SmStateType
|
||||
state*: ref SmStateType
|
||||
|
||||
# Raft Node Persistent Storage basic definition
|
||||
RaftNodePersistentStorage*[SmCommandType, SmStateType] = object # Should be some kind of Persistent Transactional Store Wrapper
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# nim-raft
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import ../raft/types
|
||||
import std/tables
|
||||
|
||||
export tables
|
||||
|
||||
type
|
||||
SmState* = Table[string, string]
|
||||
|
||||
SmCommands* = enum
|
||||
scSet = 0,
|
||||
scDel = 1
|
||||
|
||||
SmCommand* = object
|
||||
cmd*: SmCommands
|
||||
key*: string
|
||||
val*: string
|
||||
|
||||
RaftBasicSm* = RaftNodeStateMachine[SmCommand, SmState]
|
||||
|
||||
proc RaftSmInit*(stateMachine: var RaftBasicSm) =
|
||||
new(stateMachine)
|
||||
new(stateMachine.state)
|
||||
|
||||
proc RaftSmApply*(stateMachine: RaftBasicSm, command: SmCommand) =
|
||||
case command.cmd:
|
||||
of scSet:
|
||||
stateMachine.state[command.key] = command.val
|
||||
of scDel:
|
||||
stateMachine.state.del(command.key)
|
|
@ -0,0 +1,50 @@
|
|||
# nim-raft
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import unittest2
|
||||
import ../raft/types
|
||||
import basic_state_machine
|
||||
|
||||
proc smRunner() =
|
||||
var
|
||||
sm: RaftBasicSm
|
||||
smCommandsLog: seq[SmCommand]
|
||||
|
||||
suite "Test Basic State Machine Implementation":
|
||||
|
||||
test "Test Init":
|
||||
RaftSmInit(sm)
|
||||
|
||||
check sm != nil and sm.state != nil and sm.state.len == 0
|
||||
|
||||
test "Init commands":
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "a", val: "a"))
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "b", val: "b"))
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "c", val: "c"))
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "d", val: "d"))
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "e", val: "e"))
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "f", val: "f"))
|
||||
smCommandsLog.add(SmCommand(cmd: scDel, key: "a"))
|
||||
smCommandsLog.add(SmCommand(cmd: scDel, key: "a"))
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "a", val: "a"))
|
||||
smCommandsLog.add(SmCommand(cmd: scDel, key: "a"))
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "g", val: "g"))
|
||||
smCommandsLog.add(SmCommand(cmd: scDel, key: "d"))
|
||||
smCommandsLog.add(SmCommand(cmd: scSet, key: "h", val: "h"))
|
||||
|
||||
check smCommandsLog.len == 13
|
||||
|
||||
test "Apply commands and check result":
|
||||
for c in smCommandsLog:
|
||||
RaftSmApply(sm, c)
|
||||
|
||||
check sm.state[] == {"b": "b", "c": "c", "e": "e", "f": "f", "g": "g", "h": "h"}.toTable
|
||||
|
||||
if isMainModule:
|
||||
smRunner()
|
|
@ -19,6 +19,9 @@ var
|
|||
runningMtx: Lock
|
||||
running: bool
|
||||
|
||||
timersChan: seq[RaftTimer]
|
||||
timersChanMtx: Lock
|
||||
|
||||
proc RaftTimerCreateCustomImpl*(timerInterval: int, oneshot: bool, timerCallback: RaftTimerCallback): RaftTimer {.nimcall, gcsafe.} =
|
||||
var
|
||||
timer = RaftTimer(mtx: Lock(), canceled: false, expired: false, timeout: timerInterval, oneshot: oneshot)
|
||||
|
@ -49,15 +52,15 @@ proc RaftTimerCancelCustomImpl*(timer: RaftTimer): bool {.nimcall, gcsafe, disca
|
|||
proc RaftTimerPollThread() {.thread, nimcall, gcsafe.} =
|
||||
while running:
|
||||
try:
|
||||
|
||||
withLock(timersChanMtx):
|
||||
debugEcho timersChan.len
|
||||
poll()
|
||||
debugEcho activeDescriptors()
|
||||
except ValueError as e:
|
||||
debugEcho e.msg
|
||||
# Add a 'dummy' timer if no other handles are present to prevent more
|
||||
# ValueError exceptions this is a workaround for a asyncdyspatch bug
|
||||
# see - https://github.com/nim-lang/Nim/issues/14564
|
||||
addTimer(10000, false, proc (fd: AsyncFD): bool {.closure, gcsafe.} = false)
|
||||
addTimer(1, true, proc (fd: AsyncFD): bool {.closure, gcsafe.} = true)
|
||||
|
||||
proc RaftTimerJoinPollThread*() {.nimcall, gcsafe.} =
|
||||
joinThread(pollThr)
|
||||
|
|
Loading…
Reference in New Issue