1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
package generics_tree
import (
"bufio"
"fmt"
"log"
"os"
"strings"
"testing"
"github.com/kentik/patricia"
"github.com/stretchr/testify/assert"
)
func TestBulkLoad(t *testing.T) {
// Test bulk loading
filePath := "../test_tags.tsv"
recordsToLoad := -1 // -1 == all
tree := NewTreeV4[string]()
var ipToTags map[string]string
var ips []string
// insert the tags
load := func() {
ipToTags = make(map[string]string)
ips = make([]string, 0)
file, err := os.Open(filePath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
fmt.Printf("Loading up to %d tags:\n", recordsToLoad)
scanner := bufio.NewScanner(file)
recordsLoaded := 0
for scanner.Scan() {
if recordsToLoad > 0 {
if recordsLoaded == recordsToLoad {
fmt.Printf("Loaded %d: done\n", recordsToLoad)
break
}
}
recordsLoaded++
line := scanner.Text()
parts := strings.Split(line, "\t")
if len(parts) != 2 {
panic(fmt.Sprintf("Line should have 2 parts: %s\n", line))
}
ipToTags[parts[0]] = parts[1]
ips = append(ips, parts[0])
v4, v6, err := patricia.ParseIPFromString(parts[0])
if err != nil {
panic(fmt.Sprintf("insert: Could not parse IP '%s': %s", parts[0], err))
}
if v4 != nil {
tree.Add(*v4, parts[1], nil)
continue
}
if v6 == nil {
panic(fmt.Sprintf("insert: Didn't get v4 or v6 address from line: '%s'", line))
}
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
fmt.Printf("done - loaded %d tags\n", recordsLoaded)
fmt.Printf("tree says loaded %d tags into %d nodes\n", tree.countTags(1), tree.countNodes(1))
assert.Equal(t, recordsLoaded, int(tree.countTags(1)))
assert.Equal(t, recordsLoaded, tree.CountTags())
}
buf := make([]string, 0)
evaluate := func() {
fmt.Printf("# of nodes: %d\n", len(tree.nodes))
// query all tags from each address, query specific tag from each address, delete the tag
for _, address := range ips {
tag := ipToTags[address]
v4, v6, err := patricia.ParseIPFromString(address)
if err != nil {
panic(fmt.Sprintf("search: Could not parse IP '%s': %s", address, err))
}
if v4 != nil {
foundTags := tree.FindTagsAppend(buf, *v4)
if assert.True(t, len(foundTags) > 0, "Couldn't find tags for "+address) {
assert.True(t, tag == foundTags[len(foundTags)-1])
}
found, foundTag := tree.FindDeepestTag(*v4)
assert.True(t, found, "Couldn't find deepest tag")
assert.True(t, tag == foundTag)
// delete the tags now
//fmt.Printf("Deleting %s: %s\n", address, tag)
deleteCount := tree.DeleteWithBuffer(buf, *v4, func(a string, b string) bool { return a == b }, tag)
assert.Equal(t, 1, deleteCount, "Tried deleting tag")
//tree.print()
} else if v6 == nil {
panic(fmt.Sprintf("search: Didn't get v4 or v6 address from address: '%s'", address))
}
}
// should be nothing left
assert.Equal(t, 0, tree.countTags(1))
assert.Equal(t, 1, tree.countNodes(1))
fmt.Printf("Finished looping, finding, deleting - Tree now has %d tags in %d logical nodes, %d capacity, %d node objects in use, %d available indexes\n", tree.countTags(1), tree.countNodes(1), cap(tree.nodes), len(tree.nodes), len(tree.availableIndexes))
}
//tree.print()
load()
evaluate()
nodesCapacity := cap(tree.nodes)
nodesLength := len(tree.nodes)
fmt.Printf("Finished first pass - node capacity: %d\n", cap(tree.nodes))
// do it again a few times, and make sure the nodes array hasn't grown
load()
evaluate()
load()
evaluate()
load()
evaluate()
load()
evaluate()
assert.Equal(t, nodesLength, len(tree.nodes))
assert.Equal(t, nodesCapacity, cap(tree.nodes))
fmt.Printf("Finished looping, finding, deleting - Tree now has %d tags in %d nodes\n", tree.countTags(1), tree.countNodes(1))
// now try cloning
load()
tree = tree.Clone()
evaluate()
assert.Equal(t, nodesLength, len(tree.nodes))
assert.Equal(t, nodesCapacity, cap(tree.nodes))
//print()
}
|