X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/c220fd0ce751005b675283b5c778d74bf5b8f630..6755f2645bf6bcf8c7cd5b1f3a682a11bf2392f5:/tree_test.go?ds=sidebyside diff --git a/tree_test.go b/tree_test.go index 2e7ff3a..ece7c6f 100644 --- a/tree_test.go +++ b/tree_test.go @@ -58,9 +58,7 @@ func TestTreeBuildsEachNodeOnce(t *testing.T) { require.NoError(t, tree.Add(testNode(0, 1, "reply: b"))) require.NoError(t, tree.Add(testNode(1, 0, "a b"))) - node, built := tree.Node(0, 0) - require.True(t, built) - require.Equal(t, "user: a", node.Text) + require.Equal(t, "user: a", readNode(t, tree, 0, 0).Text) } func TestTreeReopenLoadsTheSameNodes(t *testing.T) { @@ -91,15 +89,93 @@ func TestTreeReopenLoadsTheSameNodes(t *testing.T) { require.NoError(t, tree.Close()) }() - require.Len(t, tree.nodes, len(nodes)) + require.Equal(t, len(nodes), tree.Count()) for _, node := range nodes { - loaded, built := tree.Node(node.Level, node.Index) - require.True(t, built) - require.Equal(t, node, loaded) + require.Equal(t, node, readNode(t, tree, node.Level, node.Index)) } +} + +func TestTreeBuildsAMissingIndexAgain(t *testing.T) { + root := t.TempDir() + clock := newTestClock() + tree, err := openTree(t.Context(), root, 2, clock.Now) + require.NoError(t, err) + + nodes := []Node{ + testNode(0, 1, "reply: b"), + testNode(0, 0, "user: a"), + testNode(1, 0, "user: a\nreply: b"), + } + for _, node := range nodes { + require.NoError(t, tree.Add(node)) + } + + require.NoError(t, tree.Close()) + require.NoError(t, os.RemoveAll(filepath.Join(root, "index"))) _, err = openTree(t.Context(), root, 1, clock.Now) require.ErrorContains(t, err, "covers messages after the log") + require.NoError(t, os.RemoveAll(filepath.Join(root, "index"))) + + tree, err = openTree(t.Context(), root, 2, clock.Now) + require.NoError(t, err) + + defer func() { + require.NoError(t, tree.Close()) + }() + + require.Equal(t, len(nodes), tree.Count()) + for _, node := range nodes { + require.Equal(t, node, readNode(t, tree, node.Level, node.Index)) + } +} + +func TestTreeIndexesTheNodesAfterACrash(t *testing.T) { + root := t.TempDir() + clock := newTestClock() + tree, err := openTree(t.Context(), root, 2, clock.Now) + require.NoError(t, err) + + require.NoError(t, tree.Add(testNode(0, 0, "user: a"))) + require.NoError(t, tree.Add(testNode(0, 1, "reply: b"))) + require.NoError(t, tree.Close()) + + // A crash after the line write and in the middle of the index writes. + order := filepath.Join(root, "index", "tree.idx") + require.NoError(t, os.Truncate(order, treeRecordBytes+5)) + require.NoError(t, os.Truncate(filepath.Join(root, "index", "tree-0.idx"), positionBytes)) + + tree, err = openTree(t.Context(), root, 2, clock.Now) + require.NoError(t, err) + + defer func() { + require.NoError(t, tree.Close()) + }() + + require.Equal(t, 2, tree.Count()) + require.Equal(t, "reply: b", readNode(t, tree, 0, 1).Text) + require.NoError(t, tree.Add(testNode(1, 0, "user: a\nreply: b"))) +} + +// isBuilt tells if the node (l, i) of tree is built. +func isBuilt(t *testing.T, tree *Tree, level, index int) bool { + t.Helper() + + built, err := tree.Built(level, index) + require.NoError(t, err) + + return built +} + +// readNode reads the node (l, i) of tree, which must be built. +func readNode(t *testing.T, tree *Tree, level, index int) Node { + t.Helper() + + node, built, err := tree.Node(level, index) + require.NoError(t, err) + require.True(t, built, "node (%d, %d)", level, index) + + return node } func testNode(level, index int, text string) Node {