mirror of
https://github.com/logos-messaging/logos-messaging-nim.git
synced 2026-01-05 23:43:07 +00:00
chore: Postgres migrations (#2477)
* Add postgres_driver/migrations.nim * Postgres and archive logic adaptation to the migration implementation * libwaku: adapt node_lifecycle_request.nim to migration refactoring * test_app.nim: add more detail for test that only fails in CI * postgres migrations: store the migration scripts inside the resulting wakunode binary instead of external .sql files.
This commit is contained in:
parent
88ff928213
commit
560f949a8b
@ -493,7 +493,7 @@ proc setupProtocols(node: WakuNode,
|
|||||||
|
|
||||||
if conf.store:
|
if conf.store:
|
||||||
# Archive setup
|
# Archive setup
|
||||||
let archiveDriverRes = ArchiveDriver.new(conf.storeMessageDbUrl,
|
let archiveDriverRes = waitFor ArchiveDriver.new(conf.storeMessageDbUrl,
|
||||||
conf.storeMessageDbVacuum,
|
conf.storeMessageDbVacuum,
|
||||||
conf.storeMessageDbMigration,
|
conf.storeMessageDbMigration,
|
||||||
conf.storeMaxNumDbConnections,
|
conf.storeMaxNumDbConnections,
|
||||||
|
|||||||
@ -70,11 +70,11 @@ proc configureStore(node: WakuNode,
|
|||||||
discard
|
discard
|
||||||
|
|
||||||
# Archive setup
|
# Archive setup
|
||||||
let archiveDriverRes = ArchiveDriver.new(storeDbUrl,
|
let archiveDriverRes = await ArchiveDriver.new(storeDbUrl,
|
||||||
storeVacuum,
|
storeVacuum,
|
||||||
storeDbMigration,
|
storeDbMigration,
|
||||||
storeMaxNumDbConnections,
|
storeMaxNumDbConnections,
|
||||||
onFatalErrorAction)
|
onFatalErrorAction)
|
||||||
if archiveDriverRes.isErr():
|
if archiveDriverRes.isErr():
|
||||||
return err("failed to setup archive driver: " & archiveDriverRes.error)
|
return err("failed to setup archive driver: " & archiveDriverRes.error)
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
const ContentScriptVersion_1* = """
|
||||||
|
CREATE TABLE IF NOT EXISTS messages (
|
||||||
|
pubsubTopic VARCHAR NOT NULL,
|
||||||
|
contentTopic VARCHAR NOT NULL,
|
||||||
|
payload VARCHAR,
|
||||||
|
version INTEGER NOT NULL,
|
||||||
|
timestamp BIGINT NOT NULL,
|
||||||
|
id VARCHAR NOT NULL,
|
||||||
|
messageHash VARCHAR NOT NULL,
|
||||||
|
storedAt BIGINT NOT NULL,
|
||||||
|
CONSTRAINT messageIndex PRIMARY KEY (messageHash)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE iF NOT EXISTS version (
|
||||||
|
version INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO version (version) VALUES(1);
|
||||||
|
|
||||||
|
"""
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
const ContentScriptVersion_2* = """
|
||||||
|
ALTER TABLE messages RENAME TO messages_backup;
|
||||||
|
ALTER TABLE messages_backup DROP CONSTRAINT messageIndex;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS messages (
|
||||||
|
pubsubTopic VARCHAR NOT NULL,
|
||||||
|
contentTopic VARCHAR NOT NULL,
|
||||||
|
payload VARCHAR,
|
||||||
|
version INTEGER NOT NULL,
|
||||||
|
timestamp BIGINT NOT NULL,
|
||||||
|
id VARCHAR NOT NULL,
|
||||||
|
messageHash VARCHAR NOT NULL,
|
||||||
|
storedAt BIGINT NOT NULL,
|
||||||
|
CONSTRAINT messageIndex PRIMARY KEY (messageHash, storedAt)
|
||||||
|
) PARTITION BY RANGE (storedAt);
|
||||||
|
|
||||||
|
DO $$
|
||||||
|
DECLARE
|
||||||
|
min_storedAt numeric;
|
||||||
|
max_storedAt numeric;
|
||||||
|
min_storedAtSeconds integer = 0;
|
||||||
|
max_storedAtSeconds integer = 0;
|
||||||
|
partition_name TEXT;
|
||||||
|
create_partition_stmt TEXT;
|
||||||
|
BEGIN
|
||||||
|
SELECT MIN(storedAt) into min_storedAt
|
||||||
|
FROM messages_backup;
|
||||||
|
|
||||||
|
SELECT MAX(storedAt) into max_storedAt
|
||||||
|
FROM messages_backup;
|
||||||
|
|
||||||
|
min_storedAtSeconds := min_storedAt / 1000000000;
|
||||||
|
max_storedAtSeconds := max_storedAt / 1000000000;
|
||||||
|
|
||||||
|
partition_name := 'messages_' || min_storedAtSeconds || '_' || max_storedAtSeconds;
|
||||||
|
create_partition_stmt := 'CREATE TABLE ' || partition_name ||
|
||||||
|
' PARTITION OF messages FOR VALUES FROM (' ||
|
||||||
|
min_storedAt || ') TO (' || (max_storedAt + 1) || ')';
|
||||||
|
IF min_storedAtSeconds > 0 AND max_storedAtSeconds > 0 THEN
|
||||||
|
EXECUTE create_partition_stmt USING partition_name, min_storedAt, max_storedAt;
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
INSERT INTO messages (
|
||||||
|
pubsubTopic,
|
||||||
|
contentTopic,
|
||||||
|
payload,
|
||||||
|
version,
|
||||||
|
timestamp,
|
||||||
|
id,
|
||||||
|
messageHash,
|
||||||
|
storedAt
|
||||||
|
)
|
||||||
|
SELECT pubsubTopic,
|
||||||
|
contentTopic,
|
||||||
|
payload,
|
||||||
|
version,
|
||||||
|
timestamp,
|
||||||
|
id,
|
||||||
|
messageHash,
|
||||||
|
storedAt
|
||||||
|
FROM messages_backup;
|
||||||
|
|
||||||
|
DROP TABLE messages_backup;
|
||||||
|
|
||||||
|
UPDATE version SET version = 2 WHERE version = 1;
|
||||||
|
|
||||||
|
"""
|
||||||
37
migrations/message_store_postgres/pg_migration_manager.nim
Normal file
37
migrations/message_store_postgres/pg_migration_manager.nim
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
import
|
||||||
|
content_script_version_1,
|
||||||
|
content_script_version_2
|
||||||
|
|
||||||
|
type
|
||||||
|
MigrationScript* = object
|
||||||
|
version*: int
|
||||||
|
scriptContent*: string
|
||||||
|
|
||||||
|
proc init*(T: type MigrationScript,
|
||||||
|
targetVersion: int,
|
||||||
|
scriptContent: string): T =
|
||||||
|
|
||||||
|
return MigrationScript(
|
||||||
|
targetVersion: targetVersion,
|
||||||
|
scriptContent: scriptContent)
|
||||||
|
|
||||||
|
const PgMigrationScripts* = @[
|
||||||
|
MigrationScript(
|
||||||
|
version: 1,
|
||||||
|
scriptContent: ContentScriptVersion_1),
|
||||||
|
MigrationScript(
|
||||||
|
version: 2,
|
||||||
|
scriptContent: ContentScriptVersion_2)
|
||||||
|
]
|
||||||
|
|
||||||
|
proc getMigrationScripts*(currentVersion: int64,
|
||||||
|
targetVersion: int64): seq[string] =
|
||||||
|
var ret = newSeq[string]()
|
||||||
|
var v = currentVersion
|
||||||
|
while v < targetVersion:
|
||||||
|
ret.add(PgMigrationScripts[v].scriptContent)
|
||||||
|
v.inc()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
33
tests/testlib/postgres.nim
Normal file
33
tests/testlib/postgres.nim
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
import
|
||||||
|
chronicles,
|
||||||
|
chronos
|
||||||
|
import
|
||||||
|
../../../waku/waku_archive,
|
||||||
|
../../../waku/waku_archive/driver as driver_module,
|
||||||
|
../../../waku/waku_archive/driver/builder,
|
||||||
|
../../../waku/waku_archive/driver/postgres_driver
|
||||||
|
|
||||||
|
const storeMessageDbUrl = "postgres://postgres:test123@localhost:5432/postgres"
|
||||||
|
|
||||||
|
proc newTestPostgresDriver*(): Future[Result[ArchiveDriver, string]] {.async.} =
|
||||||
|
|
||||||
|
proc onErr(errMsg: string) {.gcsafe, closure.} =
|
||||||
|
error "error creating ArchiveDriver", error = errMsg
|
||||||
|
quit(QuitFailure)
|
||||||
|
|
||||||
|
let
|
||||||
|
vacuum = false
|
||||||
|
migrate = true
|
||||||
|
maxNumConn = 50
|
||||||
|
|
||||||
|
let driverRes = await ArchiveDriver.new(storeMessageDbUrl,
|
||||||
|
vacuum,
|
||||||
|
migrate,
|
||||||
|
maxNumConn,
|
||||||
|
onErr)
|
||||||
|
if driverRes.isErr():
|
||||||
|
onErr("could not create archive driver: " & driverRes.error)
|
||||||
|
|
||||||
|
return ok(driverRes.get())
|
||||||
|
|
||||||
@ -9,7 +9,9 @@ import
|
|||||||
../../../waku/waku_archive/driver/postgres_driver,
|
../../../waku/waku_archive/driver/postgres_driver,
|
||||||
../../../waku/waku_core,
|
../../../waku/waku_core,
|
||||||
../../../waku/waku_core/message/digest,
|
../../../waku/waku_core/message/digest,
|
||||||
../testlib/wakucore
|
../testlib/wakucore,
|
||||||
|
../testlib/testasync,
|
||||||
|
../testlib/postgres
|
||||||
|
|
||||||
proc now():int64 = getTime().toUnix()
|
proc now():int64 = getTime().toUnix()
|
||||||
|
|
||||||
@ -24,18 +26,24 @@ proc computeTestCursor(pubsubTopic: PubsubTopic,
|
|||||||
)
|
)
|
||||||
|
|
||||||
suite "Postgres driver":
|
suite "Postgres driver":
|
||||||
|
## Unique driver instance
|
||||||
|
var driver {.threadvar.}: PostgresDriver
|
||||||
|
|
||||||
const storeMessageDbUrl = "postgres://postgres:test123@localhost:5432/postgres"
|
asyncSetup:
|
||||||
|
let driverRes = await newTestPostgresDriver()
|
||||||
|
if driverRes.isErr():
|
||||||
|
assert false, driverRes.error
|
||||||
|
|
||||||
|
driver = PostgresDriver(driverRes.get())
|
||||||
|
|
||||||
|
asyncTeardown:
|
||||||
|
let resetRes = await driver.reset()
|
||||||
|
if resetRes.isErr():
|
||||||
|
assert false, resetRes.error
|
||||||
|
|
||||||
|
(await driver.close()).expect("driver to close")
|
||||||
|
|
||||||
asyncTest "Asynchronous queries":
|
asyncTest "Asynchronous queries":
|
||||||
let driverRes = PostgresDriver.new(dbUrl = storeMessageDbUrl,
|
|
||||||
maxConnections = 100)
|
|
||||||
|
|
||||||
assert driverRes.isOk(), driverRes.error
|
|
||||||
|
|
||||||
let driver = driverRes.value
|
|
||||||
discard await driver.reset()
|
|
||||||
|
|
||||||
var futures = newSeq[Future[ArchiveDriverResult[void]]](0)
|
var futures = newSeq[Future[ArchiveDriverResult[void]]](0)
|
||||||
|
|
||||||
let beforeSleep = now()
|
let beforeSleep = now()
|
||||||
@ -50,33 +58,9 @@ suite "Postgres driver":
|
|||||||
# connections and we spawn 100 tasks that spend ~1s each.
|
# connections and we spawn 100 tasks that spend ~1s each.
|
||||||
require diff < 20
|
require diff < 20
|
||||||
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "Init database":
|
|
||||||
let driverRes = PostgresDriver.new(storeMessageDbUrl)
|
|
||||||
assert driverRes.isOk(), driverRes.error
|
|
||||||
|
|
||||||
let driver = driverRes.value
|
|
||||||
discard await driver.reset()
|
|
||||||
|
|
||||||
let initRes = await driver.init()
|
|
||||||
assert initRes.isOk(), initRes.error
|
|
||||||
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "Insert a message":
|
asyncTest "Insert a message":
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driverRes = PostgresDriver.new(storeMessageDbUrl)
|
|
||||||
assert driverRes.isOk(), driverRes.error
|
|
||||||
|
|
||||||
let driver = driverRes.get()
|
|
||||||
|
|
||||||
discard await driver.reset()
|
|
||||||
|
|
||||||
let initRes = await driver.init()
|
|
||||||
assert initRes.isOk(), initRes.error
|
|
||||||
|
|
||||||
let msg = fakeWakuMessage(contentTopic=contentTopic)
|
let msg = fakeWakuMessage(contentTopic=contentTopic)
|
||||||
|
|
||||||
let computedDigest = computeDigest(msg)
|
let computedDigest = computeDigest(msg)
|
||||||
@ -94,24 +78,12 @@ suite "Postgres driver":
|
|||||||
toHex(computedDigest.data) == toHex(digest) and
|
toHex(computedDigest.data) == toHex(digest) and
|
||||||
toHex(actualMsg.payload) == toHex(msg.payload)
|
toHex(actualMsg.payload) == toHex(msg.payload)
|
||||||
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "Insert and query message":
|
asyncTest "Insert and query message":
|
||||||
const contentTopic1 = "test-content-topic-1"
|
const contentTopic1 = "test-content-topic-1"
|
||||||
const contentTopic2 = "test-content-topic-2"
|
const contentTopic2 = "test-content-topic-2"
|
||||||
const pubsubTopic1 = "pubsubtopic-1"
|
const pubsubTopic1 = "pubsubtopic-1"
|
||||||
const pubsubTopic2 = "pubsubtopic-2"
|
const pubsubTopic2 = "pubsubtopic-2"
|
||||||
|
|
||||||
let driverRes = PostgresDriver.new(storeMessageDbUrl)
|
|
||||||
assert driverRes.isOk(), driverRes.error
|
|
||||||
|
|
||||||
let driver = driverRes.value
|
|
||||||
|
|
||||||
discard await driver.reset()
|
|
||||||
|
|
||||||
let initRes = await driver.init()
|
|
||||||
assert initRes.isOk(), initRes.error
|
|
||||||
|
|
||||||
let msg1 = fakeWakuMessage(contentTopic=contentTopic1)
|
let msg1 = fakeWakuMessage(contentTopic=contentTopic1)
|
||||||
|
|
||||||
var putRes = await driver.put(pubsubTopic1, msg1, computeDigest(msg1), computeMessageHash(pubsubTopic1, msg1), msg1.timestamp)
|
var putRes = await driver.put(pubsubTopic1, msg1, computeDigest(msg1), computeMessageHash(pubsubTopic1, msg1), msg1.timestamp)
|
||||||
@ -178,19 +150,8 @@ suite "Postgres driver":
|
|||||||
assert messagesRes.isOk(), messagesRes.error
|
assert messagesRes.isOk(), messagesRes.error
|
||||||
require messagesRes.get().len == 1
|
require messagesRes.get().len == 1
|
||||||
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "Insert true duplicated messages":
|
asyncTest "Insert true duplicated messages":
|
||||||
# Validates that two completely equal messages can not be stored.
|
# Validates that two completely equal messages can not be stored.
|
||||||
let driverRes = PostgresDriver.new(storeMessageDbUrl)
|
|
||||||
assert driverRes.isOk(), driverRes.error
|
|
||||||
|
|
||||||
let driver = driverRes.value
|
|
||||||
|
|
||||||
discard await driver.reset()
|
|
||||||
|
|
||||||
let initRes = await driver.init()
|
|
||||||
assert initRes.isOk(), initRes.error
|
|
||||||
|
|
||||||
let now = now()
|
let now = now()
|
||||||
|
|
||||||
@ -205,4 +166,3 @@ suite "Postgres driver":
|
|||||||
msg2, computeDigest(msg2), computeMessageHash(DefaultPubsubTopic, msg2), msg2.timestamp)
|
msg2, computeDigest(msg2), computeMessageHash(DefaultPubsubTopic, msg2), msg2.timestamp)
|
||||||
require not putRes.isOk()
|
require not putRes.isOk()
|
||||||
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|||||||
@ -7,11 +7,15 @@ import
|
|||||||
chronicles
|
chronicles
|
||||||
import
|
import
|
||||||
../../../waku/waku_archive,
|
../../../waku/waku_archive,
|
||||||
|
../../../waku/waku_archive/driver as driver_module,
|
||||||
|
../../../waku/waku_archive/driver/builder,
|
||||||
../../../waku/waku_archive/driver/postgres_driver,
|
../../../waku/waku_archive/driver/postgres_driver,
|
||||||
../../../waku/waku_core,
|
../../../waku/waku_core,
|
||||||
../../../waku/waku_core/message/digest,
|
../../../waku/waku_core/message/digest,
|
||||||
../testlib/common,
|
../testlib/common,
|
||||||
../testlib/wakucore
|
../testlib/wakucore,
|
||||||
|
../testlib/testasync,
|
||||||
|
../testlib/postgres
|
||||||
|
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
@ -24,17 +28,6 @@ logScope:
|
|||||||
# Initialize the random number generator
|
# Initialize the random number generator
|
||||||
common.randomize()
|
common.randomize()
|
||||||
|
|
||||||
const storeMessageDbUrl = "postgres://postgres:test123@localhost:5432/postgres"
|
|
||||||
|
|
||||||
proc newTestPostgresDriver(): ArchiveDriver =
|
|
||||||
let driver = PostgresDriver.new(dbUrl = storeMessageDbUrl).tryGet()
|
|
||||||
discard waitFor driver.reset()
|
|
||||||
|
|
||||||
let initRes = waitFor driver.init()
|
|
||||||
assert initRes.isOk(), initRes.error
|
|
||||||
|
|
||||||
return driver
|
|
||||||
|
|
||||||
proc computeTestCursor(pubsubTopic: PubsubTopic, message: WakuMessage): ArchiveCursor =
|
proc computeTestCursor(pubsubTopic: PubsubTopic, message: WakuMessage): ArchiveCursor =
|
||||||
ArchiveCursor(
|
ArchiveCursor(
|
||||||
pubsubTopic: pubsubTopic,
|
pubsubTopic: pubsubTopic,
|
||||||
@ -43,14 +36,28 @@ proc computeTestCursor(pubsubTopic: PubsubTopic, message: WakuMessage): ArchiveC
|
|||||||
digest: computeDigest(message)
|
digest: computeDigest(message)
|
||||||
)
|
)
|
||||||
|
|
||||||
suite "Postgres driver - query by content topic":
|
suite "Postgres driver - queries":
|
||||||
|
## Unique driver instance
|
||||||
|
var driver {.threadvar.}: PostgresDriver
|
||||||
|
|
||||||
|
asyncSetup:
|
||||||
|
let driverRes = await newTestPostgresDriver()
|
||||||
|
if driverRes.isErr():
|
||||||
|
assert false, driverRes.error
|
||||||
|
|
||||||
|
driver = PostgresDriver(driverRes.get())
|
||||||
|
|
||||||
|
asyncTeardown:
|
||||||
|
let resetRes = await driver.reset()
|
||||||
|
if resetRes.isErr():
|
||||||
|
assert false, resetRes.error
|
||||||
|
|
||||||
|
(await driver.close()).expect("driver to close")
|
||||||
|
|
||||||
asyncTest "no content topic":
|
asyncTest "no content topic":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=DefaultContentTopic, ts=ts(00)),
|
fakeWakuMessage(@[byte 0], contentTopic=DefaultContentTopic, ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], contentTopic=DefaultContentTopic, ts=ts(10)),
|
fakeWakuMessage(@[byte 1], contentTopic=DefaultContentTopic, ts=ts(10)),
|
||||||
@ -83,15 +90,10 @@ suite "Postgres driver - query by content topic":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[0..4]
|
filteredMessages == expected[0..4]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "single content topic":
|
asyncTest "single content topic":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
||||||
@ -126,15 +128,10 @@ suite "Postgres driver - query by content topic":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[2..3]
|
filteredMessages == expected[2..3]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "single content topic - descending order":
|
asyncTest "single content topic - descending order":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
||||||
@ -169,17 +166,12 @@ suite "Postgres driver - query by content topic":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[6..7].reversed()
|
filteredMessages == expected[6..7].reversed()
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "multiple content topic":
|
asyncTest "multiple content topic":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic1 = "test-content-topic-1"
|
const contentTopic1 = "test-content-topic-1"
|
||||||
const contentTopic2 = "test-content-topic-2"
|
const contentTopic2 = "test-content-topic-2"
|
||||||
const contentTopic3 = "test-content-topic-3"
|
const contentTopic3 = "test-content-topic-3"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
||||||
@ -232,15 +224,10 @@ suite "Postgres driver - query by content topic":
|
|||||||
filteredMessages = res.tryGet().mapIt(it[1])
|
filteredMessages = res.tryGet().mapIt(it[1])
|
||||||
check filteredMessages == @[expected[2]]
|
check filteredMessages == @[expected[2]]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "single content topic - no results":
|
asyncTest "single content topic - no results":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=DefaultContentTopic, ts=ts(00)),
|
fakeWakuMessage(@[byte 0], contentTopic=DefaultContentTopic, ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], contentTopic=DefaultContentTopic, ts=ts(10)),
|
fakeWakuMessage(@[byte 1], contentTopic=DefaultContentTopic, ts=ts(10)),
|
||||||
@ -270,15 +257,10 @@ suite "Postgres driver - query by content topic":
|
|||||||
check:
|
check:
|
||||||
filteredMessages.len == 0
|
filteredMessages.len == 0
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "content topic and max page size - not enough messages stored":
|
asyncTest "content topic and max page size - not enough messages stored":
|
||||||
## Given
|
## Given
|
||||||
const pageSize: uint = 50
|
const pageSize: uint = 50
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
for t in 0..<40:
|
for t in 0..<40:
|
||||||
let msg = fakeWakuMessage(@[byte t], DefaultContentTopic, ts=ts(t))
|
let msg = fakeWakuMessage(@[byte t], DefaultContentTopic, ts=ts(t))
|
||||||
require (await driver.put(DefaultPubsubTopic, msg, computeDigest(msg), computeMessageHash(DefaultPubsubTopic, msg), msg.timestamp)).isOk()
|
require (await driver.put(DefaultPubsubTopic, msg, computeDigest(msg), computeMessageHash(DefaultPubsubTopic, msg), msg.timestamp)).isOk()
|
||||||
@ -297,18 +279,11 @@ suite "Postgres driver - query by content topic":
|
|||||||
check:
|
check:
|
||||||
filteredMessages.len == 40
|
filteredMessages.len == 40
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
suite "Postgres driver - query by pubsub topic":
|
|
||||||
|
|
||||||
asyncTest "pubsub topic":
|
asyncTest "pubsub topic":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00))),
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 1], ts=ts(10))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 1], ts=ts(10))),
|
||||||
@ -344,16 +319,11 @@ suite "Postgres driver - query by pubsub topic":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[4..5]
|
filteredMessages == expectedMessages[4..5]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "no pubsub topic":
|
asyncTest "no pubsub topic":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00))),
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 1], ts=ts(10))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 1], ts=ts(10))),
|
||||||
@ -388,16 +358,11 @@ suite "Postgres driver - query by pubsub topic":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[0..1]
|
filteredMessages == expectedMessages[0..1]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "content topic and pubsub topic":
|
asyncTest "content topic and pubsub topic":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00))),
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 1], ts=ts(10))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 1], ts=ts(10))),
|
||||||
@ -435,17 +400,10 @@ suite "Postgres driver - query by pubsub topic":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[4..5]
|
filteredMessages == expectedMessages[4..5]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
suite "Postgres driver - query by cursor":
|
|
||||||
|
|
||||||
asyncTest "only cursor":
|
asyncTest "only cursor":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
||||||
@ -482,15 +440,10 @@ suite "Postgres driver - query by cursor":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[5..6]
|
filteredMessages == expected[5..6]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "only cursor - descending order":
|
asyncTest "only cursor - descending order":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
||||||
@ -527,15 +480,10 @@ suite "Postgres driver - query by cursor":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[2..3].reversed()
|
filteredMessages == expected[2..3].reversed()
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "content topic and cursor":
|
asyncTest "content topic and cursor":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
||||||
@ -571,15 +519,10 @@ suite "Postgres driver - query by cursor":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[5..6]
|
filteredMessages == expected[5..6]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "content topic and cursor - descending order":
|
asyncTest "content topic and cursor - descending order":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
fakeWakuMessage(@[byte 0], ts=ts(00)),
|
||||||
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
fakeWakuMessage(@[byte 1], ts=ts(10)),
|
||||||
@ -615,16 +558,11 @@ suite "Postgres driver - query by cursor":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[2..5].reversed()
|
filteredMessages == expected[2..5].reversed()
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "pubsub topic and cursor":
|
asyncTest "pubsub topic and cursor":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
||||||
@ -667,16 +605,11 @@ suite "Postgres driver - query by cursor":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[6..7]
|
filteredMessages == expectedMessages[6..7]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "pubsub topic and cursor - descending order":
|
asyncTest "pubsub topic and cursor - descending order":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
||||||
@ -719,17 +652,10 @@ suite "Postgres driver - query by cursor":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[4..5].reversed()
|
filteredMessages == expectedMessages[4..5].reversed()
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
suite "Postgres driver - query by time range":
|
|
||||||
|
|
||||||
asyncTest "start time only":
|
asyncTest "start time only":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
||||||
@ -763,15 +689,10 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[2..6]
|
filteredMessages == expected[2..6]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "end time only":
|
asyncTest "end time only":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
||||||
@ -805,16 +726,11 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[0..4]
|
filteredMessages == expected[0..4]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "start time and end time":
|
asyncTest "start time and end time":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
||||||
@ -855,15 +771,10 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[2..4]
|
filteredMessages == expectedMessages[2..4]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "invalid time range - no results":
|
asyncTest "invalid time range - no results":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
||||||
@ -899,15 +810,10 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages.len == 0
|
filteredMessages.len == 0
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "time range start and content topic":
|
asyncTest "time range start and content topic":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
||||||
@ -941,15 +847,10 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[2..6]
|
filteredMessages == expected[2..6]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "time range start and content topic - descending order":
|
asyncTest "time range start and content topic - descending order":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
||||||
@ -986,15 +887,10 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[2..6].reversed()
|
filteredMessages == expected[2..6].reversed()
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "time range start, single content topic and cursor":
|
asyncTest "time range start, single content topic and cursor":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
||||||
@ -1034,15 +930,10 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[4..9]
|
filteredMessages == expected[4..9]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "time range start, single content topic and cursor - descending order":
|
asyncTest "time range start, single content topic and cursor - descending order":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
||||||
@ -1082,16 +973,11 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expected[3..4].reversed()
|
filteredMessages == expected[3..4].reversed()
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "time range, content topic, pubsub topic and cursor":
|
asyncTest "time range, content topic, pubsub topic and cursor":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
# start_time
|
# start_time
|
||||||
@ -1136,16 +1022,11 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[3..4]
|
filteredMessages == expectedMessages[3..4]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "time range, content topic, pubsub topic and cursor - descending order":
|
asyncTest "time range, content topic, pubsub topic and cursor - descending order":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
||||||
@ -1190,16 +1071,11 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[4..5].reversed()
|
filteredMessages == expectedMessages[4..5].reversed()
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "time range, content topic, pubsub topic and cursor - cursor timestamp out of time range":
|
asyncTest "time range, content topic, pubsub topic and cursor - cursor timestamp out of time range":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
||||||
@ -1245,16 +1121,11 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages == expectedMessages[4..5]
|
filteredMessages == expectedMessages[4..5]
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "time range, content topic, pubsub topic and cursor - cursor timestamp out of time range, descending order":
|
asyncTest "time range, content topic, pubsub topic and cursor - cursor timestamp out of time range, descending order":
|
||||||
## Given
|
## Given
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
const pubsubTopic = "test-pubsub-topic"
|
const pubsubTopic = "test-pubsub-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
(DefaultPubsubTopic, fakeWakuMessage(@[byte 0], ts=ts(00, timeOrigin))),
|
||||||
@ -1299,16 +1170,9 @@ suite "Postgres driver - query by time range":
|
|||||||
check:
|
check:
|
||||||
filteredMessages.len == 0
|
filteredMessages.len == 0
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
suite "Postgres driver - retention policy":
|
|
||||||
|
|
||||||
asyncTest "Get oldest and newest message timestamp":
|
asyncTest "Get oldest and newest message timestamp":
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let oldestTime = ts(00, timeOrigin)
|
let oldestTime = ts(00, timeOrigin)
|
||||||
let newestTime = ts(100, timeOrigin)
|
let newestTime = ts(100, timeOrigin)
|
||||||
@ -1337,14 +1201,9 @@ suite "Postgres driver - retention policy":
|
|||||||
assert res.isOk(), res.error
|
assert res.isOk(), res.error
|
||||||
assert res.get() == newestTime, "Failed to retrieve the newest timestamp"
|
assert res.get() == newestTime, "Failed to retrieve the newest timestamp"
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "Delete messages older than certain timestamp":
|
asyncTest "Delete messages older than certain timestamp":
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let targetTime = ts(40, timeOrigin)
|
let targetTime = ts(40, timeOrigin)
|
||||||
let expected = @[
|
let expected = @[
|
||||||
@ -1375,14 +1234,9 @@ suite "Postgres driver - retention policy":
|
|||||||
assert res.isOk(), res.error
|
assert res.isOk(), res.error
|
||||||
assert res.get() == 3, "Failed to retrieve the # of messages after deletion"
|
assert res.get() == 3, "Failed to retrieve the # of messages after deletion"
|
||||||
|
|
||||||
## Cleanup
|
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
|
||||||
asyncTest "Keep last n messages":
|
asyncTest "Keep last n messages":
|
||||||
const contentTopic = "test-content-topic"
|
const contentTopic = "test-content-topic"
|
||||||
|
|
||||||
let driver = newTestPostgresDriver()
|
|
||||||
|
|
||||||
let timeOrigin = now()
|
let timeOrigin = now()
|
||||||
let expected = @[
|
let expected = @[
|
||||||
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
fakeWakuMessage(@[byte 0], contentTopic=contentTopic, ts=ts(00, timeOrigin)),
|
||||||
@ -1412,5 +1266,9 @@ suite "Postgres driver - retention policy":
|
|||||||
assert res.isOk(), res.error
|
assert res.isOk(), res.error
|
||||||
assert res.get() == 2, "Failed to retrieve the # of messages after deletion"
|
assert res.get() == 2, "Failed to retrieve the # of messages after deletion"
|
||||||
|
|
||||||
## Cleanup
|
asyncTest "Exists table":
|
||||||
(await driver.close()).expect("driver to close")
|
|
||||||
|
var existsRes = await driver.existsTable("version")
|
||||||
|
assert existsRes.isOk(), existsRes.error
|
||||||
|
check existsRes.get() == true
|
||||||
|
|
||||||
|
|||||||
@ -43,7 +43,7 @@ suite "Wakunode2 - App initialization":
|
|||||||
let res = wakunode2.setupPeerPersistence()
|
let res = wakunode2.setupPeerPersistence()
|
||||||
|
|
||||||
## Then
|
## Then
|
||||||
check res.isOk()
|
assert res.isOk(), $res.error
|
||||||
|
|
||||||
test "node setup is successful with default configuration":
|
test "node setup is successful with default configuration":
|
||||||
## Given
|
## Given
|
||||||
|
|||||||
@ -79,3 +79,6 @@ method decreaseDatabaseSize*(driver: ArchiveDriver,
|
|||||||
method close*(driver: ArchiveDriver):
|
method close*(driver: ArchiveDriver):
|
||||||
Future[ArchiveDriverResult[void]] {.base, async.} = discard
|
Future[ArchiveDriverResult[void]] {.base, async.} = discard
|
||||||
|
|
||||||
|
method existsTable*(driver: ArchiveDriver, tableName: string):
|
||||||
|
Future[ArchiveDriverResult[bool]] {.base, async.} = discard
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import
|
|||||||
../../common/error_handling,
|
../../common/error_handling,
|
||||||
./sqlite_driver,
|
./sqlite_driver,
|
||||||
./sqlite_driver/migrations as archive_driver_sqlite_migrations,
|
./sqlite_driver/migrations as archive_driver_sqlite_migrations,
|
||||||
|
./postgres_driver/migrations as archive_postgres_driver_migrations,
|
||||||
./queue_driver
|
./queue_driver
|
||||||
|
|
||||||
export
|
export
|
||||||
@ -31,7 +32,7 @@ proc new*(T: type ArchiveDriver,
|
|||||||
migrate: bool,
|
migrate: bool,
|
||||||
maxNumConn: int,
|
maxNumConn: int,
|
||||||
onFatalErrorAction: OnFatalErrorHandler):
|
onFatalErrorAction: OnFatalErrorHandler):
|
||||||
Result[T, string] =
|
Future[Result[T, string]] {.async.} =
|
||||||
## url - string that defines the database
|
## url - string that defines the database
|
||||||
## vacuum - if true, a cleanup operation will be applied to the database
|
## vacuum - if true, a cleanup operation will be applied to the database
|
||||||
## migrate - if true, the database schema will be updated
|
## migrate - if true, the database schema will be updated
|
||||||
@ -63,17 +64,25 @@ proc new*(T: type ArchiveDriver,
|
|||||||
let db = dbRes.get()
|
let db = dbRes.get()
|
||||||
|
|
||||||
# SQLite vacuum
|
# SQLite vacuum
|
||||||
let (pageSize, pageCount, freelistCount) = ? db.gatherSqlitePageStats()
|
let sqliteStatsRes = db.gatherSqlitePageStats()
|
||||||
|
if sqliteStatsRes.isErr():
|
||||||
|
return err("error while gathering sqlite stats: " & $sqliteStatsRes.error)
|
||||||
|
|
||||||
|
let (pageSize, pageCount, freelistCount) = sqliteStatsRes.get()
|
||||||
debug "sqlite database page stats", pageSize = pageSize,
|
debug "sqlite database page stats", pageSize = pageSize,
|
||||||
pages = pageCount,
|
pages = pageCount,
|
||||||
freePages = freelistCount
|
freePages = freelistCount
|
||||||
|
|
||||||
if vacuum and (pageCount > 0 and freelistCount > 0):
|
if vacuum and (pageCount > 0 and freelistCount > 0):
|
||||||
? db.performSqliteVacuum()
|
let vacuumRes = db.performSqliteVacuum()
|
||||||
|
if vacuumRes.isErr():
|
||||||
|
return err("error in vacuum sqlite: " & $vacuumRes.error)
|
||||||
|
|
||||||
# Database migration
|
# Database migration
|
||||||
if migrate:
|
if migrate:
|
||||||
? archive_driver_sqlite_migrations.migrate(db)
|
let migrateRes = archive_driver_sqlite_migrations.migrate(db)
|
||||||
|
if migrateRes.isErr():
|
||||||
|
return err("error in migrate sqlite: " & $migrateRes.error)
|
||||||
|
|
||||||
debug "setting up sqlite waku archive driver"
|
debug "setting up sqlite waku archive driver"
|
||||||
let res = SqliteDriver.new(db)
|
let res = SqliteDriver.new(db)
|
||||||
@ -92,13 +101,11 @@ proc new*(T: type ArchiveDriver,
|
|||||||
|
|
||||||
let driver = res.get()
|
let driver = res.get()
|
||||||
|
|
||||||
try:
|
# Database migration
|
||||||
# The table should exist beforehand.
|
if migrate:
|
||||||
let newTableRes = waitFor driver.createMessageTable()
|
let migrateRes = await archive_postgres_driver_migrations.migrate(driver)
|
||||||
if newTableRes.isErr():
|
if migrateRes.isErr():
|
||||||
return err("error creating table: " & newTableRes.error)
|
return err("ArchiveDriver build failed in migration: " & $migrateRes.error)
|
||||||
except CatchableError:
|
|
||||||
return err("exception creating table: " & getCurrentExceptionMsg())
|
|
||||||
|
|
||||||
return ok(driver)
|
return ok(driver)
|
||||||
|
|
||||||
|
|||||||
95
waku/waku_archive/driver/postgres_driver/migrations.nim
Normal file
95
waku/waku_archive/driver/postgres_driver/migrations.nim
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
{.push raises: [].}
|
||||||
|
|
||||||
|
import
|
||||||
|
std/[tables, strutils, os],
|
||||||
|
stew/results,
|
||||||
|
chronicles,
|
||||||
|
chronos
|
||||||
|
import
|
||||||
|
../../../common/databases/common,
|
||||||
|
../../../../migrations/message_store_postgres/pg_migration_manager,
|
||||||
|
../postgres_driver
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
topics = "waku archive migration"
|
||||||
|
|
||||||
|
const SchemaVersion* = 1 # increase this when there is an update in the database schema
|
||||||
|
|
||||||
|
proc breakIntoStatements*(script: string): seq[string] =
|
||||||
|
## Given a full migration script, that can potentially contain a list
|
||||||
|
## of SQL statements, this proc splits it into the contained isolated statements
|
||||||
|
## that should be executed one after the other.
|
||||||
|
var statements = newSeq[string]()
|
||||||
|
|
||||||
|
let lines = script.split('\n')
|
||||||
|
|
||||||
|
var simpleStmt: string
|
||||||
|
var plSqlStatement: string
|
||||||
|
var insidePlSqlScript = false
|
||||||
|
for line in lines:
|
||||||
|
if line.strip().len == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if insidePlSqlScript:
|
||||||
|
if line.contains("END $$"):
|
||||||
|
## End of the Pl/SQL script
|
||||||
|
plSqlStatement &= line
|
||||||
|
statements.add(plSqlStatement)
|
||||||
|
plSqlStatement = ""
|
||||||
|
insidePlSqlScript = false
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
plSqlStatement &= line & "\n"
|
||||||
|
|
||||||
|
if line.contains("DO $$"):
|
||||||
|
## Beginning of the Pl/SQL script
|
||||||
|
insidePlSqlScript = true
|
||||||
|
plSqlStatement &= line & "\n"
|
||||||
|
|
||||||
|
if not insidePlSqlScript:
|
||||||
|
if line.contains(';'):
|
||||||
|
## End of simple statement
|
||||||
|
simpleStmt &= line
|
||||||
|
statements.add(simpleStmt)
|
||||||
|
simpleStmt = ""
|
||||||
|
else:
|
||||||
|
simpleStmt &= line & "\n"
|
||||||
|
|
||||||
|
return statements
|
||||||
|
|
||||||
|
proc migrate*(driver: PostgresDriver,
|
||||||
|
targetVersion = SchemaVersion):
|
||||||
|
Future[DatabaseResult[void]] {.async.} =
|
||||||
|
|
||||||
|
debug "starting message store's postgres database migration"
|
||||||
|
|
||||||
|
let currentVersion = (await driver.getCurrentVersion()).valueOr:
|
||||||
|
return err("migrate error could not retrieve current version: " & $error)
|
||||||
|
|
||||||
|
if currentVersion == targetVersion:
|
||||||
|
debug "database schema is up to date",
|
||||||
|
currentVersion=currentVersion, targetVersion=targetVersion
|
||||||
|
return ok()
|
||||||
|
|
||||||
|
info "database schema is outdated", currentVersion=currentVersion, targetVersion=targetVersion
|
||||||
|
|
||||||
|
# Load migration scripts
|
||||||
|
let scripts = pg_migration_manager.getMigrationScripts(currentVersion, targetVersion)
|
||||||
|
|
||||||
|
# Run the migration scripts
|
||||||
|
for script in scripts:
|
||||||
|
|
||||||
|
for statement in script.breakIntoStatements():
|
||||||
|
debug "executing migration statement", statement=statement
|
||||||
|
|
||||||
|
(await driver.performWriteQuery(statement)).isOkOr:
|
||||||
|
error "failed to execute migration statement", statement=statement, error=error
|
||||||
|
return err("failed to execute migration statement")
|
||||||
|
|
||||||
|
debug "migration statement executed succesfully", statement=statement
|
||||||
|
|
||||||
|
debug "finished message store's postgres database migration"
|
||||||
|
|
||||||
|
return ok()
|
||||||
|
|
||||||
@ -4,7 +4,7 @@ else:
|
|||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[nre,options,sequtils,strutils,times],
|
std/[nre,options,sequtils,strutils,times,strformat],
|
||||||
stew/[results,byteutils],
|
stew/[results,byteutils],
|
||||||
db_postgres,
|
db_postgres,
|
||||||
postgres,
|
postgres,
|
||||||
@ -28,6 +28,9 @@ type PostgresDriver* = ref object of ArchiveDriver
|
|||||||
proc dropTableQuery(): string =
|
proc dropTableQuery(): string =
|
||||||
"DROP TABLE messages"
|
"DROP TABLE messages"
|
||||||
|
|
||||||
|
proc dropVersionTableQuery(): string =
|
||||||
|
"DROP TABLE version"
|
||||||
|
|
||||||
proc createTableQuery(): string =
|
proc createTableQuery(): string =
|
||||||
"CREATE TABLE IF NOT EXISTS messages (" &
|
"CREATE TABLE IF NOT EXISTS messages (" &
|
||||||
" pubsubTopic VARCHAR NOT NULL," &
|
" pubsubTopic VARCHAR NOT NULL," &
|
||||||
@ -111,6 +114,15 @@ proc new*(T: type PostgresDriver,
|
|||||||
return ok(PostgresDriver(writeConnPool: writeConnPool,
|
return ok(PostgresDriver(writeConnPool: writeConnPool,
|
||||||
readConnPool: readConnPool))
|
readConnPool: readConnPool))
|
||||||
|
|
||||||
|
proc performWriteQuery*(s: PostgresDriver,
|
||||||
|
query: string): Future[ArchiveDriverResult[void]] {.async.} =
|
||||||
|
## Executes a query that changes the database state
|
||||||
|
## TODO: we can reduce the code a little with this proc
|
||||||
|
(await s.writeConnPool.pgQuery(query)).isOkOr:
|
||||||
|
return err(fmt"error in {query}: {error}")
|
||||||
|
|
||||||
|
return ok()
|
||||||
|
|
||||||
proc createMessageTable*(s: PostgresDriver):
|
proc createMessageTable*(s: PostgresDriver):
|
||||||
Future[ArchiveDriverResult[void]] {.async.} =
|
Future[ArchiveDriverResult[void]] {.async.} =
|
||||||
|
|
||||||
@ -120,7 +132,7 @@ proc createMessageTable*(s: PostgresDriver):
|
|||||||
|
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
proc deleteMessageTable*(s: PostgresDriver):
|
proc deleteMessageTable(s: PostgresDriver):
|
||||||
Future[ArchiveDriverResult[void]] {.async.} =
|
Future[ArchiveDriverResult[void]] {.async.} =
|
||||||
|
|
||||||
let execRes = await s.writeConnPool.pgQuery(dropTableQuery())
|
let execRes = await s.writeConnPool.pgQuery(dropTableQuery())
|
||||||
@ -129,18 +141,22 @@ proc deleteMessageTable*(s: PostgresDriver):
|
|||||||
|
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
proc init*(s: PostgresDriver): Future[ArchiveDriverResult[void]] {.async.} =
|
proc deleteVersionTable(s: PostgresDriver):
|
||||||
|
Future[ArchiveDriverResult[void]] {.async.} =
|
||||||
|
|
||||||
let createMsgRes = await s.createMessageTable()
|
let execRes = await s.writeConnPool.pgQuery(dropVersionTableQuery())
|
||||||
if createMsgRes.isErr():
|
if execRes.isErr():
|
||||||
return err("createMsgRes.isErr in init: " & createMsgRes.error)
|
return err("error in deleteVersionTable: " & execRes.error)
|
||||||
|
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
proc reset*(s: PostgresDriver): Future[ArchiveDriverResult[void]] {.async.} =
|
proc reset*(s: PostgresDriver): Future[ArchiveDriverResult[void]] {.async.} =
|
||||||
|
## This is only used for testing purposes, to set a fresh database at the beginning of each test
|
||||||
let ret = await s.deleteMessageTable()
|
(await s.deleteMessageTable()).isOkOr:
|
||||||
return ret
|
return err("error deleting message table: " & $error)
|
||||||
|
(await s.deleteVersionTable()).isOkOr:
|
||||||
|
return err("error deleting version table: " & $error)
|
||||||
|
return ok()
|
||||||
|
|
||||||
proc rowCallbackImpl(pqResult: ptr PGresult,
|
proc rowCallbackImpl(pqResult: ptr PGresult,
|
||||||
outRows: var seq[(PubsubTopic, WakuMessage, seq[byte], Timestamp)]) =
|
outRows: var seq[(PubsubTopic, WakuMessage, seq[byte], Timestamp)]) =
|
||||||
@ -570,3 +586,45 @@ proc sleep*(s: PostgresDriver, seconds: int):
|
|||||||
return err("exception sleeping: " & getCurrentExceptionMsg())
|
return err("exception sleeping: " & getCurrentExceptionMsg())
|
||||||
|
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
|
method existsTable*(s: PostgresDriver, tableName: string):
|
||||||
|
Future[ArchiveDriverResult[bool]] {.async.} =
|
||||||
|
let query: string = fmt"""
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT FROM
|
||||||
|
pg_tables
|
||||||
|
WHERE
|
||||||
|
tablename = '{tableName}'
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
|
||||||
|
var exists: string
|
||||||
|
proc rowCallback(pqResult: ptr PGresult) =
|
||||||
|
if pqResult.pqnfields() != 1:
|
||||||
|
error "Wrong number of fields in existsTable"
|
||||||
|
return
|
||||||
|
|
||||||
|
if pqResult.pqNtuples() != 1:
|
||||||
|
error "Wrong number of rows in existsTable"
|
||||||
|
return
|
||||||
|
|
||||||
|
exists = $(pqgetvalue(pqResult, 0, 0))
|
||||||
|
|
||||||
|
(await s.readConnPool.pgQuery(query, newSeq[string](0), rowCallback)).isOkOr:
|
||||||
|
return err("existsTable failed in getRow: " & $error)
|
||||||
|
|
||||||
|
return ok(exists == "t")
|
||||||
|
|
||||||
|
proc getCurrentVersion*(s: PostgresDriver):
|
||||||
|
Future[ArchiveDriverResult[int64]] {.async.} =
|
||||||
|
|
||||||
|
let existsVersionTable = (await s.existsTable("version")).valueOr:
|
||||||
|
return err("error in getCurrentVersion-existsTable: " & $error)
|
||||||
|
|
||||||
|
if not existsVersionTable:
|
||||||
|
return ok(0)
|
||||||
|
|
||||||
|
let res = (await s.getInt(fmt"SELECT version FROM version")).valueOr:
|
||||||
|
return err("error in getMessagesCount: " & $error)
|
||||||
|
|
||||||
|
return ok(res)
|
||||||
|
|||||||
@ -240,6 +240,10 @@ method getAllMessages*(driver: QueueDriver):
|
|||||||
# TODO: Implement this message_store method
|
# TODO: Implement this message_store method
|
||||||
return err("interface method not implemented")
|
return err("interface method not implemented")
|
||||||
|
|
||||||
|
method existsTable*(driver: QueueDriver, tableName: string):
|
||||||
|
Future[ArchiveDriverResult[bool]] {.async.} =
|
||||||
|
return err("interface method not implemented")
|
||||||
|
|
||||||
method getMessages*(driver: QueueDriver,
|
method getMessages*(driver: QueueDriver,
|
||||||
contentTopic: seq[ContentTopic] = @[],
|
contentTopic: seq[ContentTopic] = @[],
|
||||||
pubsubTopic = none(PubsubTopic),
|
pubsubTopic = none(PubsubTopic),
|
||||||
|
|||||||
@ -189,3 +189,7 @@ method close*(s: SqliteDriver):
|
|||||||
s.db.close()
|
s.db.close()
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
|
method existsTable*(s: SqliteDriver, tableName: string):
|
||||||
|
Future[ArchiveDriverResult[bool]] {.async.} =
|
||||||
|
return err("existsTable method not implemented in sqlite_driver")
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user