blob: 673b0fd4d266b350c55384a4dd605dfc3751d1f4 [file] [log] [blame]
Adam Sadovskyaba9d502015-04-10 22:06:06 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Adam Sadovskyaba9d502015-04-10 22:06:06 -07005package nosql_test
6
Adam Sadovskyaba9d502015-04-10 22:06:06 -07007import (
Adam Sadovsky13922e32015-05-19 17:39:59 -07008 "reflect"
Adam Sadovskyaba9d502015-04-10 22:06:06 -07009 "testing"
Sergey Rogulenko1f988de2015-08-14 17:00:09 -070010 "time"
Adam Sadovskyaba9d502015-04-10 22:06:06 -070011
Sergey Rogulenko1f988de2015-08-14 17:00:09 -070012 wire "v.io/syncbase/v23/services/syncbase/nosql"
Adam Sadovskyaba9d502015-04-10 22:06:06 -070013 "v.io/syncbase/v23/syncbase"
Adam Sadovsky13922e32015-05-19 17:39:59 -070014 "v.io/syncbase/v23/syncbase/nosql"
John Kline4894fb12015-06-17 09:06:56 -070015 "v.io/syncbase/v23/syncbase/nosql/syncql"
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -070016 tu "v.io/syncbase/v23/syncbase/testutil"
Sergey Rogulenko1f988de2015-08-14 17:00:09 -070017 "v.io/v23/context"
Adam Sadovskyfd0cd952015-06-04 22:23:51 -070018 "v.io/v23/naming"
Sergey Rogulenko1f988de2015-08-14 17:00:09 -070019 "v.io/v23/services/watch"
John Kline4894fb12015-06-17 09:06:56 -070020 "v.io/v23/vdl"
Adam Sadovsky13922e32015-05-19 17:39:59 -070021 "v.io/v23/verror"
Sergey Rogulenko1f988de2015-08-14 17:00:09 -070022 "v.io/v23/vom"
Adam Sadovsky67e5f7c2015-05-11 16:04:15 -070023 _ "v.io/x/ref/runtime/factories/generic"
Adam Sadovskyaba9d502015-04-10 22:06:06 -070024)
25
Adam Sadovskyaba9d502015-04-10 22:06:06 -070026// TODO(sadovsky): Finish writing tests.
Sergey Rogulenko445e0412015-06-18 23:06:11 -070027// TODO(rogulenko): Test perms checking for Glob and Exec.
Adam Sadovskyaba9d502015-04-10 22:06:06 -070028
Adam Sadovskyfd0cd952015-06-04 22:23:51 -070029// Tests various Name, FullName, and Key methods.
Adam Sadovskyaba9d502015-04-10 22:06:06 -070030func TestNameAndKey(t *testing.T) {
Jatin Lodhiaaf93faa2015-07-17 15:57:36 -070031 d := syncbase.NewService("s").App("a").NoSQLDatabase("d", nil)
Adam Sadovskyaba9d502015-04-10 22:06:06 -070032 tb := d.Table("tb")
33 r := tb.Row("r")
34
35 if d.Name() != "d" {
Adam Sadovsky13922e32015-05-19 17:39:59 -070036 t.Errorf("Wrong name: %q", d.Name())
Adam Sadovskyaba9d502015-04-10 22:06:06 -070037 }
Adam Sadovskyfd0cd952015-06-04 22:23:51 -070038 if d.FullName() != naming.Join("s", "a", "d") {
39 t.Errorf("Wrong full name: %q", d.FullName())
40 }
Adam Sadovskyaba9d502015-04-10 22:06:06 -070041 if tb.Name() != "tb" {
Adam Sadovsky13922e32015-05-19 17:39:59 -070042 t.Errorf("Wrong name: %q", tb.Name())
Adam Sadovskyaba9d502015-04-10 22:06:06 -070043 }
Adam Sadovskyfd0cd952015-06-04 22:23:51 -070044 if tb.FullName() != naming.Join("s", "a", "d", "tb") {
45 t.Errorf("Wrong full name: %q", tb.FullName())
46 }
Adam Sadovskyaba9d502015-04-10 22:06:06 -070047 if r.Key() != "r" {
Adam Sadovsky13922e32015-05-19 17:39:59 -070048 t.Errorf("Wrong key: %q", r.Key())
Adam Sadovskyaba9d502015-04-10 22:06:06 -070049 }
Adam Sadovskyfd0cd952015-06-04 22:23:51 -070050 if r.FullName() != naming.Join("s", "a", "d", "tb", "r") {
51 t.Errorf("Wrong full name: %q", r.FullName())
52 }
Adam Sadovskyaba9d502015-04-10 22:06:06 -070053}
54
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -070055// Tests that Database.Create works as expected.
56func TestDatabaseCreate(t *testing.T) {
57 ctx, sName, cleanup := tu.SetupOrDie(nil)
Adam Sadovskyaba9d502015-04-10 22:06:06 -070058 defer cleanup()
Adam Sadovsky13922e32015-05-19 17:39:59 -070059 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -070060 tu.TestCreate(t, ctx, a)
Adam Sadovskyaba9d502015-04-10 22:06:06 -070061}
62
John Kline4894fb12015-06-17 09:06:56 -070063// Tests that Database.Exec works as expected.
64// Note: More comprehensive client/server tests are in the exec_test
65// directory. Also, exec is tested in its entirety in
66// v23/syncbase/nosql/internal/query/...
67func TestExec(t *testing.T) {
68 ctx, sName, cleanup := tu.SetupOrDie(nil)
69 defer cleanup()
70 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
71 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
72 tb := tu.CreateTable(t, ctx, d, "tb")
73
74 foo := Foo{I: 4, S: "f"}
75 if err := tb.Put(ctx, "foo", foo); err != nil {
76 t.Fatalf("tb.Put() failed: %v", err)
77 }
78
79 bar := Bar{F: 0.5, S: "b"}
80 // NOTE: not best practice, but store bar as
81 // optional (by passing the address of bar to Put).
82 // This tests auto-dereferencing.
83 if err := tb.Put(ctx, "bar", &bar); err != nil {
84 t.Fatalf("tb.Put() failed: %v", err)
85 }
86
87 baz := Baz{Name: "John Doe", Active: true}
88 if err := tb.Put(ctx, "baz", baz); err != nil {
89 t.Fatalf("tb.Put() failed: %v", err)
90 }
91
John Kline6bf4e902015-08-03 13:28:41 -070092 tu.CheckExec(t, ctx, d, "select k, v.Name from tb where Type(v) like \"%.Baz\"",
John Kline4894fb12015-06-17 09:06:56 -070093 []string{"k", "v.Name"},
94 [][]*vdl.Value{
95 []*vdl.Value{vdl.ValueOf("baz"), vdl.ValueOf(baz.Name)},
96 })
97
98 tu.CheckExec(t, ctx, d, "select k, v from tb",
99 []string{"k", "v"},
100 [][]*vdl.Value{
101 []*vdl.Value{vdl.ValueOf("bar"), vdl.ValueOf(bar)},
102 []*vdl.Value{vdl.ValueOf("baz"), vdl.ValueOf(baz)},
103 []*vdl.Value{vdl.ValueOf("foo"), vdl.ValueOf(foo)},
104 })
105
106 tu.CheckExec(t, ctx, d, "select k, v from tb where k like \"ba%\"",
107 []string{"k", "v"},
108 [][]*vdl.Value{
109 []*vdl.Value{vdl.ValueOf("bar"), vdl.ValueOf(bar)},
110 []*vdl.Value{vdl.ValueOf("baz"), vdl.ValueOf(baz)},
111 })
112
113 tu.CheckExec(t, ctx, d, "select k, v from tb where v.Active = true",
114 []string{"k", "v"},
115 [][]*vdl.Value{
116 []*vdl.Value{vdl.ValueOf("baz"), vdl.ValueOf(baz)},
117 })
118
John Kline6bf4e902015-08-03 13:28:41 -0700119 tu.CheckExec(t, ctx, d, "select k, v from tb where Type(v) like \"%.Bar\"",
John Kline4894fb12015-06-17 09:06:56 -0700120 []string{"k", "v"},
121 [][]*vdl.Value{
122 []*vdl.Value{vdl.ValueOf("bar"), vdl.ValueOf(bar)},
123 })
124
125 tu.CheckExec(t, ctx, d, "select k, v from tb where v.F = 0.5",
126 []string{"k", "v"},
127 [][]*vdl.Value{
128 []*vdl.Value{vdl.ValueOf("bar"), vdl.ValueOf(bar)},
129 })
130
John Kline6bf4e902015-08-03 13:28:41 -0700131 tu.CheckExec(t, ctx, d, "select k, v from tb where Type(v) like \"%.Baz\"",
John Kline4894fb12015-06-17 09:06:56 -0700132 []string{"k", "v"},
133 [][]*vdl.Value{
134 []*vdl.Value{vdl.ValueOf("baz"), vdl.ValueOf(baz)},
135 })
136
137 tu.CheckExecError(t, ctx, d, "select k, v from foo", syncql.ErrTableCantAccess.ID)
138}
139
Adam Sadovskyaba9d502015-04-10 22:06:06 -0700140// Tests that Database.Delete works as expected.
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -0700141func TestDatabaseDelete(t *testing.T) {
142 ctx, sName, cleanup := tu.SetupOrDie(nil)
143 defer cleanup()
Adam Sadovsky13922e32015-05-19 17:39:59 -0700144 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -0700145 tu.TestDelete(t, ctx, a)
Adam Sadovskyaba9d502015-04-10 22:06:06 -0700146}
147
Adam Sadovsky13922e32015-05-19 17:39:59 -0700148// Tests that Database.ListTables works as expected.
149func TestListTables(t *testing.T) {
150 ctx, sName, cleanup := tu.SetupOrDie(nil)
151 defer cleanup()
152 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
153 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
154 tu.TestListChildren(t, ctx, d)
155}
156
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -0700157// Tests that Database.{Set,Get}Permissions work as expected.
158func TestDatabasePerms(t *testing.T) {
159 ctx, sName, cleanup := tu.SetupOrDie(nil)
160 defer cleanup()
Adam Sadovsky13922e32015-05-19 17:39:59 -0700161 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
162 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -0700163 tu.TestPerms(t, ctx, d)
Adam Sadovskyaba9d502015-04-10 22:06:06 -0700164}
165
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -0700166// Tests that Database.CreateTable works as expected.
167func TestTableCreate(t *testing.T) {
Adam Sadovsky13922e32015-05-19 17:39:59 -0700168 ctx, sName, cleanup := tu.SetupOrDie(nil)
169 defer cleanup()
170 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
171 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
172 tu.TestCreate(t, ctx, d)
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -0700173}
174
175// Tests that Database.DeleteTable works as expected.
176func TestTableDelete(t *testing.T) {
Adam Sadovsky13922e32015-05-19 17:39:59 -0700177 ctx, sName, cleanup := tu.SetupOrDie(nil)
178 defer cleanup()
179 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
180 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
181 tu.TestDelete(t, ctx, d)
Adam Sadovskyfa5f16f2015-05-04 15:33:22 -0700182}
183
184// Tests that Table.{Set,Get,Delete}Permissions methods work as expected.
185func TestTablePerms(t *testing.T) {
Adam Sadovskyda069202015-06-24 12:56:11 -0700186 ctx, clientACtx, sName, rootp, cleanup := tu.SetupOrDieCustom("clientA", "server", nil)
Sergey Rogulenko445e0412015-06-18 23:06:11 -0700187 defer cleanup()
Adam Sadovskyda069202015-06-24 12:56:11 -0700188 clientBCtx := tu.NewCtx(ctx, rootp, "clientB")
Sergey Rogulenko445e0412015-06-18 23:06:11 -0700189 a := tu.CreateApp(t, clientACtx, syncbase.NewService(sName), "a")
190 d := tu.CreateNoSQLDatabase(t, clientACtx, a, "d")
191 tb := tu.CreateTable(t, clientACtx, d, "tb")
192
193 // Permission objects.
Adam Sadovskyda069202015-06-24 12:56:11 -0700194 aAndB := tu.DefaultPerms("root/clientA", "root/clientB")
195 aOnly := tu.DefaultPerms("root/clientA")
196 bOnly := tu.DefaultPerms("root/clientB")
Sergey Rogulenko445e0412015-06-18 23:06:11 -0700197
198 // Set initial permissions.
199 if err := tb.SetPermissions(clientACtx, nosql.Prefix(""), aAndB); err != nil {
200 t.Fatalf("tb.SetPermissions() failed: %v", err)
201 }
202 if err := tb.SetPermissions(clientACtx, nosql.Prefix("prefix"), aAndB); err != nil {
203 t.Fatalf("tb.SetPermissions() failed: %v", err)
204 }
205 if err := tb.SetPermissions(clientBCtx, nosql.Prefix("prefix"), aAndB); err != nil {
206 t.Fatalf("tb.SetPermissions() failed: %v", err)
207 }
208 if err := tb.SetPermissions(clientACtx, nosql.Prefix("prefix_a"), aOnly); err != nil {
209 t.Fatalf("tb.SetPermissions() failed: %v", err)
210 }
211 if err := tb.SetPermissions(clientBCtx, nosql.Prefix("prefix_b"), bOnly); err != nil {
212 t.Fatalf("tb.SetPermissions() failed: %v", err)
213 }
214
215 // Checks A has no access to 'prefix_b' and vice versa.
216 if err := tb.SetPermissions(clientACtx, nosql.Prefix("prefix_b"), aOnly); verror.ErrorID(err) != verror.ErrNoAccess.ID {
217 t.Fatalf("tb.SetPermissions() should have failed: %v", err)
218 }
219 if err := tb.SetPermissions(clientACtx, nosql.Prefix("prefix_b_suffix"), aOnly); verror.ErrorID(err) != verror.ErrNoAccess.ID {
220 t.Fatalf("tb.SetPermissions() should have failed: %v", err)
221 }
222 if err := tb.SetPermissions(clientBCtx, nosql.Prefix("prefix_a"), bOnly); verror.ErrorID(err) != verror.ErrNoAccess.ID {
223 t.Fatalf("tb.SetPermissions() should have failed: %v", err)
224 }
225 if err := tb.SetPermissions(clientBCtx, nosql.Prefix("prefix_a_suffix"), bOnly); verror.ErrorID(err) != verror.ErrNoAccess.ID {
226 t.Fatalf("tb.SetPermissions() should have failed: %v", err)
227 }
228
229 // Check GetPermissions.
230 wantPerms := []nosql.PrefixPermissions{
231 nosql.PrefixPermissions{Prefix: nosql.Prefix(""), Perms: aAndB},
232 }
233 if got, _ := tb.GetPermissions(clientACtx, ""); !reflect.DeepEqual(got, wantPerms) {
234 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
235 }
236 if got, _ := tb.GetPermissions(clientACtx, "abc"); !reflect.DeepEqual(got, wantPerms) {
237 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
238 }
239 wantPerms = []nosql.PrefixPermissions{
240 nosql.PrefixPermissions{Prefix: nosql.Prefix("prefix"), Perms: aAndB},
241 nosql.PrefixPermissions{Prefix: nosql.Prefix(""), Perms: aAndB},
242 }
243 if got, _ := tb.GetPermissions(clientACtx, "prefix"); !reflect.DeepEqual(got, wantPerms) {
244 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
245 }
246 if got, _ := tb.GetPermissions(clientACtx, "prefix_c"); !reflect.DeepEqual(got, wantPerms) {
247 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
248 }
249 wantPerms = []nosql.PrefixPermissions{
250 nosql.PrefixPermissions{Prefix: nosql.Prefix("prefix_a"), Perms: aOnly},
251 nosql.PrefixPermissions{Prefix: nosql.Prefix("prefix"), Perms: aAndB},
252 nosql.PrefixPermissions{Prefix: nosql.Prefix(""), Perms: aAndB},
253 }
254 if got, _ := tb.GetPermissions(clientACtx, "prefix_a"); !reflect.DeepEqual(got, wantPerms) {
255 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
256 }
257 if got, _ := tb.GetPermissions(clientACtx, "prefix_a_suffix"); !reflect.DeepEqual(got, wantPerms) {
258 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
259 }
260 wantPerms = []nosql.PrefixPermissions{
261 nosql.PrefixPermissions{Prefix: nosql.Prefix("prefix_b"), Perms: bOnly},
262 nosql.PrefixPermissions{Prefix: nosql.Prefix("prefix"), Perms: aAndB},
263 nosql.PrefixPermissions{Prefix: nosql.Prefix(""), Perms: aAndB},
264 }
265 if got, _ := tb.GetPermissions(clientACtx, "prefix_b"); !reflect.DeepEqual(got, wantPerms) {
266 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
267 }
268 if got, _ := tb.GetPermissions(clientACtx, "prefix_b_suffix"); !reflect.DeepEqual(got, wantPerms) {
269 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
270 }
271
272 // Delete some prefix permissions and check again.
273 // Check that A can't delete permissions of B.
274 if err := tb.DeletePermissions(clientACtx, nosql.Prefix("prefix_b")); verror.ErrorID(err) != verror.ErrNoAccess.ID {
275 t.Fatalf("tb.DeletePermissions() should have failed: %v", err)
276 }
277 if err := tb.DeletePermissions(clientBCtx, nosql.Prefix("prefix_a")); verror.ErrorID(err) != verror.ErrNoAccess.ID {
278 t.Fatalf("tb.DeletePermissions() should have failed: %v", err)
279 }
280 // Delete 'prefix' and 'prefix_a'
281 if err := tb.DeletePermissions(clientACtx, nosql.Prefix("prefix")); err != nil {
282 t.Fatalf("tb.DeletePermissions() failed: %v", err)
283 }
284 if err := tb.DeletePermissions(clientACtx, nosql.Prefix("prefix_a")); err != nil {
285 t.Fatalf("tb.DeletePermissions() failed: %v", err)
286 }
287 // Check DeletePermissions is idempotent.
288 if err := tb.DeletePermissions(clientACtx, nosql.Prefix("prefix")); err != nil {
289 t.Fatalf("tb.DeletePermissions() failed: %v", err)
290 }
291
292 // Check GetPermissions again.
293 wantPerms = []nosql.PrefixPermissions{
294 nosql.PrefixPermissions{Prefix: nosql.Prefix(""), Perms: aAndB},
295 }
296 if got, _ := tb.GetPermissions(clientACtx, ""); !reflect.DeepEqual(got, wantPerms) {
297 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
298 }
299 if got, _ := tb.GetPermissions(clientACtx, "prefix"); !reflect.DeepEqual(got, wantPerms) {
300 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
301 }
302 if got, _ := tb.GetPermissions(clientACtx, "prefix_a"); !reflect.DeepEqual(got, wantPerms) {
303 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
304 }
305 if got, _ := tb.GetPermissions(clientACtx, "prefix_a_suffix"); !reflect.DeepEqual(got, wantPerms) {
306 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
307 }
308 wantPerms = []nosql.PrefixPermissions{
309 nosql.PrefixPermissions{Prefix: nosql.Prefix("prefix_b"), Perms: bOnly},
310 nosql.PrefixPermissions{Prefix: nosql.Prefix(""), Perms: aAndB},
311 }
312 if got, _ := tb.GetPermissions(clientACtx, "prefix_b"); !reflect.DeepEqual(got, wantPerms) {
313 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
314 }
315 if got, _ := tb.GetPermissions(clientACtx, "prefix_b_suffix"); !reflect.DeepEqual(got, wantPerms) {
316 t.Fatalf("Unexpected permissions: got %v, want %v", got, wantPerms)
317 }
318
319 // Remove B from table-level permissions and check B has no access.
320 if err := tb.SetPermissions(clientACtx, nosql.Prefix(""), aOnly); err != nil {
321 t.Fatalf("tb.SetPermissions() failed: %v", err)
322 }
323 if _, err := tb.GetPermissions(clientBCtx, ""); verror.ErrorID(err) != verror.ErrNoAccess.ID {
324 t.Fatalf("tb.GetPermissions() should have failed: %v", err)
325 }
326 if _, err := tb.GetPermissions(clientBCtx, "prefix_b"); verror.ErrorID(err) != verror.ErrNoAccess.ID {
327 t.Fatalf("tb.GetPermissions() should have failed: %v", err)
328 }
329 if err := tb.SetPermissions(clientBCtx, nosql.Prefix(""), bOnly); verror.ErrorID(err) != verror.ErrNoAccess.ID {
330 t.Fatalf("tb.SetPermissions() should have failed: %v", err)
331 }
332 if err := tb.SetPermissions(clientBCtx, nosql.Prefix("prefix_b"), bOnly); verror.ErrorID(err) != verror.ErrNoAccess.ID {
333 t.Fatalf("tb.SetPermissions() should have failed: %v", err)
334 }
Adam Sadovskyaba9d502015-04-10 22:06:06 -0700335}
336
Adam Sadovsky13922e32015-05-19 17:39:59 -0700337////////////////////////////////////////
338// Tests involving rows
339
340type Foo struct {
341 I int
342 S string
343}
344
345type Bar struct {
346 F float32
347 S string
348}
349
John Kline4894fb12015-06-17 09:06:56 -0700350type Baz struct {
351 Name string
352 Active bool
353}
354
Adam Sadovsky13922e32015-05-19 17:39:59 -0700355// Tests that Table.Scan works as expected.
356func TestTableScan(t *testing.T) {
357 ctx, sName, cleanup := tu.SetupOrDie(nil)
358 defer cleanup()
359 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
360 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
361 tb := tu.CreateTable(t, ctx, d, "tb")
362
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700363 tu.CheckScan(t, ctx, tb, nosql.Prefix(""), []string{}, []interface{}{})
Adam Sadovsky13922e32015-05-19 17:39:59 -0700364
365 fooWant := Foo{I: 4, S: "f"}
366 if err := tb.Put(ctx, "foo", &fooWant); err != nil {
367 t.Fatalf("tb.Put() failed: %v", err)
368 }
369 barWant := Bar{F: 0.5, S: "b"}
370 if err := tb.Put(ctx, "bar", &barWant); err != nil {
371 t.Fatalf("tb.Put() failed: %v", err)
372 }
373
374 // Match all keys.
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700375 tu.CheckScan(t, ctx, tb, nosql.Prefix(""), []string{"bar", "foo"}, []interface{}{&barWant, &fooWant})
376 tu.CheckScan(t, ctx, tb, nosql.Range("", ""), []string{"bar", "foo"}, []interface{}{&barWant, &fooWant})
377 tu.CheckScan(t, ctx, tb, nosql.Range("", "z"), []string{"bar", "foo"}, []interface{}{&barWant, &fooWant})
378 tu.CheckScan(t, ctx, tb, nosql.Range("a", ""), []string{"bar", "foo"}, []interface{}{&barWant, &fooWant})
379 tu.CheckScan(t, ctx, tb, nosql.Range("a", "z"), []string{"bar", "foo"}, []interface{}{&barWant, &fooWant})
Adam Sadovsky13922e32015-05-19 17:39:59 -0700380
381 // Match "bar" only.
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700382 tu.CheckScan(t, ctx, tb, nosql.Prefix("b"), []string{"bar"}, []interface{}{&barWant})
383 tu.CheckScan(t, ctx, tb, nosql.Prefix("bar"), []string{"bar"}, []interface{}{&barWant})
384 tu.CheckScan(t, ctx, tb, nosql.Range("bar", "baz"), []string{"bar"}, []interface{}{&barWant})
385 tu.CheckScan(t, ctx, tb, nosql.Range("bar", "foo"), []string{"bar"}, []interface{}{&barWant})
386 tu.CheckScan(t, ctx, tb, nosql.Range("", "foo"), []string{"bar"}, []interface{}{&barWant})
Adam Sadovsky13922e32015-05-19 17:39:59 -0700387
388 // Match "foo" only.
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700389 tu.CheckScan(t, ctx, tb, nosql.Prefix("f"), []string{"foo"}, []interface{}{&fooWant})
390 tu.CheckScan(t, ctx, tb, nosql.Prefix("foo"), []string{"foo"}, []interface{}{&fooWant})
391 tu.CheckScan(t, ctx, tb, nosql.Range("foo", "fox"), []string{"foo"}, []interface{}{&fooWant})
392 tu.CheckScan(t, ctx, tb, nosql.Range("foo", ""), []string{"foo"}, []interface{}{&fooWant})
Adam Sadovsky13922e32015-05-19 17:39:59 -0700393
394 // Match nothing.
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700395 tu.CheckScan(t, ctx, tb, nosql.Range("a", "bar"), []string{}, []interface{}{})
396 tu.CheckScan(t, ctx, tb, nosql.Range("bar", "bar"), []string{}, []interface{}{})
397 tu.CheckScan(t, ctx, tb, nosql.Prefix("z"), []string{}, []interface{}{})
Adam Sadovsky13922e32015-05-19 17:39:59 -0700398}
399
Adam Sadovskyc5cc4a32015-06-02 18:44:46 -0700400// Tests that Table.Delete works as expected.
401func TestTableDeleteRowRange(t *testing.T) {
402 ctx, sName, cleanup := tu.SetupOrDie(nil)
403 defer cleanup()
404 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
405 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
406 tb := tu.CreateTable(t, ctx, d, "tb")
407
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700408 tu.CheckScan(t, ctx, tb, nosql.Prefix(""), []string{}, []interface{}{})
Adam Sadovskyc5cc4a32015-06-02 18:44:46 -0700409
410 // Put foo and bar.
411 fooWant := Foo{I: 4, S: "f"}
412 if err := tb.Put(ctx, "foo", &fooWant); err != nil {
413 t.Fatalf("tb.Put() failed: %v", err)
414 }
415 barWant := Bar{F: 0.5, S: "b"}
416 if err := tb.Put(ctx, "bar", &barWant); err != nil {
417 t.Fatalf("tb.Put() failed: %v", err)
418 }
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700419 tu.CheckScan(t, ctx, tb, nosql.Prefix(""), []string{"bar", "foo"}, []interface{}{&barWant, &fooWant})
Adam Sadovskyc5cc4a32015-06-02 18:44:46 -0700420
421 // Delete foo.
422 if err := tb.Delete(ctx, nosql.Prefix("f")); err != nil {
423 t.Fatalf("tb.Delete() failed: %v", err)
424 }
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700425 tu.CheckScan(t, ctx, tb, nosql.Prefix(""), []string{"bar"}, []interface{}{&barWant})
Adam Sadovskyc5cc4a32015-06-02 18:44:46 -0700426
427 // Restore foo.
428 if err := tb.Put(ctx, "foo", &fooWant); err != nil {
429 t.Fatalf("tb.Put() failed: %v", err)
430 }
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700431 tu.CheckScan(t, ctx, tb, nosql.Prefix(""), []string{"bar", "foo"}, []interface{}{&barWant, &fooWant})
Adam Sadovskyc5cc4a32015-06-02 18:44:46 -0700432
433 // Delete everything.
434 if err := tb.Delete(ctx, nosql.Prefix("")); err != nil {
435 t.Fatalf("tb.Delete() failed: %v", err)
436 }
Adam Sadovskyfd0cd952015-06-04 22:23:51 -0700437 tu.CheckScan(t, ctx, tb, nosql.Prefix(""), []string{}, []interface{}{})
Adam Sadovskyc5cc4a32015-06-02 18:44:46 -0700438}
439
Adam Sadovskyaba9d502015-04-10 22:06:06 -0700440// Tests that Table.{Get,Put,Delete} work as expected.
441func TestTableRowMethods(t *testing.T) {
Adam Sadovsky13922e32015-05-19 17:39:59 -0700442 ctx, sName, cleanup := tu.SetupOrDie(nil)
443 defer cleanup()
444 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
445 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
446 tb := tu.CreateTable(t, ctx, d, "tb")
447
448 got, want := Foo{}, Foo{I: 4, S: "foo"}
449 if err := tb.Get(ctx, "f", &got); verror.ErrorID(err) != verror.ErrNoExist.ID {
450 t.Fatalf("tb.Get() should have failed: %v", err)
451 }
452 if err := tb.Put(ctx, "f", &want); err != nil {
453 t.Fatalf("tb.Put() failed: %v", err)
454 }
455 if err := tb.Get(ctx, "f", &got); err != nil {
456 t.Fatalf("tb.Get() failed: %v", err)
457 }
458 if !reflect.DeepEqual(got, want) {
459 t.Fatalf("Values do not match: got %v, want %v", got, want)
460 }
461 // Overwrite value.
462 want.I = 6
463 if err := tb.Put(ctx, "f", &want); err != nil {
464 t.Fatalf("tb.Put() failed: %v", err)
465 }
466 if err := tb.Get(ctx, "f", &got); err != nil {
467 t.Fatalf("tb.Get() failed: %v", err)
468 }
469 if !reflect.DeepEqual(got, want) {
470 t.Fatalf("Values do not match: got %v, want %v", got, want)
471 }
Adam Sadovskyc5cc4a32015-06-02 18:44:46 -0700472 if err := tb.Delete(ctx, nosql.Prefix("f")); err != nil {
473 t.Fatalf("tb.Delete() failed: %v", err)
474 }
475 if err := tb.Get(ctx, "f", &got); verror.ErrorID(err) != verror.ErrNoExist.ID {
476 t.Fatalf("r.Get() should have failed: %v", err)
477 }
Adam Sadovskyaba9d502015-04-10 22:06:06 -0700478}
479
480// Tests that Row.{Get,Put,Delete} work as expected.
481func TestRowMethods(t *testing.T) {
Adam Sadovsky13922e32015-05-19 17:39:59 -0700482 ctx, sName, cleanup := tu.SetupOrDie(nil)
483 defer cleanup()
484 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
485 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
486 tb := tu.CreateTable(t, ctx, d, "tb")
487
488 r := tb.Row("f")
489 got, want := Foo{}, Foo{I: 4, S: "foo"}
490 if err := r.Get(ctx, &got); verror.ErrorID(err) != verror.ErrNoExist.ID {
491 t.Fatalf("r.Get() should have failed: %v", err)
492 }
493 if err := r.Put(ctx, &want); err != nil {
494 t.Fatalf("r.Put() failed: %v", err)
495 }
496 if err := r.Get(ctx, &got); err != nil {
497 t.Fatalf("r.Get() failed: %v", err)
498 }
499 if !reflect.DeepEqual(got, want) {
500 t.Fatalf("Values do not match: got %v, want %v", got, want)
501 }
502 // Overwrite value.
503 want.I = 6
504 if err := r.Put(ctx, &want); err != nil {
505 t.Fatalf("r.Put() failed: %v", err)
506 }
507 if err := r.Get(ctx, &got); err != nil {
508 t.Fatalf("r.Get() failed: %v", err)
509 }
510 if !reflect.DeepEqual(got, want) {
511 t.Fatalf("Values do not match: got %v, want %v", got, want)
512 }
513 if err := r.Delete(ctx); err != nil {
514 t.Fatalf("r.Delete() failed: %v", err)
515 }
516 if err := r.Get(ctx, &got); verror.ErrorID(err) != verror.ErrNoExist.ID {
517 t.Fatalf("r.Get() should have failed: %v", err)
518 }
Adam Sadovskyaba9d502015-04-10 22:06:06 -0700519}
Sergey Rogulenko445e0412015-06-18 23:06:11 -0700520
521// Test permission checking in Row.{Get,Put,Delete} and
522// Table.{Scan, DeleteRowRange}.
523func TestRowPermissions(t *testing.T) {
Adam Sadovskyda069202015-06-24 12:56:11 -0700524 ctx, clientACtx, sName, rootp, cleanup := tu.SetupOrDieCustom("clientA", "server", nil)
Sergey Rogulenko445e0412015-06-18 23:06:11 -0700525 defer cleanup()
Adam Sadovskyda069202015-06-24 12:56:11 -0700526 clientBCtx := tu.NewCtx(ctx, rootp, "clientB")
Sergey Rogulenko445e0412015-06-18 23:06:11 -0700527 a := tu.CreateApp(t, clientACtx, syncbase.NewService(sName), "a")
528 d := tu.CreateNoSQLDatabase(t, clientACtx, a, "d")
529 tb := tu.CreateTable(t, clientACtx, d, "tb")
530
531 // Permission objects.
Adam Sadovskyda069202015-06-24 12:56:11 -0700532 aAndB := tu.DefaultPerms("root/clientA", "root/clientB")
533 aOnly := tu.DefaultPerms("root/clientA")
534 bOnly := tu.DefaultPerms("root/clientB")
Sergey Rogulenko445e0412015-06-18 23:06:11 -0700535
536 // Set initial permissions.
537 if err := tb.SetPermissions(clientACtx, nosql.Prefix(""), aAndB); err != nil {
538 t.Fatalf("tb.SetPermissions() failed: %v", err)
539 }
540 if err := tb.SetPermissions(clientACtx, nosql.Prefix("a"), aOnly); err != nil {
541 t.Fatalf("tb.SetPermissions() failed: %v", err)
542 }
543 if err := tb.SetPermissions(clientBCtx, nosql.Prefix("b"), bOnly); err != nil {
544 t.Fatalf("tb.SetPermissions() failed: %v", err)
545 }
546
547 // Add some key-value pairs.
548 ra := tb.Row("afoo")
549 rb := tb.Row("bfoo")
550 if err := ra.Put(clientACtx, Foo{}); err != nil {
551 t.Fatalf("ra.Put() failed: %v", err)
552 }
553 if err := rb.Put(clientBCtx, Foo{}); err != nil {
554 t.Fatalf("rb.Put() failed: %v", err)
555 }
556
557 // Check A doesn't have access to 'b'.
558 if err := rb.Get(clientACtx, &Foo{}); verror.ErrorID(err) != verror.ErrNoAccess.ID {
559 t.Fatalf("rb.Get() should have failed: %v", err)
560 }
561 if err := rb.Put(clientACtx, Foo{}); verror.ErrorID(err) != verror.ErrNoAccess.ID {
562 t.Fatalf("rb.Put() should have failed: %v", err)
563 }
564 if err := rb.Delete(clientACtx); verror.ErrorID(err) != verror.ErrNoAccess.ID {
565 t.Fatalf("rb.Delete() should have failed: %v", err)
566 }
567 // Test Table.Delete and Scan.
568 if err := tb.Delete(clientACtx, nosql.Prefix("")); verror.ErrorID(err) != verror.ErrNoAccess.ID {
569 t.Fatalf("tb.Delete should have failed: %v", err)
570 }
571 s := tb.Scan(clientACtx, nosql.Prefix(""))
572 if !s.Advance() {
573 t.Fatalf("Stream should have advanced: %v", s.Err())
574 }
575 if s.Key() != "afoo" {
576 t.Fatalf("Unexpected key: got %q, want %q", s.Key(), "afoo")
577 }
578 if s.Advance() {
579 t.Fatalf("Stream advanced unexpectedly")
580 }
581 if err := s.Err(); verror.ErrorID(err) != verror.ErrNoAccess.ID {
582 t.Fatalf("Unexpected stream error: %v", err)
583 }
584}
Sergey Rogulenko1f988de2015-08-14 17:00:09 -0700585
586// TestWatchBasic test the basic client watch functionality: no perms,
587// no batches.
588func TestWatchBasic(t *testing.T) {
589 ctx, sName, cleanup := tu.SetupOrDie(nil)
590 defer cleanup()
591 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
592 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
593 tb := tu.CreateTable(t, ctx, d, "tb")
594 var resumeMarkers []watch.ResumeMarker
595
596 // Generate the data and resume markers.
597 // Initial state.
598 resumeMarker, err := d.GetResumeMarker(ctx)
599 if err != nil {
600 t.Fatalf("d.GetResumeMarker() failed: %v", err)
601 }
602 resumeMarkers = append(resumeMarkers, resumeMarker)
603 // Put "abc".
604 r := tb.Row("abc")
605 if err := r.Put(ctx, "value"); err != nil {
606 t.Fatalf("r.Put() failed: %v", err)
607 }
608 if resumeMarker, err = d.GetResumeMarker(ctx); err != nil {
609 t.Fatalf("d.GetResumeMarker() failed: %v", err)
610 }
611 resumeMarkers = append(resumeMarkers, resumeMarker)
612 // Delete "abc".
613 if err := r.Delete(ctx); err != nil {
614 t.Fatalf("r.Delete() failed: %v", err)
615 }
616 if resumeMarker, err = d.GetResumeMarker(ctx); err != nil {
617 t.Fatalf("d.GetResumeMarker() failed: %v", err)
618 }
619 resumeMarkers = append(resumeMarkers, resumeMarker)
620 // Put "a".
621 r = tb.Row("a")
622 if err := r.Put(ctx, "value"); err != nil {
623 t.Fatalf("r.Put() failed: %v", err)
624 }
625 if resumeMarker, err = d.GetResumeMarker(ctx); err != nil {
626 t.Fatalf("d.GetResumeMarker() failed: %v", err)
627 }
628 resumeMarkers = append(resumeMarkers, resumeMarker)
629
630 vomValue, _ := vom.Encode("value")
631 allChanges := []nosql.WatchChange{
632 nosql.WatchChange{
633 Table: "tb",
634 Row: "abc",
635 ChangeType: nosql.PutChange,
636 ValueBytes: vomValue,
637 ResumeMarker: resumeMarkers[1],
638 },
639 nosql.WatchChange{
640 Table: "tb",
641 Row: "abc",
642 ChangeType: nosql.DeleteChange,
643 ResumeMarker: resumeMarkers[2],
644 },
645 nosql.WatchChange{
646 Table: "tb",
647 Row: "a",
648 ChangeType: nosql.PutChange,
649 ValueBytes: vomValue,
650 ResumeMarker: resumeMarkers[3],
651 },
652 }
653 ctxWithTimeout, _ := context.WithTimeout(ctx, 10*time.Second)
654 wstream, _ := d.Watch(ctxWithTimeout, "tb", "a", resumeMarkers[0])
655 tu.CheckWatch(t, wstream, allChanges)
656 wstream, _ = d.Watch(ctxWithTimeout, "tb", "a", resumeMarkers[1])
657 tu.CheckWatch(t, wstream, allChanges[1:])
658 wstream, _ = d.Watch(ctxWithTimeout, "tb", "a", resumeMarkers[2])
659 tu.CheckWatch(t, wstream, allChanges[2:])
660
661 wstream, _ = d.Watch(ctxWithTimeout, "tb", "abc", resumeMarkers[0])
662 tu.CheckWatch(t, wstream, allChanges[:2])
663 wstream, _ = d.Watch(ctxWithTimeout, "tb", "abc", resumeMarkers[1])
664 tu.CheckWatch(t, wstream, allChanges[1:2])
665}
666
667// TestWatchWithBatchAndPerms test that the client watch correctly handles
668// batches and prefix perms.
669func TestWatchWithBatchAndPerms(t *testing.T) {
670 ctx, clientACtx, sName, rootp, cleanup := tu.SetupOrDieCustom("clientA", "server", nil)
671 defer cleanup()
672 clientBCtx := tu.NewCtx(ctx, rootp, "clientB")
673 a := tu.CreateApp(t, clientACtx, syncbase.NewService(sName), "a")
674 d := tu.CreateNoSQLDatabase(t, clientACtx, a, "d")
675 tb := tu.CreateTable(t, clientACtx, d, "tb")
676
677 // Set initial permissions.
678 aAndB := tu.DefaultPerms("root/clientA", "root/clientB")
679 aOnly := tu.DefaultPerms("root/clientA")
680 if err := tb.SetPermissions(clientACtx, nosql.Prefix(""), aAndB); err != nil {
681 t.Fatalf("tb.SetPermissions() failed: %v", err)
682 }
683 if err := tb.SetPermissions(clientACtx, nosql.Prefix("a"), aOnly); err != nil {
684 t.Fatalf("tb.SetPermissions() failed: %v", err)
685 }
686 // Get the initial resume marker.
687 resumeMarker, err := d.GetResumeMarker(clientACtx)
688 if err != nil {
689 t.Fatalf("d.GetResumeMarker() failed: %v", err)
690 }
691 initMarker := resumeMarker
692 // Do two puts in a batch.
693 if err := nosql.RunInBatch(clientACtx, d, wire.BatchOptions{}, func(b nosql.BatchDatabase) error {
694 tb := b.Table("tb")
695 if err := tb.Put(clientACtx, "a", "value"); err != nil {
696 return err
697 }
698 return tb.Put(clientACtx, "b", "value")
699 }); err != nil {
700 t.Fatalf("RunInBatch failed: %v", err)
701 }
702
703 if resumeMarker, err = d.GetResumeMarker(clientACtx); err != nil {
704 t.Fatalf("d.GetResumeMarker() failed: %v", err)
705 }
706 vomValue, _ := vom.Encode("value")
707 allChanges := []nosql.WatchChange{
708 nosql.WatchChange{
709 Table: "tb",
710 Row: "a",
711 ChangeType: nosql.PutChange,
712 ValueBytes: vomValue,
713 ResumeMarker: nil,
714 Continued: true,
715 },
716 nosql.WatchChange{
717 Table: "tb",
718 Row: "b",
719 ChangeType: nosql.PutChange,
720 ValueBytes: vomValue,
721 ResumeMarker: resumeMarker,
722 },
723 }
724
725 ctxAWithTimeout, _ := context.WithTimeout(clientACtx, 10*time.Second)
726 ctxBWithTimeout, _ := context.WithTimeout(clientBCtx, 10*time.Second)
727 // ClientA should see both changes as one batch.
728 wstream, _ := d.Watch(ctxAWithTimeout, "tb", "", initMarker)
729 tu.CheckWatch(t, wstream, allChanges)
730 // ClientB should see only one change.
731 wstream, _ = d.Watch(ctxBWithTimeout, "tb", "", initMarker)
732 tu.CheckWatch(t, wstream, allChanges[1:])
733}
734
735// TestBlockingWatch tests that the server side of the client watch correctly
736// blocks until new updates to the database arrive.
737func TestBlockingWatch(t *testing.T) {
738 ctx, sName, cleanup := tu.SetupOrDie(nil)
739 defer cleanup()
740 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
741 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
742 tb := tu.CreateTable(t, ctx, d, "tb")
743
744 resumeMarker, err := d.GetResumeMarker(ctx)
745 if err != nil {
746 t.Fatalf("d.GetResumeMarker() failed: %v", err)
747 }
748 ctxWithTimeout, _ := context.WithTimeout(ctx, 10*time.Second)
749 wstream, _ := d.Watch(ctxWithTimeout, "tb", "a", resumeMarker)
750 vomValue, _ := vom.Encode("value")
751 for i := 0; i < 10; i++ {
752 // Put "abc".
753 r := tb.Row("abc")
754 if err := r.Put(ctx, "value"); err != nil {
755 t.Fatalf("r.Put() failed: %v", err)
756 }
757 if resumeMarker, err = d.GetResumeMarker(ctx); err != nil {
758 t.Fatalf("d.GetResumeMarker() failed: %v", err)
759 }
760 if !wstream.Advance() {
761 t.Fatalf("wstream.Advance() reached the end: %v", wstream.Err())
762 }
763 want := nosql.WatchChange{
764 Table: "tb",
765 Row: "abc",
766 ChangeType: nosql.PutChange,
767 ValueBytes: vomValue,
768 ResumeMarker: resumeMarker,
769 }
770 if got := wstream.Change(); !reflect.DeepEqual(got, want) {
771 t.Fatalf("unexpected watch change: got %v, want %v", got, want)
772 }
773 }
774}
775
776// TestBlockedWatchCancel tests that the watch call blocked on the server side
777// can be successfully canceled from the client.
778func TestBlockedWatchCancel(t *testing.T) {
779 ctx, sName, cleanup := tu.SetupOrDie(nil)
780 defer cleanup()
781 a := tu.CreateApp(t, ctx, syncbase.NewService(sName), "a")
782 d := tu.CreateNoSQLDatabase(t, ctx, a, "d")
783
784 resumeMarker, err := d.GetResumeMarker(ctx)
785 if err != nil {
786 t.Fatalf("d.GetResumeMarker() failed: %v", err)
787 }
788 ctxWithTimeout, _ := context.WithTimeout(ctx, 100*time.Millisecond)
789 wstream, _ := d.Watch(ctxWithTimeout, "tb", "a", resumeMarker)
790 if wstream.Advance() {
791 t.Fatalf("wstream advanced")
792 }
793 if got, want := verror.ErrorID(wstream.Err()), verror.ErrTimeout.ID; got != want {
794 t.Fatalf("unexpected wstream error ID: got %v, want %v", got, want)
795 }
796}