mirror of
https://github.com/codex-storage/nim-codex.git
synced 2025-02-13 05:17:58 +00:00
* [purchasing] Simplify test * [utils] Move StorageRequest.example up one level * [purchasing] Load purchases from market * [purchasing] load purchase states * Implement myRequest() and getState() methods for OnChainMarket * [proofs] Fix intermittently failing tests Ensures that examples of proofs in tests are never of length 0; these are considered invalid proofs by the smart contract logic. * [contracts] Fix failing test With the new solidity contracts update, a contract can only be paid out after it started. * [market] Add method to get request end time * [purchasing] wait until purchase is finished Purchase.wait() would previously wait until purchase was started, now we wait until it is finished. * [purchasing] Handle 'finished' and 'failed' states * [marketplace] move to failed state once request fails - Add support for subscribing to request failure events. - Add supporting contract tests for subscribing to request failure events. - Allow the PurchaseStarted state to move to PurchaseFailure once a request failure event is emitted - Add supporting tests for moving from PurchaseStarted to PurchaseFailure - Add state transition tests for PurchaseUnknown. * [marketplace] Fix test with longer sleepAsync * [integration] Add function to restart a codex node * [purchasing] Set client address before requesting storage To prevent the purchase id (which equals the request id) from changing once it's been submitted. * [contracts] Fix: OnChainMarket.getState() Had the wrong method signature before * [purchasing] Load purchases on node start * [purchasing] Rename state 'PurchaseError' to 'PurchaseErrored' Allows for an exception type called 'PurchaseError' * [purchasing] Load purchases in background No longer calls market.getRequest() for every purchase on node start. * [contracts] Add `$` for RequestId, SlotId and Nonce To aid with debugging * [purchasing] Add Purchasing.stop() To ensure that all contract interactions have both a start() and a stop() for * [tests] Remove sleepAsync where possible Use `eventually` loop instead, to make sure that we're not waiting unnecessarily. * [integration] Fix: handle non-json response in test * [purchasing] Add purchase state to json * [integration] Ensure that purchase is submitted before restart Fixes test failure on slower CI * [purchasing] re-implement `description` as method Allows description to be set in the same module where the state type is defined. Co-authored-by: Eric Mastro <eric.mastro@gmail.com> * [contracts] fix typo Co-authored-by: Eric Mastro <eric.mastro@gmail.com> * [market] Use more generic error type Should we decide to change the provider type later Co-authored-by: Eric Mastro <eric.mastro@gmail.com> Co-authored-by: Eric Mastro <eric.mastro@gmail.com>
149 lines
5.0 KiB
Nim
149 lines
5.0 KiB
Nim
import std/osproc
|
|
import std/os
|
|
import std/httpclient
|
|
import std/json
|
|
import std/strutils
|
|
|
|
import pkg/chronos
|
|
import ./ethertest
|
|
import ./contracts/time
|
|
import ./integration/nodes
|
|
import ./integration/tokens
|
|
import ./codex/helpers/eventually
|
|
|
|
ethersuite "Integration tests":
|
|
|
|
var node1, node2: NodeProcess
|
|
var baseurl1, baseurl2: string
|
|
var client: HttpClient
|
|
|
|
let dataDir1 = getTempDir() / "Codex1"
|
|
let dataDir2 = getTempDir() / "Codex2"
|
|
|
|
setup:
|
|
await provider.getSigner(accounts[0]).mint()
|
|
await provider.getSigner(accounts[1]).mint()
|
|
await provider.getSigner(accounts[1]).deposit()
|
|
|
|
baseurl1 = "http://localhost:8080/api/codex/v1"
|
|
baseurl2 = "http://localhost:8081/api/codex/v1"
|
|
client = newHttpClient()
|
|
|
|
node1 = startNode([
|
|
"--api-port=8080",
|
|
"--data-dir=" & dataDir1,
|
|
"--nat=127.0.0.1",
|
|
"--disc-ip=127.0.0.1",
|
|
"--disc-port=8090",
|
|
"--persistence",
|
|
"--eth-account=" & $accounts[0]
|
|
], debug = false)
|
|
|
|
node2 = startNode([
|
|
"--api-port=8081",
|
|
"--data-dir=" & dataDir2,
|
|
"--nat=127.0.0.1",
|
|
"--disc-ip=127.0.0.1",
|
|
"--disc-port=8091",
|
|
"--bootstrap-node=" & strip($(parseJson(client.get(baseurl1 & "/info").body)["spr"]), chars = {'"'}),
|
|
"--persistence",
|
|
"--eth-account=" & $accounts[1]
|
|
], debug = false)
|
|
|
|
teardown:
|
|
client.close()
|
|
node1.stop()
|
|
node2.stop()
|
|
|
|
dataDir1.removeDir()
|
|
dataDir2.removeDir()
|
|
|
|
test "nodes can print their peer information":
|
|
let info1 = client.get(baseurl1 & "/info").body
|
|
let info2 = client.get(baseurl2 & "/info").body
|
|
check info1 != info2
|
|
|
|
test "node accepts file uploads":
|
|
let url = baseurl1 & "/upload"
|
|
let response = client.post(url, "some file contents")
|
|
check response.status == "200 OK"
|
|
|
|
test "node handles new storage availability":
|
|
let url = baseurl1 & "/sales/availability"
|
|
let json = %*{"size": "0x1", "duration": "0x2", "minPrice": "0x3"}
|
|
check client.post(url, $json).status == "200 OK"
|
|
|
|
test "node lists storage that is for sale":
|
|
let url = baseurl1 & "/sales/availability"
|
|
let json = %*{"size": "0x1", "duration": "0x2", "minPrice": "0x3"}
|
|
let availability = parseJson(client.post(url, $json).body)
|
|
let response = client.get(url)
|
|
check response.status == "200 OK"
|
|
check %*availability in parseJson(response.body)
|
|
|
|
test "node handles storage request":
|
|
let cid = client.post(baseurl1 & "/upload", "some file contents").body
|
|
let url = baseurl1 & "/storage/request/" & cid
|
|
let json = %*{"duration": "0x1", "reward": "0x2"}
|
|
let response = client.post(url, $json)
|
|
check response.status == "200 OK"
|
|
|
|
test "node retrieves purchase status":
|
|
let cid = client.post(baseurl1 & "/upload", "some file contents").body
|
|
let request = %*{"duration": "0x1", "reward": "0x2"}
|
|
let id = client.post(baseurl1 & "/storage/request/" & cid, $request).body
|
|
let response = client.get(baseurl1 & "/storage/purchases/" & id)
|
|
check response.status == "200 OK"
|
|
let json = parseJson(response.body)
|
|
check json["request"]["ask"]["duration"].getStr == "0x1"
|
|
check json["request"]["ask"]["reward"].getStr == "0x2"
|
|
|
|
test "node remembers purchase status after restart":
|
|
let cid = client.post(baseurl1 & "/upload", "some file contents").body
|
|
let request = %*{"duration": "0x1", "reward": "0x2"}
|
|
let id = client.post(baseurl1 & "/storage/request/" & cid, $request).body
|
|
|
|
proc getPurchase(id: string): JsonNode =
|
|
let response = client.get(baseurl1 & "/storage/purchases/" & id)
|
|
return parseJson(response.body).catch |? nil
|
|
|
|
check eventually getPurchase(id){"state"}.getStr == "submitted"
|
|
|
|
node1.restart()
|
|
|
|
client.close()
|
|
client = newHttpClient()
|
|
|
|
check eventually (not isNil getPurchase(id){"request"}{"ask"})
|
|
check getPurchase(id){"request"}{"ask"}{"duration"}.getStr == "0x1"
|
|
check getPurchase(id){"request"}{"ask"}{"reward"}.getStr == "0x2"
|
|
|
|
test "nodes negotiate contracts on the marketplace":
|
|
proc sell =
|
|
let json = %*{"size": "0xFFFFF", "duration": "0x200", "minPrice": "0x300"}
|
|
discard client.post(baseurl2 & "/sales/availability", $json)
|
|
|
|
proc available: JsonNode =
|
|
client.get(baseurl2 & "/sales/availability").body.parseJson
|
|
|
|
proc upload: string =
|
|
client.post(baseurl1 & "/upload", "some file contents").body
|
|
|
|
proc buy(cid: string): string =
|
|
let expiry = ((waitFor provider.currentTime()) + 30).toHex
|
|
let json = %*{"duration": "0x1", "reward": "0x400", "expiry": expiry}
|
|
client.post(baseurl1 & "/storage/request/" & cid, $json).body
|
|
|
|
proc finish(purchase: string): Future[JsonNode] {.async.} =
|
|
while true:
|
|
let response = client.get(baseurl1 & "/storage/purchases/" & purchase)
|
|
let json = parseJson(response.body)
|
|
if json["state"].getStr == "finished": return json
|
|
await sleepAsync(1.seconds)
|
|
|
|
sell()
|
|
let purchase = waitFor upload().buy().finish()
|
|
|
|
check purchase["error"].getStr == ""
|
|
check available().len == 0
|