166 lines
5.0 KiB
Nim
166 lines
5.0 KiB
Nim
import std/sets
|
|
import std/sequtils
|
|
import std/sugar
|
|
import std/times
|
|
import pkg/asynctest
|
|
import pkg/chronos
|
|
import pkg/codex/sales
|
|
import pkg/codex/sales/salesagent
|
|
import pkg/codex/sales/salescontext
|
|
import pkg/codex/sales/statemachine
|
|
import pkg/codex/sales/states/errorhandling
|
|
import pkg/codex/proving
|
|
import ../helpers/mockmarket
|
|
import ../helpers/mockclock
|
|
import ../helpers/eventually
|
|
import ../examples
|
|
|
|
var onCancelCalled = false
|
|
var onFailedCalled = false
|
|
var onSlotFilledCalled = false
|
|
var onErrorCalled = false
|
|
|
|
type
|
|
MockState = ref object of SaleState
|
|
MockErrorState = ref object of ErrorHandlingState
|
|
|
|
method `$`*(state: MockState): string = "MockState"
|
|
|
|
method onCancelled*(state: MockState, request: StorageRequest): ?State =
|
|
onCancelCalled = true
|
|
|
|
method onFailed*(state: MockState, request: StorageRequest): ?State =
|
|
onFailedCalled = true
|
|
|
|
method onSlotFilled*(state: MockState, requestId: RequestId,
|
|
slotIndex: UInt256): ?State =
|
|
onSlotFilledCalled = true
|
|
|
|
method onError*(state: MockErrorState, err: ref CatchableError): ?State =
|
|
onErrorCalled = true
|
|
|
|
method run*(state: MockErrorState, machine: Machine): Future[?State] {.async.} =
|
|
raise newException(ValueError, "failure")
|
|
|
|
suite "Sales agent":
|
|
|
|
let availability = Availability.init(
|
|
size=100.u256,
|
|
duration=60.u256,
|
|
minPrice=600.u256
|
|
)
|
|
var request = StorageRequest(
|
|
ask: StorageAsk(
|
|
slots: 4,
|
|
slotSize: 100.u256,
|
|
duration: 60.u256,
|
|
reward: 10.u256,
|
|
),
|
|
content: StorageContent(
|
|
cid: "some cid"
|
|
),
|
|
expiry: (getTime() + initDuration(hours=1)).toUnix.u256
|
|
)
|
|
|
|
var agent: SalesAgent
|
|
var context: SalesContext
|
|
var slotIndex: UInt256
|
|
var market: MockMarket
|
|
var clock: MockClock
|
|
|
|
setup:
|
|
market = MockMarket.new()
|
|
clock = MockClock.new()
|
|
context = SalesContext(market: market, clock: clock)
|
|
slotIndex = 0.u256
|
|
onCancelCalled = false
|
|
onFailedCalled = false
|
|
onSlotFilledCalled = false
|
|
agent = newSalesAgent(context,
|
|
request.id,
|
|
slotIndex,
|
|
some availability,
|
|
some request)
|
|
request.expiry = (getTime() + initDuration(hours=1)).toUnix.u256
|
|
|
|
teardown:
|
|
await agent.stop()
|
|
|
|
test "can retrieve request":
|
|
agent = newSalesAgent(context,
|
|
request.id,
|
|
slotIndex,
|
|
some availability,
|
|
none StorageRequest)
|
|
market.requested = @[request]
|
|
await agent.retrieveRequest()
|
|
check agent.data.request == some request
|
|
|
|
test "subscribe assigns subscriptions/futures":
|
|
await agent.subscribe()
|
|
check not agent.data.cancelled.isNil
|
|
check not agent.data.failed.isNil
|
|
check not agent.data.fulfilled.isNil
|
|
check not agent.data.slotFilled.isNil
|
|
|
|
test "unsubscribe deassigns subscriptions/futures":
|
|
await agent.subscribe()
|
|
await agent.unsubscribe()
|
|
check agent.data.cancelled.isNil
|
|
check agent.data.failed.isNil
|
|
check agent.data.fulfilled.isNil
|
|
check agent.data.slotFilled.isNil
|
|
|
|
test "subscribe can be called multiple times, without overwriting subscriptions/futures":
|
|
await agent.subscribe()
|
|
let cancelled = agent.data.cancelled
|
|
let failed = agent.data.failed
|
|
let fulfilled = agent.data.fulfilled
|
|
let slotFilled = agent.data.slotFilled
|
|
await agent.subscribe()
|
|
check cancelled == agent.data.cancelled
|
|
check failed == agent.data.failed
|
|
check fulfilled == agent.data.fulfilled
|
|
check slotFilled == agent.data.slotFilled
|
|
|
|
test "unsubscribe can be called multiple times":
|
|
await agent.subscribe()
|
|
await agent.unsubscribe()
|
|
await agent.unsubscribe()
|
|
|
|
test "subscribe can be called when request expiry has lapsed":
|
|
# succeeds when agent.data.fulfilled.isNil
|
|
request.expiry = (getTime() - initDuration(seconds=1)).toUnix.u256
|
|
agent.data.request = some request
|
|
check agent.data.fulfilled.isNil
|
|
await agent.subscribe()
|
|
|
|
test "current state onCancelled called when cancel emitted":
|
|
let state = MockState.new()
|
|
agent.start(state)
|
|
await agent.subscribe()
|
|
clock.set(request.expiry.truncate(int64))
|
|
check eventually onCancelCalled
|
|
|
|
test "cancelled future is finished (cancelled) when fulfillment emitted":
|
|
agent.start(MockState.new())
|
|
await agent.subscribe()
|
|
market.emitRequestFulfilled(request.id)
|
|
check eventually agent.data.cancelled.cancelled()
|
|
|
|
test "current state onFailed called when failed emitted":
|
|
agent.start(MockState.new())
|
|
await agent.subscribe()
|
|
market.emitRequestFailed(request.id)
|
|
check eventually onFailedCalled
|
|
|
|
test "current state onSlotFilled called when slot filled emitted":
|
|
agent.start(MockState.new())
|
|
await agent.subscribe()
|
|
market.emitSlotFilled(request.id, slotIndex)
|
|
check eventually onSlotFilledCalled
|
|
|
|
test "ErrorHandlingState.onError can be overridden at the state level":
|
|
agent.start(MockErrorState.new())
|
|
check eventually onErrorCalled
|