osbase/logtree: add WithStartPosition option
To allow users to not always request all messages,
we introduce another option to the logtree.LogReader
which allows for starting at a specific global log id.
This, for example, makes implementing scrollback easier.
Change-Id: I1773288f670f476706d94baf3f052fe1e5da9eb0
Reviewed-on: https://review.monogon.dev/c/monogon/+/4452
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/osbase/logtree/logtree_access_test.go b/osbase/logtree/logtree_access_test.go
new file mode 100644
index 0000000..8379fd3
--- /dev/null
+++ b/osbase/logtree/logtree_access_test.go
@@ -0,0 +1,166 @@
+// Copyright The Monogon Project Authors.
+// SPDX-License-Identifier: Apache-2.0
+
+package logtree
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+)
+
+func TestJournalStartPosition(t *testing.T) {
+ lt := New()
+
+ for i := 0; i < 100; i += 1 {
+ e := &entry{
+ origin: "main",
+ leveled: testPayload(fmt.Sprintf("test %d", i)),
+ }
+ lt.journal.append(e)
+ }
+
+ type tCase struct {
+ name string
+
+ count int
+ direction ReadDirection
+ pos int
+
+ expectedCount int
+ expectedFirst string
+ expectedLast string
+ }
+
+ for _, tc := range []tCase{
+ {
+ name: "fetch all before id 0",
+ count: BacklogAllAvailable,
+ direction: ReadDirectionBefore,
+ pos: 0,
+
+ expectedCount: 0,
+ expectedFirst: "UNREACHABLE",
+ expectedLast: "UNREACHABLE",
+ },
+ {
+ name: "fetch all after id 0",
+ count: BacklogAllAvailable,
+ direction: ReadDirectionAfter,
+ pos: 0,
+
+ expectedCount: 100,
+ expectedFirst: "test 0",
+ expectedLast: "test 99",
+ },
+
+ {
+ name: "fetch all before id 10",
+ count: BacklogAllAvailable,
+ direction: ReadDirectionBefore,
+ pos: 10,
+
+ expectedCount: 10,
+ expectedFirst: "test 0",
+ expectedLast: "test 9",
+ },
+ {
+ name: "fetch all after id 10",
+ count: BacklogAllAvailable,
+ direction: ReadDirectionAfter,
+ pos: 10,
+
+ expectedCount: 90,
+ expectedFirst: "test 10",
+ expectedLast: "test 99",
+ },
+
+ {
+ name: "fetch 10 before id 0",
+ count: 10,
+ direction: ReadDirectionBefore,
+ pos: 0,
+
+ expectedCount: 0,
+ expectedFirst: "UNREACHABLE",
+ expectedLast: "UNREACHABLE",
+ },
+ {
+ name: "fetch 10 after id 0",
+ count: 10,
+ direction: ReadDirectionAfter,
+ pos: 0,
+
+ expectedCount: 10,
+ expectedFirst: "test 0",
+ expectedLast: "test 9",
+ },
+
+ {
+ name: "fetch 10 before id 3",
+ count: 10,
+ direction: ReadDirectionBefore,
+ pos: 3,
+
+ expectedCount: 3,
+ expectedFirst: "test 0",
+ expectedLast: "test 2",
+ },
+ {
+ name: "fetch 10 after id 3",
+ count: 10,
+ direction: ReadDirectionAfter,
+ pos: 3,
+
+ expectedCount: 10,
+ expectedFirst: "test 3",
+ expectedLast: "test 12",
+ },
+ {
+ name: "fetch 43 before id 47",
+ count: 43,
+ direction: ReadDirectionBefore,
+ pos: 47,
+
+ expectedCount: 43,
+ expectedFirst: "test 4",
+ expectedLast: "test 46",
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ lr, _ := lt.Read("main",
+ WithBacklog(tc.count),
+ WithStartPosition(tc.pos, tc.direction),
+ )
+ if l := len(lr.Backlog); l != tc.expectedCount {
+ t.Fatalf("expected %d entries, got %d", tc.expectedCount, l)
+ }
+ if len(lr.Backlog) == 0 {
+ // If there is nothing to test against, skip to next test.
+ return
+ }
+ if first := strings.Join(lr.Backlog[0].Leveled.messages, "\n"); first != tc.expectedFirst {
+ t.Errorf("wanted first entry %q, got %q", tc.expectedFirst, first)
+ }
+ if last := strings.Join(lr.Backlog[len(lr.Backlog)-1].Leveled.messages, "\n"); last != tc.expectedLast {
+ t.Errorf("wanted last entry %q, got %q", tc.expectedLast, last)
+ }
+ for i, entry := range lr.Backlog {
+ // If we skip messages and are reading oldest first, adapt the
+ // id to the expected position
+ if tc.pos != 0 && tc.direction == ReadDirectionAfter {
+ i = tc.pos + i
+ }
+ if tc.count != BacklogAllAvailable && tc.pos != 0 && tc.direction == ReadDirectionBefore {
+ // Limit the negative offset to 0
+ i = max(0, tc.pos-tc.count) + i
+ }
+ want := fmt.Sprintf("test %d", i)
+ got := strings.Join(entry.Leveled.messages, "\n")
+ if want != got {
+ t.Errorf("wanted entry %q, got %q", want, got)
+ }
+ }
+ })
+ }
+}