mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-05-12 06:19:33 +00:00
180 lines
5.3 KiB
Nim
180 lines
5.3 KiB
Nim
import std/[sets, options]
|
|
|
|
import pkg/unittest2
|
|
import pkg/libp2p/cid
|
|
|
|
import pkg/storage/blockexchange/engine/downloadcontext {.all.}
|
|
import pkg/storage/blockexchange/engine/scheduler {.all.}
|
|
|
|
import ../../examples
|
|
import ../../helpers
|
|
|
|
suite "Random Window Cursor":
|
|
test "Produces all windows exactly once (full permutation)":
|
|
for totalWindows in [
|
|
1'u64, 2, 3, 5, 7, 10, 16, 17, 31, 32, 63, 64, 100, 127, 128, 255, 256, 1000
|
|
]:
|
|
let
|
|
windowSize = 100'u64
|
|
totalBlocks = totalWindows * windowSize
|
|
var
|
|
cursor = initRandomWindowCursor(totalBlocks, windowSize)
|
|
seen = initHashSet[uint64]()
|
|
|
|
seen.incl(cursor.currentWindow().start div windowSize)
|
|
|
|
for i in 1'u64 ..< totalWindows:
|
|
check cursor.advance()
|
|
let windowIdx = cursor.currentWindow().start div windowSize
|
|
check windowIdx < totalWindows
|
|
check windowIdx notin seen
|
|
seen.incl(windowIdx)
|
|
|
|
check seen.len.uint64 == totalWindows
|
|
check cursor.isDone
|
|
|
|
test "Different inits produce different permutations":
|
|
let
|
|
windowSize = 100'u64
|
|
totalBlocks = 10000'u64
|
|
totalWindows = totalBlocks div windowSize
|
|
|
|
var
|
|
cursor1 = initRandomWindowCursor(totalBlocks, windowSize)
|
|
cursor2 = initRandomWindowCursor(totalBlocks, windowSize)
|
|
same = 0
|
|
|
|
if cursor1.currentWindow().start == cursor2.currentWindow().start:
|
|
same += 1
|
|
|
|
for i in 1'u64 ..< totalWindows:
|
|
discard cursor1.advance()
|
|
discard cursor2.advance()
|
|
if cursor1.currentWindow().start == cursor2.currentWindow().start:
|
|
same += 1
|
|
|
|
check same < 50
|
|
|
|
test "Edge case: single window":
|
|
var cursor = initRandomWindowCursor(50, 100)
|
|
check cursor.currentWindow().start == 0
|
|
check cursor.currentWindow().count == 50
|
|
check cursor.isDone
|
|
|
|
test "Edge case: two windows":
|
|
var
|
|
cursor = initRandomWindowCursor(200, 100)
|
|
seen = initHashSet[uint64]()
|
|
seen.incl(cursor.currentWindow().start)
|
|
check cursor.advance()
|
|
seen.incl(cursor.currentWindow().start)
|
|
check seen.len == 2
|
|
check 0'u64 in seen
|
|
check 100'u64 in seen
|
|
check cursor.isDone
|
|
|
|
test "Last window is truncated when totalBlocks not divisible by windowSize":
|
|
var
|
|
cursor = initRandomWindowCursor(350, 100)
|
|
foundShort = false
|
|
|
|
if cursor.currentWindow().count < 100:
|
|
foundShort = true
|
|
while cursor.advance():
|
|
if cursor.currentWindow().count < 100:
|
|
foundShort = true
|
|
check cursor.currentWindow().count == 50
|
|
check foundShort
|
|
|
|
suite "DownloadContext Random Windows":
|
|
test "initRandomWindows sets up first window":
|
|
let
|
|
md = testManifestDesc(Cid.example, 65536, 100000)
|
|
ctx = DownloadContext.new(
|
|
DownloadDesc(md: md, count: 100000, selectionPolicy: spRandomWindow)
|
|
)
|
|
(start, count) = ctx.currentPresenceWindow()
|
|
check count > 0
|
|
check start < ctx.totalBlocks
|
|
check start + count <= ctx.totalBlocks
|
|
|
|
test "advanceWindow cycles through all windows":
|
|
let
|
|
blockSize = 65536'u32
|
|
windowSize = computeWindowSize(blockSize)
|
|
totalBlocks = windowSize * 5
|
|
md = testManifestDesc(Cid.example, blockSize, totalBlocks.int)
|
|
ctx = DownloadContext.new(
|
|
DownloadDesc(md: md, count: totalBlocks, selectionPolicy: spRandomWindow)
|
|
)
|
|
|
|
var windowStarts = initHashSet[uint64]()
|
|
windowStarts.incl(ctx.currentPresenceWindow().start)
|
|
|
|
for i in 1 ..< 5:
|
|
while true:
|
|
let batch = ctx.scheduler.take()
|
|
if batch.isNone:
|
|
break
|
|
ctx.scheduler.markComplete(batch.get().start)
|
|
|
|
check ctx.needsNextPresenceWindow()
|
|
discard ctx.advancePresenceWindow()
|
|
windowStarts.incl(ctx.currentPresenceWindow().start)
|
|
|
|
check windowStarts.len == 5
|
|
check not ctx.needsNextPresenceWindow()
|
|
|
|
test "scheduler.isEmpty returns true when all batches complete":
|
|
let
|
|
md = testManifestDesc(Cid.example, 65536, 100)
|
|
ctx = DownloadContext.new(
|
|
DownloadDesc(md: md, count: 100, selectionPolicy: spRandomWindow)
|
|
)
|
|
while true:
|
|
let batch = ctx.scheduler.take()
|
|
if batch.isNone:
|
|
break
|
|
ctx.scheduler.markComplete(batch.get().start)
|
|
check ctx.scheduler.isEmpty
|
|
|
|
test "File smaller than 1 window (single window)":
|
|
let
|
|
blockSize = 65536'u32
|
|
windowSize = computeWindowSize(blockSize)
|
|
totalBlocks = windowSize div 2
|
|
md = testManifestDesc(Cid.example, blockSize, totalBlocks.int)
|
|
ctx = DownloadContext.new(
|
|
DownloadDesc(md: md, count: totalBlocks, selectionPolicy: spRandomWindow)
|
|
)
|
|
(start, count) = ctx.currentPresenceWindow()
|
|
|
|
check start == 0
|
|
check count == totalBlocks
|
|
check not ctx.needsNextPresenceWindow()
|
|
|
|
test "File exactly N windows":
|
|
let
|
|
blockSize = 65536'u32
|
|
windowSize = computeWindowSize(blockSize)
|
|
totalBlocks = windowSize * 3
|
|
md = testManifestDesc(Cid.example, blockSize, totalBlocks.int)
|
|
ctx = DownloadContext.new(
|
|
DownloadDesc(md: md, count: totalBlocks, selectionPolicy: spRandomWindow)
|
|
)
|
|
|
|
var count = 1
|
|
while true:
|
|
while true:
|
|
let batch = ctx.scheduler.take()
|
|
if batch.isNone:
|
|
break
|
|
ctx.scheduler.markComplete(batch.get().start)
|
|
|
|
if not ctx.needsNextPresenceWindow():
|
|
break
|
|
discard ctx.advancePresenceWindow()
|
|
count += 1
|
|
|
|
check count == 3
|