Skip to content

Commit 5d70c1c

Browse files
amcoliniennae
andauthored
fix(datastore): ensure idempotent index creation in tests (#5493)
Co-authored-by: Jennifer Davis <sigje@google.com>
1 parent 3ca3f7f commit 5d70c1c

3 files changed

Lines changed: 101 additions & 43 deletions

File tree

datastore/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/GoogleCloudPlatform/golang-samples v0.0.0-20240724083556-7f760db013b7
88
github.com/google/uuid v1.6.0
99
google.golang.org/api v0.217.0
10+
google.golang.org/grpc v1.69.4
1011
)
1112

1213
require (
@@ -53,6 +54,5 @@ require (
5354
google.golang.org/genproto v0.0.0-20250115164207-1a7da9e5054f // indirect
5455
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect
5556
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
56-
google.golang.org/grpc v1.69.4 // indirect
5757
google.golang.org/protobuf v1.36.3 // indirect
5858
)

datastore/snippets/query_test.go

Lines changed: 80 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"bytes"
2222
"context"
2323
"log"
24+
"os"
25+
"reflect"
2426
"strings"
2527
"testing"
2628

@@ -29,23 +31,31 @@ import (
2931
"cloud.google.com/go/datastore/admin/apiv1/adminpb"
3032
"github.com/GoogleCloudPlatform/golang-samples/internal/testutil"
3133
"github.com/google/uuid"
34+
"google.golang.org/api/iterator"
35+
"google.golang.org/grpc/codes"
36+
"google.golang.org/grpc/status"
3237
)
3338

3439
var projectID string
3540

3641
func TestMain(m *testing.M) {
42+
os.Exit(testMain(m))
43+
}
44+
45+
func testMain(m *testing.M) int {
3746
tc, ok := testutil.ContextMain(m)
3847
if !ok {
39-
log.Fatal("test project not set up properly")
40-
return
48+
log.Print("test project not set up properly")
49+
return 1
4150
}
4251

4352
projectID = tc.ProjectID
4453

4554
ctx := context.Background()
4655
client, err := datastore.NewClient(ctx, projectID)
4756
if err != nil {
48-
log.Fatal(err)
57+
log.Print(err)
58+
return 1
4959
}
5060
defer client.Close()
5161

@@ -59,17 +69,22 @@ func TestMain(m *testing.M) {
5969
key := datastore.IncompleteKey("TaskList", nil)
6070
key, err = client.Put(ctx, key, &task)
6171
if err != nil {
62-
log.Fatal(err)
72+
log.Print(err)
73+
return 1
6374
}
6475

6576
// Run the sample test
66-
m.Run()
77+
code := m.Run()
6778

6879
// Do teardown tasks
6980
err = client.Delete(ctx, key)
7081
if err != nil {
71-
log.Fatal(err)
82+
log.Print(err)
83+
if code == 0 {
84+
code = 1
85+
}
7286
}
87+
return code
7388
}
7489

7590
func TestNotEqualQuery(t *testing.T) {
@@ -176,42 +191,7 @@ func TestMultipleInequalitiesQuery(t *testing.T) {
176191
t.Cleanup(func() {
177192
adminClient.Close()
178193
})
179-
createOp, err := adminClient.CreateIndex(ctx, &adminpb.CreateIndexRequest{
180-
ProjectId: projectID,
181-
Index: &adminpb.Index{
182-
Kind: "Task",
183-
Ancestor: adminpb.Index_NONE,
184-
Properties: []*adminpb.Index_IndexedProperty{
185-
{
186-
Name: "days",
187-
Direction: adminpb.Index_ASCENDING,
188-
},
189-
{
190-
Name: "priority",
191-
Direction: adminpb.Index_ASCENDING,
192-
},
193-
},
194-
},
195-
})
196-
if err != nil {
197-
t.Fatalf("CreateIndex: %v", err)
198-
}
199-
createdIndex, err := createOp.Wait(ctx)
200-
if err != nil {
201-
t.Fatalf("CreateIndex Wait: %v", err)
202-
}
203-
t.Cleanup(func() {
204-
deleteOp, err := adminClient.DeleteIndex(ctx, &adminpb.DeleteIndexRequest{
205-
ProjectId: projectID,
206-
IndexId: createdIndex.IndexId,
207-
})
208-
if err != nil {
209-
t.Errorf("DeleteIndex: %v", err)
210-
}
211-
if _, err := deleteOp.Wait(ctx); err != nil {
212-
t.Errorf("DeleteIndex Wait: %v", err)
213-
}
214-
})
194+
setupIndex(t, ctx, adminClient, projectID)
215195

216196
// Run query
217197
var buf bytes.Buffer
@@ -226,3 +206,61 @@ func TestMultipleInequalitiesQuery(t *testing.T) {
226206
t.Errorf("got %q, want %q", got, want)
227207
}
228208
}
209+
210+
func setupIndex(t *testing.T, ctx context.Context, adminClient *admin.DatastoreAdminClient, projectID string) {
211+
t.Helper()
212+
index := &adminpb.Index{
213+
Kind: "Task",
214+
Ancestor: adminpb.Index_NONE,
215+
Properties: []*adminpb.Index_IndexedProperty{
216+
{Name: "days", Direction: adminpb.Index_ASCENDING},
217+
{Name: "priority", Direction: adminpb.Index_ASCENDING},
218+
},
219+
}
220+
createOp, err := adminClient.CreateIndex(ctx, &adminpb.CreateIndexRequest{
221+
ProjectId: projectID,
222+
Index: index,
223+
})
224+
var indexID string
225+
if err != nil {
226+
if status.Code(err) == codes.AlreadyExists {
227+
it := adminClient.ListIndexes(ctx, &adminpb.ListIndexesRequest{ProjectId: projectID})
228+
for {
229+
idx, err := it.Next()
230+
if err == iterator.Done {
231+
break
232+
}
233+
if err != nil {
234+
t.Fatalf("ListIndexes: %v", err)
235+
}
236+
if idx.Kind == index.Kind && idx.Ancestor == index.Ancestor && reflect.DeepEqual(idx.Properties, index.Properties) {
237+
indexID = idx.IndexId
238+
break
239+
}
240+
}
241+
} else {
242+
t.Fatalf("CreateIndex: %v", err)
243+
}
244+
} else {
245+
createdIndex, err := createOp.Wait(ctx)
246+
if err != nil {
247+
t.Fatalf("CreateIndex Wait: %v", err)
248+
}
249+
indexID = createdIndex.IndexId
250+
}
251+
252+
if indexID != "" {
253+
t.Cleanup(func() {
254+
deleteOp, err := adminClient.DeleteIndex(ctx, &adminpb.DeleteIndexRequest{
255+
ProjectId: projectID,
256+
IndexId: indexID,
257+
})
258+
if err != nil {
259+
t.Errorf("DeleteIndex: %v", err)
260+
}
261+
if _, err := deleteOp.Wait(ctx); err != nil {
262+
t.Errorf("DeleteIndex Wait: %v", err)
263+
}
264+
})
265+
}
266+
}

firestore/query_multiple_inequality_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import (
1919
"context"
2020
"fmt"
2121
"os"
22+
"reflect"
2223
"strings"
2324
"testing"
2425

2526
"cloud.google.com/go/firestore"
2627
apiv1 "cloud.google.com/go/firestore/apiv1/admin"
2728
"cloud.google.com/go/firestore/apiv1/admin/adminpb"
29+
"google.golang.org/api/iterator"
2830
"google.golang.org/grpc/codes"
2931
"google.golang.org/grpc/status"
3032
)
@@ -159,6 +161,24 @@ func TestMultipleInequalitiesQuery(t *testing.T) {
159161
// Fail the test only if the index does not already exist
160162
t.Fatalf("CreateIndex: %v", createErr)
161163
}
164+
// Index already exists, find it for cleanup
165+
it := adminClient.ListIndexes(ctx, &adminpb.ListIndexesRequest{
166+
Parent: req.Parent,
167+
})
168+
for {
169+
idx, err := it.Next()
170+
if err == iterator.Done {
171+
break
172+
}
173+
if err != nil {
174+
t.Fatalf("ListIndexes: %v", err)
175+
}
176+
// Compare fields to find the right index
177+
if reflect.DeepEqual(idx.Fields, adminPbIndexFields) {
178+
createdIndex = idx
179+
break
180+
}
181+
}
162182
} else {
163183
createdIndex, waitErr = op.Wait(ctx)
164184
if waitErr != nil {

0 commit comments

Comments
 (0)