address some coord/node0 test issues

This commit is contained in:
Travis 2021-01-26 22:46:37 -06:00
parent 315cad679d
commit 4380a05bbd
No known key found for this signature in database
GPG key ID: 37080CC2042BA34E
8 changed files with 114 additions and 89 deletions

View file

@ -299,6 +299,7 @@ func TestAPI_ImportValue(t *testing.T) {
)
defer c.Close()
coord := c.GetCoordinator()
m0 := c.GetNode(0)
m1 := c.GetNode(1)
@ -307,11 +308,11 @@ func TestAPI_ImportValue(t *testing.T) {
index := "valck"
field := "f"
_, err := m0.API.CreateIndex(ctx, index, pilosa.IndexOptions{Keys: true})
_, err := coord.API.CreateIndex(ctx, index, pilosa.IndexOptions{Keys: true})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = m0.API.CreateField(ctx, index, field, pilosa.OptFieldTypeInt(math.MinInt64, math.MaxInt64))
_, err = coord.API.CreateField(ctx, index, field, pilosa.OptFieldTypeInt(math.MinInt64, math.MaxInt64))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -334,8 +335,8 @@ func TestAPI_ImportValue(t *testing.T) {
Values: values,
}
qcx := m0.API.Txf().NewQcx()
if err := m0.API.ImportValue(ctx, qcx, req); err != nil {
qcx := coord.API.Txf().NewQcx()
if err := coord.API.ImportValue(ctx, qcx, req); err != nil {
t.Fatal(err)
}
panicOn(qcx.Finish())
@ -376,7 +377,7 @@ func TestAPI_ImportValue(t *testing.T) {
t.Fatalf("creating field: %v", err)
}
// Generate some keyed records.
// Generate some records.
values := []float64{}
colIDs := []uint64{}
for i := 0; i < 10; i++ {
@ -384,8 +385,8 @@ func TestAPI_ImportValue(t *testing.T) {
colIDs = append(colIDs, uint64(i))
}
// Import data with keys to the coordinator (node0) and verify that it gets
// translated and forwarded to the owner of shard 0 (node1; because of offsetModHasher)
// Import data with keys to node1 and verify that it gets translated and
// forwarded to the owner of shard 0 (node0; because of offsetModHasher)
req := &pilosa.ImportValueRequest{
Index: index,
Field: field,
@ -431,16 +432,16 @@ func TestAPI_ImportValue(t *testing.T) {
fgnIndex := "fgnvalstr"
_, err := m0.API.CreateIndex(ctx, index, pilosa.IndexOptions{})
_, err := coord.API.CreateIndex(ctx, index, pilosa.IndexOptions{})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = m0.API.CreateIndex(ctx, fgnIndex, pilosa.IndexOptions{Keys: true})
_, err = coord.API.CreateIndex(ctx, fgnIndex, pilosa.IndexOptions{Keys: true})
if err != nil {
t.Fatalf("creating foreign index: %v", err)
}
_, err = m0.API.CreateField(ctx, index, field,
_, err = coord.API.CreateField(ctx, index, field,
pilosa.OptFieldTypeInt(0, math.MaxInt64),
pilosa.OptFieldForeignIndex(fgnIndex),
)
@ -457,8 +458,9 @@ func TestAPI_ImportValue(t *testing.T) {
colIDs = append(colIDs, uint64(i))
}
// Import data with keys to the coordinator (node0) and verify that it gets
// translated and forwarded to the owner of shard 0 (node1; because of offsetModHasher)
// Import data with keys to the node0 and verify that it gets translated
// and forwarded to the owner of shard 0 (node1; because of
// offsetModHasher)
req := &pilosa.ImportValueRequest{
Index: index,
Field: field,
@ -473,8 +475,8 @@ func TestAPI_ImportValue(t *testing.T) {
pql := fmt.Sprintf(`Row(%s=="strval-110")`, field)
// Query node0.
if res, err := m0.API.Query(ctx, &pilosa.QueryRequest{Index: index, Query: pql}); err != nil {
// Query node1.
if res, err := m1.API.Query(ctx, &pilosa.QueryRequest{Index: index, Query: pql}); err != nil {
t.Fatal(err)
} else if ids := res.Results[0].(*pilosa.Row).Columns(); !reflect.DeepEqual(ids, []uint64{1}) {
t.Fatalf("unexpected columns: observerd %+v; expected '%+v'", ids, []uint64{1})

View file

@ -402,6 +402,9 @@ func check(dirs []string, cfg *FsckConfig, targetIndex string, targetPartition i
return firstChecksum, nil
}
// These are here to satisfy the linter in CI while the test is being skipped.
var _ = getFwdRev
var _ = check
var _ = getChecksums
func getChecksums(dirs []string, cfg *FsckConfig, targetPartition int) (chksum []string) {

View file

@ -2957,11 +2957,11 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
hldr0 := c.GetHolder(0)
hldr1 := c.GetHolder(1)
_, err := c.GetNode(0).API.CreateIndex(context.Background(), "i", pilosa.IndexOptions{})
_, err := c.GetCoordinator().API.CreateIndex(context.Background(), "i", pilosa.IndexOptions{})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c.GetNode(0).API.CreateField(context.Background(), "i", "f", pilosa.OptFieldTypeSet(pilosa.DefaultCacheType, pilosa.DefaultCacheSize))
_, err = c.GetCoordinator().API.CreateField(context.Background(), "i", "f", pilosa.OptFieldTypeSet(pilosa.DefaultCacheType, pilosa.DefaultCacheSize))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -2994,7 +2994,7 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
})
t.Run("remote with timestamp", func(t *testing.T) {
_, err = c.GetNode(0).API.CreateField(context.Background(), "i", "z", pilosa.OptFieldTypeTime("Y"))
_, err = c.GetCoordinator().API.CreateField(context.Background(), "i", "z", pilosa.OptFieldTypeTime("Y"))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -3009,7 +3009,7 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
})
t.Run("remote topn", func(t *testing.T) {
_, err = c.GetNode(0).API.CreateField(context.Background(), "i", "fn", pilosa.OptFieldTypeSet(pilosa.CacheTypeRanked, 100))
_, err = c.GetCoordinator().API.CreateField(context.Background(), "i", "fn", pilosa.OptFieldTypeSet(pilosa.CacheTypeRanked, 100))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -3056,7 +3056,7 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
})
t.Run("remote groupBy", func(t *testing.T) {
if res, err := c.GetNode(1).API.Query(context.Background(), &pilosa.QueryRequest{
if res, err := c.GetNode(0).API.Query(context.Background(), &pilosa.QueryRequest{
Index: "i",
Query: `GroupBy(Rows(f))`,
}); err != nil {
@ -3072,7 +3072,7 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
})
t.Run("remote groupBy on ints", func(t *testing.T) {
_, err = c.GetNode(0).API.CreateField(context.Background(), "i", "fint", pilosa.OptFieldTypeInt(-1000, 1000))
_, err = c.GetCoordinator().API.CreateField(context.Background(), "i", "fint", pilosa.OptFieldTypeInt(-1000, 1000))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -3114,7 +3114,7 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
})
t.Run("groupBy on ints with offset regression", func(t *testing.T) {
_, err = c.GetNode(0).API.CreateField(context.Background(), "i", "hint", pilosa.OptFieldTypeInt(1, 1000))
_, err = c.GetCoordinator().API.CreateField(context.Background(), "i", "hint", pilosa.OptFieldTypeInt(1, 1000))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -3145,12 +3145,12 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
})
t.Run("Row on ints with ASSIGN condition", func(t *testing.T) {
_, err := c.GetNode(0).API.CreateIndex(context.Background(), "intidx", pilosa.IndexOptions{})
_, err := c.GetCoordinator().API.CreateIndex(context.Background(), "intidx", pilosa.IndexOptions{})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c.GetNode(0).API.CreateField(context.Background(), "intidx", "gint", pilosa.OptFieldTypeInt(-1000, 1000))
_, err = c.GetCoordinator().API.CreateField(context.Background(), "intidx", "gint", pilosa.OptFieldTypeInt(-1000, 1000))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -3180,12 +3180,12 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
})
t.Run("Row on decimals with ASSIGN condition", func(t *testing.T) {
_, err := c.GetNode(0).API.CreateIndex(context.Background(), "decidx", pilosa.IndexOptions{})
_, err := c.GetCoordinator().API.CreateIndex(context.Background(), "decidx", pilosa.IndexOptions{})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c.GetNode(0).API.CreateField(context.Background(), "decidx", "fdec", pilosa.OptFieldTypeDecimal(0))
_, err = c.GetCoordinator().API.CreateField(context.Background(), "decidx", "fdec", pilosa.OptFieldTypeDecimal(0))
if err != nil {
t.Fatalf("creating field: %v", err)
}
@ -3214,19 +3214,19 @@ func TestExecutor_Execute_Remote_Row(t *testing.T) {
})
t.Run("Row on foreign key with ASSIGN condition", func(t *testing.T) {
_, err := c.GetNode(0).API.CreateIndex(context.Background(), "parent", pilosa.IndexOptions{Keys: true})
_, err := c.GetCoordinator().API.CreateIndex(context.Background(), "parent", pilosa.IndexOptions{Keys: true})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c.GetNode(0).API.CreateField(context.Background(), "parent", "general", pilosa.OptFieldTypeSet(pilosa.DefaultCacheType, pilosa.DefaultCacheSize))
_, err = c.GetCoordinator().API.CreateField(context.Background(), "parent", "general", pilosa.OptFieldTypeSet(pilosa.DefaultCacheType, pilosa.DefaultCacheSize))
if err != nil {
t.Fatalf("creating field: %v", err)
}
_, err = c.GetNode(0).API.CreateIndex(context.Background(), "child", pilosa.IndexOptions{Keys: false})
_, err = c.GetCoordinator().API.CreateIndex(context.Background(), "child", pilosa.IndexOptions{Keys: false})
if err != nil {
t.Fatalf("creating index: %v", err)
}
_, err = c.GetNode(0).API.CreateField(context.Background(), "child", "parentid",
_, err = c.GetCoordinator().API.CreateField(context.Background(), "child", "parentid",
pilosa.OptFieldForeignIndex("parent"),
pilosa.OptFieldTypeInt(-9223372036854775808, 9223372036854775807),
)

View file

@ -49,15 +49,16 @@ func TestClient_MultiNode(t *testing.T) {
)
defer c.Close()
hldr := []test.Holder{}
for _, command := range c.Nodes {
hldr = append(hldr, test.Holder{Holder: command.Server.Holder()})
}
hldr0 := c.GetHolder(0)
hldr1 := c.GetHolder(1)
hldr2 := c.GetHolder(2)
// Create a dispersed set of bitmaps across 3 nodes such that each individual node and shard width increment would reveal a different TopN.
// Create a dispersed set of bitmaps across 3 nodes such that each
// individual node and shard width increment would reveal a different TopN.
shardNums := []uint64{1, 2, 6}
// This was generated with: `owns := s[i].Handler.Handler.API.Cluster.OwnsShards("i", 20, s[i].HostURI())`
// This was generated with:
// `owns := s[i].Handler.Handler.API.Cluster.OwnsShards("i", 20, s[i].HostURI())`
owns := [][]uint64{
{1, 3, 4, 8, 10, 13, 17, 19},
{2, 5, 7, 11, 12, 14, 18},
@ -96,26 +97,26 @@ func TestClient_MultiNode(t *testing.T) {
t.Fatalf("creating field: %v", err)
}
hldr[0].MustSetBits("i", "f", 100, baseBit0+10)
hldr[0].MustSetBits("i", "f", 4, baseBit0+10, baseBit0+11, baseBit0+12)
hldr[0].MustSetBits("i", "f", 4, baseBit0+10, baseBit0+11, baseBit0+12, baseBit0+13, baseBit0+14, baseBit0+15)
hldr[0].MustSetBits("i", "f", 2, baseBit0+1, baseBit0+2, baseBit0+3, baseBit0+4)
hldr[0].MustSetBits("i", "f", 3, baseBit0+1, baseBit0+2, baseBit0+3, baseBit0+4, baseBit0+5)
hldr[0].MustSetBits("i", "f", 22, baseBit0+1, baseBit0+2)
hldr0.MustSetBits("i", "f", 100, baseBit0+10)
hldr0.MustSetBits("i", "f", 4, baseBit0+10, baseBit0+11, baseBit0+12)
hldr0.MustSetBits("i", "f", 4, baseBit0+10, baseBit0+11, baseBit0+12, baseBit0+13, baseBit0+14, baseBit0+15)
hldr0.MustSetBits("i", "f", 2, baseBit0+1, baseBit0+2, baseBit0+3, baseBit0+4)
hldr0.MustSetBits("i", "f", 3, baseBit0+1, baseBit0+2, baseBit0+3, baseBit0+4, baseBit0+5)
hldr0.MustSetBits("i", "f", 22, baseBit0+1, baseBit0+2)
hldr[1].MustSetBits("i", "f", 99, baseBit1+1, baseBit1+2, baseBit1+3, baseBit1+4)
hldr[1].MustSetBits("i", "f", 100, baseBit1+1, baseBit1+2, baseBit1+3, baseBit1+4, baseBit1+5, baseBit1+6, baseBit1+7, baseBit1+8, baseBit1+9, baseBit1+10)
hldr[1].MustSetBits("i", "f", 98, baseBit1+1, baseBit1+2, baseBit1+3, baseBit1+4, baseBit1+5, baseBit1+6)
hldr[1].MustSetBits("i", "f", 1, baseBit1+4)
hldr[1].MustSetBits("i", "f", 22, baseBit1+1, baseBit1+2, baseBit1+3, baseBit1+4, baseBit1+5)
hldr1.MustSetBits("i", "f", 99, baseBit1+1, baseBit1+2, baseBit1+3, baseBit1+4)
hldr1.MustSetBits("i", "f", 100, baseBit1+1, baseBit1+2, baseBit1+3, baseBit1+4, baseBit1+5, baseBit1+6, baseBit1+7, baseBit1+8, baseBit1+9, baseBit1+10)
hldr1.MustSetBits("i", "f", 98, baseBit1+1, baseBit1+2, baseBit1+3, baseBit1+4, baseBit1+5, baseBit1+6)
hldr1.MustSetBits("i", "f", 1, baseBit1+4)
hldr1.MustSetBits("i", "f", 22, baseBit1+1, baseBit1+2, baseBit1+3, baseBit1+4, baseBit1+5)
hldr[2].MustSetBits("i", "f", 24, baseBit2+10, baseBit2+11, baseBit2+12, baseBit2+13, baseBit2+14)
hldr[2].MustSetBits("i", "f", 20, baseBit2+10, baseBit2+11, baseBit2+12, baseBit2+13)
hldr[2].MustSetBits("i", "f", 21, baseBit2+10)
hldr[2].MustSetBits("i", "f", 100, baseBit2+10)
hldr[2].MustSetBits("i", "f", 99, baseBit2+10, baseBit2+11, baseBit2+12)
hldr[2].MustSetBits("i", "f", 98, baseBit2+10, baseBit2+11)
hldr[2].MustSetBits("i", "f", 22, baseBit2+10, baseBit2+11, baseBit2+12)
hldr2.MustSetBits("i", "f", 24, baseBit2+10, baseBit2+11, baseBit2+12, baseBit2+13, baseBit2+14)
hldr2.MustSetBits("i", "f", 20, baseBit2+10, baseBit2+11, baseBit2+12, baseBit2+13)
hldr2.MustSetBits("i", "f", 21, baseBit2+10)
hldr2.MustSetBits("i", "f", 100, baseBit2+10)
hldr2.MustSetBits("i", "f", 99, baseBit2+10, baseBit2+11, baseBit2+12)
hldr2.MustSetBits("i", "f", 98, baseBit2+10, baseBit2+11)
hldr2.MustSetBits("i", "f", 22, baseBit2+10, baseBit2+11, baseBit2+12)
// Rebuild the RankCache.
// We have to do this to avoid the 10-second cache invalidation delay

View file

@ -695,8 +695,8 @@ func TestCluster_GossipMembership(t *testing.T) {
func TestClusterResize_RemoveNode(t *testing.T) {
cluster := test.MustRunCluster(t, 3)
defer cluster.Close()
m0 := cluster.GetNode(0)
m1 := cluster.GetNode(1)
coord := cluster.GetCoordinator()
other := cluster.GetNonCoordinator()
mustNodeID := func(baseURL string) string {
body := test.Do(t, "GET", fmt.Sprintf("%s/status", baseURL), "").Body
@ -712,7 +712,7 @@ func TestClusterResize_RemoveNode(t *testing.T) {
}
t.Run("ErrorRemoveInvalidNode", func(t *testing.T) {
resp := test.Do(t, "POST", m0.URL()+"/cluster/resize/remove-node", `{"id": "invalid-node-id"}`)
resp := test.Do(t, "POST", coord.URL()+"/cluster/resize/remove-node", `{"id": "invalid-node-id"}`)
expBody := "removing node: finding node to remove: node with provided ID does not exist"
if resp.StatusCode != http.StatusNotFound {
t.Fatalf("expected StatusCode %d but got %d", http.StatusNotFound, resp.StatusCode)
@ -722,8 +722,8 @@ func TestClusterResize_RemoveNode(t *testing.T) {
})
t.Run("ErrorRemoveCoordinator", func(t *testing.T) {
nodeID := mustNodeID(m0.URL())
resp := test.Do(t, "POST", m0.URL()+"/cluster/resize/remove-node", fmt.Sprintf(`{"id": "%s"}`, nodeID))
nodeID := mustNodeID(coord.URL())
resp := test.Do(t, "POST", coord.URL()+"/cluster/resize/remove-node", fmt.Sprintf(`{"id": "%s"}`, nodeID))
expBody := "removing node: calling node leave: coordinator cannot be removed; first, make a different node the new coordinator"
if resp.StatusCode != http.StatusInternalServerError {
@ -734,9 +734,9 @@ func TestClusterResize_RemoveNode(t *testing.T) {
})
t.Run("ErrorRemoveOnNonCoordinator", func(t *testing.T) {
coordinatorNodeID := mustNodeID(m0.URL())
nodeID := mustNodeID(m1.URL())
resp := test.Do(t, "POST", m1.URL()+"/cluster/resize/remove-node", fmt.Sprintf(`{"id": "%s"}`, nodeID))
coordinatorNodeID := mustNodeID(coord.URL())
nodeID := mustNodeID(other.URL())
resp := test.Do(t, "POST", other.URL()+"/cluster/resize/remove-node", fmt.Sprintf(`{"id": "%s"}`, nodeID))
expBody := fmt.Sprintf("removing node: calling node leave: node removal requests are only valid on the coordinator node: %s", coordinatorNodeID)
if resp.StatusCode != http.StatusInternalServerError {
@ -747,7 +747,7 @@ func TestClusterResize_RemoveNode(t *testing.T) {
})
t.Run("ErrorRemoveWithoutReplicas", func(t *testing.T) {
client0 := m0.Client()
client0 := coord.Client()
// Create indexes and fields on one node.
if err := client0.CreateIndex(context.Background(), "i", pilosa.IndexOptions{}); err != nil && err != pilosa.ErrIndexExists {
@ -763,12 +763,12 @@ func TestClusterResize_RemoveNode(t *testing.T) {
setColumns += fmt.Sprintf("Set(%d, f=1) ", i*pilosa.ShardWidth)
}
if _, err := m0.Query(t, "i", "", setColumns); err != nil {
if _, err := coord.Query(t, "i", "", setColumns); err != nil {
t.Fatal(err)
}
nodeID := mustNodeID(m1.URL())
resp := test.Do(t, "POST", m0.URL()+"/cluster/resize/remove-node", fmt.Sprintf(`{"id": "%s"}`, nodeID))
nodeID := mustNodeID(other.URL())
resp := test.Do(t, "POST", coord.URL()+"/cluster/resize/remove-node", fmt.Sprintf(`{"id": "%s"}`, nodeID))
expBody := "not enough data to perform resize"
if resp.StatusCode != http.StatusInternalServerError {
t.Fatalf("expected StatusCode %d but got %d", http.StatusInternalServerError, resp.StatusCode)

View file

@ -387,32 +387,31 @@ func TestTransactionsAPI(t *testing.T) {
cluster := test.MustRunCluster(t, 3)
defer cluster.Close()
api0 := cluster.GetNode(0).API
api1 := cluster.GetNode(1).API
coord := cluster.GetCoordinator().API
other := cluster.GetNonCoordinator().API
ctx := context.Background()
//api2 := cluster.GetNode(2).API
// can fetch empty transactions
if trnsMap, err := api0.Transactions(ctx); err != nil {
if trnsMap, err := coord.Transactions(ctx); err != nil {
t.Fatalf("getting transactions: %v", err)
} else if len(trnsMap) != 0 {
t.Fatalf("unexpectedly has transactions: %v", trnsMap)
}
// can't fetch transactions from non-coordinator
if _, err := api1.Transactions(ctx); err != pilosa.ErrNodeNotCoordinator {
if _, err := other.Transactions(ctx); err != pilosa.ErrNodeNotCoordinator {
t.Errorf("api1 should return ErrNodeNotCoordinator when asked for transactions but got: %v", err)
}
// can start transaction
if trns, err := api0.StartTransaction(ctx, "a", time.Minute, false, false); err != nil {
if trns, err := coord.StartTransaction(ctx, "a", time.Minute, false, false); err != nil {
t.Errorf("couldn't start transaction: %v", err)
} else {
test.CompareTransactions(t, &pilosa.Transaction{ID: "a", Active: true, Timeout: time.Minute, Deadline: time.Now().Add(time.Minute)}, trns)
}
// can retrieve transaction from other nodes with remote=true
if trns, err := api1.GetTransaction(ctx, "a", true); err != nil {
if trns, err := other.GetTransaction(ctx, "a", true); err != nil {
t.Errorf("couldn't fetch transaction from other node with remote=true: %v", err)
} else {
test.CompareTransactions(t, &pilosa.Transaction{ID: "a", Active: true, Timeout: time.Minute, Deadline: time.Now().Add(time.Minute)}, trns)
@ -420,7 +419,7 @@ func TestTransactionsAPI(t *testing.T) {
// can start transaction with blank id and get uuid back
id := ""
if trns, err := api0.StartTransaction(ctx, id, time.Minute, false, false); err != nil {
if trns, err := coord.StartTransaction(ctx, id, time.Minute, false, false); err != nil {
t.Errorf("couldn't start transaction: %v", err)
} else {
id = trns.ID
@ -431,54 +430,54 @@ func TestTransactionsAPI(t *testing.T) {
}
// can't finish transaction on non-coordinator
if _, err := api1.FinishTransaction(ctx, id, false); err != pilosa.ErrNodeNotCoordinator {
if _, err := other.FinishTransaction(ctx, id, false); err != pilosa.ErrNodeNotCoordinator {
t.Errorf("unexpected error is not ErrNodeNotCoordinator: %v", err)
}
// can finish transaction
if _, err := api0.FinishTransaction(ctx, id, false); err != nil {
if _, err := coord.FinishTransaction(ctx, id, false); err != nil {
t.Errorf("couldn't finish transaction: %v", err)
}
// can finish previous transaction
if _, err := api0.FinishTransaction(ctx, "a", false); err != nil {
if _, err := coord.FinishTransaction(ctx, "a", false); err != nil {
t.Errorf("couldn't finish transaction a: %v", err)
}
// can start exclusive transaction
if te, err := api0.StartTransaction(ctx, "exc", time.Minute, true, false); err != nil {
if te, err := coord.StartTransaction(ctx, "exc", time.Minute, true, false); err != nil {
t.Errorf("couldn't start exclusive transaction: %v", err)
} else if !te.Active {
t.Errorf("expected exclusive transaction to be active: %+v", te)
}
// can finish exclusive transaction
if _, err := api0.FinishTransaction(ctx, "exc", false); err != nil {
if _, err := coord.FinishTransaction(ctx, "exc", false); err != nil {
t.Errorf("couldn't finish exclusive transaction: %v", err)
}
// can start transaction (with same name as previous finished transaction)
if trns, err := api0.StartTransaction(ctx, "a", time.Minute, false, false); err != nil {
if trns, err := coord.StartTransaction(ctx, "a", time.Minute, false, false); err != nil {
t.Errorf("couldn't start transaction: %v", err)
} else {
test.CompareTransactions(t, &pilosa.Transaction{ID: "a", Active: true, Timeout: time.Minute, Deadline: time.Now().Add(time.Minute)}, trns)
}
// can start exclusive transaction and is not immediately active
if te, err := api0.StartTransaction(ctx, "exc", time.Minute, true, false); err != nil {
if te, err := coord.StartTransaction(ctx, "exc", time.Minute, true, false); err != nil {
t.Errorf("couldn't start exclusive transaction: %v", err)
} else if te.Active {
t.Errorf("expected exclusive transaction to be inactive: %+v", te)
}
// can finish non-exclusive transaction
if _, err := api0.FinishTransaction(ctx, "a", false); err != nil {
if _, err := coord.FinishTransaction(ctx, "a", false); err != nil {
t.Errorf("couldn't finish transaction a: %v", err)
}
// can poll exclusive transaction and is active
var excTrns *pilosa.Transaction
if trns, err := api0.GetTransaction(ctx, "exc", false); err != nil {
if trns, err := coord.GetTransaction(ctx, "exc", false); err != nil {
t.Errorf("couldn't poll exclusive transaction: %v", err)
} else {
excTrns = &pilosa.Transaction{ID: "exc", Active: true, Exclusive: true, Timeout: time.Minute, Deadline: time.Now().Add(time.Minute)}
@ -486,7 +485,7 @@ func TestTransactionsAPI(t *testing.T) {
}
// can't start another exclusive transaction
if trns, err := api0.StartTransaction(ctx, "exc2", time.Minute, true, false); errors.Cause(err) != pilosa.ErrTransactionExclusive {
if trns, err := coord.StartTransaction(ctx, "exc2", time.Minute, true, false); errors.Cause(err) != pilosa.ErrTransactionExclusive {
t.Errorf("unexpected error: %v", err)
} else {
// returned transaction should be the exclusive one which is blocking this one
@ -494,14 +493,14 @@ func TestTransactionsAPI(t *testing.T) {
}
// can't keep the second exclusive name but make it nonexclusive and start a transaction
if trns, err := api0.StartTransaction(ctx, "exc2", time.Minute, false, false); errors.Cause(err) != pilosa.ErrTransactionExclusive {
if trns, err := coord.StartTransaction(ctx, "exc2", time.Minute, false, false); errors.Cause(err) != pilosa.ErrTransactionExclusive {
t.Errorf("unexpected error: %v", err)
} else {
test.CompareTransactions(t, excTrns, trns)
}
// transaction is active on other nodes with remote=true
if trns, err := api1.GetTransaction(ctx, "exc", true); err != nil {
if trns, err := other.GetTransaction(ctx, "exc", true); err != nil {
t.Errorf("couldn't poll exclusive transaction: %v", err)
} else {
test.CompareTransactions(t, &pilosa.Transaction{ID: "exc", Active: true, Exclusive: true, Timeout: time.Minute, Deadline: time.Now().Add(time.Minute)}, trns)

View file

@ -178,6 +178,17 @@ func (c *Cluster) GetHolder(n int) *Holder {
return &Holder{Holder: c.GetNode(n).Server.Holder()}
}
// GetCoordinatorHolder returns the Holder for the coordinator node.
func (c *Cluster) GetCoordinatorHolder() *Holder {
return &Holder{Holder: c.GetCoordinator().Server.Holder()}
}
// GetNonCoordinatorHolder returns the Holder for the the first non-coordinator
// node in the list of nodes.
func (c *Cluster) GetNonCoordinatorHolder() *Holder {
return &Holder{Holder: c.GetNonCoordinator().Server.Holder()}
}
func (c *Cluster) Len() int {
return len(c.Nodes)
}
@ -442,6 +453,15 @@ func (c *Cluster) Close() error {
return nil
}
func (c *Cluster) CloseAndRemoveNonCoordinator() error {
for i, n := range c.Nodes {
if !n.IsCoordinator() {
return c.CloseAndRemove(i)
}
}
return errors.New("could not find non-coordinator node")
}
func (c *Cluster) CloseAndRemove(n int) error {
if n < 0 || n >= len(c.Nodes) {
return fmt.Errorf("close/remove from cluster: index %d out of range (len %d)", n, len(c.Nodes))

View file

@ -514,16 +514,16 @@ func TestTranslation_Replication(t *testing.T) {
exp := `{"results":[{"attrs":{},"columns":[],"keys":["x1","x2"]}]}`
if !test.CheckClusterState(coord, pilosa.ClusterStateNormal, 1000) {
t.Fatalf("unexpected node0 cluster state: %s", coord.API.State())
t.Fatalf("unexpected coord cluster state: %s", coord.API.State())
} else if !test.CheckClusterState(other, pilosa.ClusterStateNormal, 1000) {
t.Fatalf("unexpected node1 cluster state: %s", other.API.State())
t.Fatalf("unexpected other cluster state: %s", other.API.State())
}
// Verify the data exists
coord.QueryExpect(t, idx, "", `Row(f=1)`, exp)
// Kill one node.
if err := c.CloseAndRemove(1); err != nil {
// Kill a non-coordinator node.
if err := c.CloseAndRemoveNonCoordinator(); err != nil {
t.Fatal(err)
}