blob: acf9dbdc854a0d0df370be02aabac099bfb99ee7 [file] [log] [blame]
Adam Sadovsky6a6214f2015-09-03 18:20:18 -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
5package testutil
6
7import (
8 "fmt"
9 "reflect"
10 "testing"
11
12 "v.io/v23/context"
13 "v.io/v23/security"
14 "v.io/v23/security/access"
15 "v.io/v23/syncbase"
16 "v.io/v23/syncbase/nosql"
17 "v.io/v23/syncbase/util"
18 "v.io/v23/verror"
19 "v.io/x/lib/vlog"
20 "v.io/x/ref/test/testutil"
21)
22
23// TestCreate tests that object creation works as expected.
24func TestCreate(t *testing.T, ctx *context.T, i interface{}) {
25 parent := makeLayer(i)
26 self := parent.Child("self")
27 child := self.Child("child")
28
29 // child.Create should fail since self does not exist.
30 if err := child.Create(ctx, nil); verror.ErrorID(err) != verror.ErrNoExist.ID {
31 t.Fatalf("child.Create() should have failed: %v", err)
32 }
33
34 assertExists(t, ctx, self, "self", false)
35 // TODO(ivanpi): Exists on child when parent does not exist currently fails
36 // with an error instead of returning false.
37 //assertExists(t, ctx, child, "child", false)
38
39 // Create self.
40 if err := self.Create(ctx, nil); err != nil {
41 t.Fatalf("self.Create() failed: %v", err)
42 }
43 if gotPerms, wantPerms := getPermsOrDie(t, ctx, self), DefaultPerms("root/client"); !reflect.DeepEqual(gotPerms, wantPerms) {
44 t.Errorf("Perms do not match: got %v, want %v", gotPerms, wantPerms)
45 }
46
47 assertExists(t, ctx, self, "self", true)
48 assertExists(t, ctx, child, "child", false)
49
50 // child.Create should now succeed.
51 if err := child.Create(ctx, nil); err != nil {
52 t.Fatalf("child.Create() failed: %v", err)
53 }
54
55 assertExists(t, ctx, child, "child", true)
56
57 // self.Create should fail since self already exists.
58 if err := self.Create(ctx, nil); verror.ErrorID(err) != verror.ErrExist.ID {
59 t.Fatalf("self.Create() should have failed: %v", err)
60 }
61
62 assertExists(t, ctx, self, "self", true)
63
64 // Test create with non-default perms.
65 self2 := parent.Child("self2")
66 perms := access.Permissions{}
67 perms.Add(security.BlessingPattern("root/client"), string(access.Admin))
68 if err := self2.Create(ctx, perms); err != nil {
69 t.Fatalf("self2.Create() failed: %v", err)
70 }
71 if gotPerms, wantPerms := getPermsOrDie(t, ctx, self2), perms; !reflect.DeepEqual(gotPerms, wantPerms) {
72 t.Errorf("Perms do not match: got %v, want %v", gotPerms, wantPerms)
73 }
74
75 // Even though self2 exists, Exists returns false because Read access is needed.
76 assertExists(t, ctx, self2, "self2", false)
77
78 // Test that create fails if the parent perms disallow access.
79 perms = DefaultPerms("root/client")
80 perms.Blacklist("root/client", string(access.Write))
81 if err := parent.SetPermissions(ctx, perms, ""); err != nil {
82 t.Fatalf("parent.SetPermissions() failed: %v", err)
83 }
84 self3 := parent.Child("self3")
85 if err := self3.Create(ctx, nil); verror.ErrorID(err) != verror.ErrNoAccess.ID {
86 t.Fatalf("self3.Create() should have failed: %v", err)
87 }
88
89 assertExists(t, ctx, self, "self", true)
90 assertExists(t, ctx, self3, "self3", false)
91}
92
93// TestDelete tests that object deletion works as expected.
94func TestDelete(t *testing.T, ctx *context.T, i interface{}) {
95 parent := makeLayer(i)
96 self := parent.Child("self")
97 child := self.Child("child")
98
99 // Create self.
100 if err := self.Create(ctx, nil); err != nil {
101 t.Fatalf("self.Create() failed: %v", err)
102 }
103
104 assertExists(t, ctx, self, "self", true)
105
106 // self.Create should fail, since self already exists.
107 if err := self.Create(ctx, nil); verror.ErrorID(err) != verror.ErrExist.ID {
108 t.Fatalf("self.Create() should have failed: %v", err)
109 }
110
111 assertExists(t, ctx, self, "self", true)
112
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700113 // By default, self perms are copied from parent, so self.Destroy should
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700114 // succeed.
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700115 if err := self.Destroy(ctx); err != nil {
116 t.Fatalf("self.Destroy() failed: %v", err)
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700117 }
118
119 assertExists(t, ctx, self, "self", false)
120
121 // child.Create should fail, since self does not exist.
122 if err := child.Create(ctx, nil); verror.ErrorID(err) != verror.ErrNoExist.ID {
123 t.Fatalf("child.Create() should have failed: %v", err)
124 }
125
126 assertExists(t, ctx, self, "self", false)
127 // TODO(ivanpi): Exists on child when parent does not exist currently fails
128 // with an error instead of returning false.
129 //assertExists(t, ctx, child, "child", false)
130
131 // self.Create should succeed, since self was deleted.
132 if err := self.Create(ctx, nil); err != nil {
133 t.Fatalf("self.Create() failed: %v", err)
134 }
135
136 assertExists(t, ctx, self, "self", true)
137 assertExists(t, ctx, child, "child", false)
138
139 // Test that delete fails if the perms disallow access.
140 self2 := parent.Child("self2")
141 if err := self2.Create(ctx, nil); err != nil {
142 t.Fatalf("self2.Create() failed: %v", err)
143 }
144 perms := DefaultPerms("root/client")
145 perms.Blacklist("root/client", string(access.Write))
146 if err := self2.SetPermissions(ctx, perms, ""); err != nil {
147 t.Fatalf("self2.SetPermissions() failed: %v", err)
148 }
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700149 if err := self2.Destroy(ctx); verror.ErrorID(err) != verror.ErrNoAccess.ID {
150 t.Fatalf("self2.Destroy() should have failed: %v", err)
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700151 }
152
153 assertExists(t, ctx, self2, "self2", true)
154
155 // Test that delete succeeds even if the parent perms disallow access.
156 perms = DefaultPerms("root/client")
157 perms.Blacklist("root/client", string(access.Write))
158 if err := parent.SetPermissions(ctx, perms, ""); err != nil {
159 t.Fatalf("parent.SetPermissions() failed: %v", err)
160 }
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700161 if err := self.Destroy(ctx); err != nil {
162 t.Fatalf("self.Destroy() failed: %v", err)
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700163 }
164
165 assertExists(t, ctx, self, "self", false)
166
167 // Test that delete is idempotent.
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700168 if err := self.Destroy(ctx); err != nil {
169 t.Fatalf("self.Destroy() failed: %v", err)
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700170 }
171
172 assertExists(t, ctx, self, "self", false)
173}
174
175func TestListChildren(t *testing.T, ctx *context.T, i interface{}) {
176 self := makeLayer(i)
177
178 var got, want []string
179 var err error
180
181 got, err = self.ListChildren(ctx)
182 want = []string{}
183 if err != nil {
184 t.Fatalf("self.ListChildren() failed: %v", err)
185 }
186 if !reflect.DeepEqual(got, want) {
187 t.Fatalf("Lists do not match: got %v, want %v", got, want)
188 }
189
190 if err := self.Child("y").Create(ctx, nil); err != nil {
191 t.Fatalf("y.Create() failed: %v", err)
192 }
193 got, err = self.ListChildren(ctx)
194 want = []string{"y"}
195 if err != nil {
196 t.Fatalf("self.ListChildren() failed: %v", err)
197 }
198 if !reflect.DeepEqual(got, want) {
199 t.Fatalf("Lists do not match: got %v, want %v", got, want)
200 }
201
202 if err := self.Child("x").Create(ctx, nil); err != nil {
203 t.Fatalf("x.Create() failed: %v", err)
204 }
205 got, err = self.ListChildren(ctx)
206 want = []string{"x", "y"}
207 if err != nil {
208 t.Fatalf("self.ListChildren() failed: %v", err)
209 }
210 if !reflect.DeepEqual(got, want) {
211 t.Fatalf("Lists do not match: got %v, want %v", got, want)
212 }
213}
214
215// TestPerms tests that {Set,Get}Permissions work as expected.
216// TODO(sadovsky): All Vanadium {Set,Get}Permissions tests ought to share this
217// test implementation. :)
218// Mirrors v.io/groups/x/ref/services/groups/internal/server/server_test.go.
219func TestPerms(t *testing.T, ctx *context.T, ac util.AccessController) {
220 myperms := access.Permissions{}
221 myperms.Add(security.BlessingPattern("root/client"), string(access.Admin))
222 // Demonstrate that myperms differs from the current perms.
223 if reflect.DeepEqual(myperms, getPermsOrDie(t, ctx, ac)) {
224 t.Fatalf("Permissions should not match: %v", myperms)
225 }
226
227 var permsBefore, permsAfter access.Permissions
228 var versionBefore, versionAfter string
229
230 getPermsAndVersionOrDie := func() (access.Permissions, string) {
231 perms, version, err := ac.GetPermissions(ctx)
232 if err != nil {
233 // Use Fatalf rather than t.Fatalf so we get a stack trace.
234 Fatalf(t, "GetPermissions failed: %v", err)
235 }
236 return perms, version
237 }
238
239 // SetPermissions with bad version should fail.
240 permsBefore, versionBefore = getPermsAndVersionOrDie()
241 if err := ac.SetPermissions(ctx, myperms, "20"); verror.ErrorID(err) != verror.ErrBadVersion.ID {
242 t.Fatal("SetPermissions should have failed with version error")
243 }
244 // Since SetPermissions failed, perms and version should not have changed.
245 permsAfter, versionAfter = getPermsAndVersionOrDie()
246 if !reflect.DeepEqual(permsAfter, permsBefore) {
247 t.Errorf("Perms do not match: got %v, want %v", permsAfter, permsBefore)
248 }
249 if versionAfter != versionBefore {
250 t.Errorf("Versions do not match: got %v, want %v", versionAfter, versionBefore)
251 }
252
253 // SetPermissions with correct version should succeed.
254 permsBefore, versionBefore = permsAfter, versionAfter
255 if err := ac.SetPermissions(ctx, myperms, versionBefore); err != nil {
256 t.Fatalf("SetPermissions failed: %v", err)
257 }
258 // Check that perms and version actually changed.
259 permsAfter, versionAfter = getPermsAndVersionOrDie()
260 if !reflect.DeepEqual(permsAfter, myperms) {
261 t.Errorf("Perms do not match: got %v, want %v", permsAfter, myperms)
262 }
263 if versionBefore == versionAfter {
264 t.Errorf("Versions should not match: %v", versionBefore)
265 }
266
267 // SetPermissions with empty version should succeed.
268 permsBefore, versionBefore = permsAfter, versionAfter
269 myperms.Add(security.BlessingPattern("root/client"), string(access.Read))
270 if err := ac.SetPermissions(ctx, myperms, ""); err != nil {
271 t.Fatalf("SetPermissions failed: %v", err)
272 }
273 // Check that perms and version actually changed.
274 permsAfter, versionAfter = getPermsAndVersionOrDie()
275 if !reflect.DeepEqual(permsAfter, myperms) {
276 t.Errorf("Perms do not match: got %v, want %v", permsAfter, myperms)
277 }
278 if versionBefore == versionAfter {
279 t.Errorf("Versions should not match: %v", versionBefore)
280 }
281
282 // SetPermissions with unchanged perms should succeed, and version should
283 // still change.
284 permsBefore, versionBefore = permsAfter, versionAfter
285 if err := ac.SetPermissions(ctx, myperms, ""); err != nil {
286 t.Fatalf("SetPermissions failed: %v", err)
287 }
288 // Check that perms did not change and version did change.
289 permsAfter, versionAfter = getPermsAndVersionOrDie()
290 if !reflect.DeepEqual(permsAfter, permsBefore) {
291 t.Errorf("Perms do not match: got %v, want %v", permsAfter, permsBefore)
292 }
293 if versionBefore == versionAfter {
294 t.Errorf("Versions should not match: %v", versionBefore)
295 }
296
297 // Take away our access. SetPermissions and GetPermissions should fail.
298 if err := ac.SetPermissions(ctx, access.Permissions{}, ""); err != nil {
299 t.Fatalf("SetPermissions failed: %v", err)
300 }
301 if _, _, err := ac.GetPermissions(ctx); verror.ErrorID(err) != verror.ErrNoAccess.ID {
302 t.Fatal("GetPermissions should have failed with access error")
303 }
304 if err := ac.SetPermissions(ctx, myperms, ""); verror.ErrorID(err) != verror.ErrNoAccess.ID {
305 t.Fatal("SetPermissions should have failed with access error")
306 }
307}
308
309////////////////////////////////////////
310// Internal helpers
311
312const notAvailable = "not available"
313
314type layer interface {
315 util.AccessController
316 Create(ctx *context.T, perms access.Permissions) error
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700317 Destroy(ctx *context.T) error
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700318 Exists(ctx *context.T) (bool, error)
319 ListChildren(ctx *context.T) ([]string, error)
320 Child(childName string) layer
321}
322
323type service struct {
324 syncbase.Service
325}
326
327func (s *service) Create(ctx *context.T, perms access.Permissions) error {
328 panic(notAvailable)
329}
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700330func (s *service) Destroy(ctx *context.T) error {
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700331 panic(notAvailable)
332}
333func (s *service) Exists(ctx *context.T) (bool, error) {
334 panic(notAvailable)
335}
336func (s *service) ListChildren(ctx *context.T) ([]string, error) {
337 return s.ListApps(ctx)
338}
339func (s *service) Child(childName string) layer {
340 return makeLayer(s.App(childName))
341}
342
343type app struct {
344 syncbase.App
345}
346
347func (a *app) ListChildren(ctx *context.T) ([]string, error) {
348 return a.ListDatabases(ctx)
349}
350func (a *app) Child(childName string) layer {
351 return makeLayer(a.NoSQLDatabase(childName, nil))
352}
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700353
354type database struct {
355 nosql.Database
356}
357
358func (d *database) ListChildren(ctx *context.T) ([]string, error) {
359 return d.ListTables(ctx)
360}
361func (d *database) Child(childName string) layer {
362 return &table{Table: d.Table(childName), d: d}
363}
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700364
365type table struct {
366 nosql.Table
367 d nosql.Database
368}
369
370func (t *table) Create(ctx *context.T, perms access.Permissions) error {
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700371 return t.Table.Create(ctx, perms)
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700372}
373func (t *table) SetPermissions(ctx *context.T, perms access.Permissions, version string) error {
374 return t.Table.SetPermissions(ctx, nosql.Prefix(""), perms)
375}
376func (t *table) GetPermissions(ctx *context.T) (perms access.Permissions, version string, err error) {
377 permsList, err := t.Table.GetPermissions(ctx, "")
378 if len(permsList) != 1 || permsList[0].Prefix.Prefix() != "" {
379 panic(fmt.Sprintf("unexpected perms list: %v", permsList))
380 }
381 return permsList[0].Perms, "", nil
382}
383func (t *table) ListChildren(ctx *context.T) ([]string, error) {
384 panic(notAvailable)
385}
386func (t *table) Child(childName string) layer {
387 return &row{t.Row(childName)}
388}
389
390type row struct {
391 nosql.Row
392}
393
394func (r *row) Create(ctx *context.T, perms access.Permissions) error {
395 if perms != nil {
396 panic(fmt.Sprintf("bad perms: %v", perms))
397 }
398 return r.Put(ctx, true)
399}
Ali Ghassemi92c060c2015-09-04 13:17:06 -0700400func (r *row) Destroy(ctx *context.T) error {
Adam Sadovsky6a6214f2015-09-03 18:20:18 -0700401 return r.Delete(ctx)
402}
403func (r *row) SetPermissions(ctx *context.T, perms access.Permissions, version string) error {
404 panic(notAvailable)
405}
406func (r *row) GetPermissions(ctx *context.T) (perms access.Permissions, version string, err error) {
407 panic(notAvailable)
408}
409func (r *row) ListChildren(ctx *context.T) ([]string, error) {
410 panic(notAvailable)
411}
412func (r *row) Child(childName string) layer {
413 panic(notAvailable)
414}
415
416func makeLayer(i interface{}) layer {
417 switch t := i.(type) {
418 case syncbase.Service:
419 return &service{t}
420 case syncbase.App:
421 return &app{t}
422 case nosql.Database:
423 return &database{t}
424 default:
425 vlog.Fatalf("unexpected type: %T", t)
426 }
427 return nil
428}
429
430func assertExists(t *testing.T, ctx *context.T, l layer, name string, want bool) {
431 if got, err := l.Exists(ctx); err != nil {
432 t.Fatal(testutil.FormatLogLine(2, "%s.Exists() failed: %v", name, err))
433 } else if got != want {
434 t.Error(testutil.FormatLogLine(2, "%s.Exists() got %v, want %v", name, got, want))
435 }
436}