[ARVADOS] created: aea8596a74dabdc894fc1139c4d8dc195e6c86b2
Git user
git at public.curoverse.com
Mon Feb 27 21:50:41 EST 2017
at aea8596a74dabdc894fc1139c4d8dc195e6c86b2 (commit)
commit aea8596a74dabdc894fc1139c4d8dc195e6c86b2
Author: Tom Clegg <tom at curoverse.com>
Date: Mon Feb 27 21:49:42 2017 -0500
10764: Permission tests. Support PDH permission check.
diff --git a/sdk/go/arvados/client.go b/sdk/go/arvados/client.go
index fc93749..8319b5d 100644
--- a/sdk/go/arvados/client.go
+++ b/sdk/go/arvados/client.go
@@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"os"
+ "regexp"
"strings"
"time"
)
@@ -241,7 +242,12 @@ func (c *Client) DiscoveryDocument() (*DiscoveryDocument, error) {
return c.dd, nil
}
+var pdhRegexp = regexp.MustCompile(`^[0-9a-f]{32}\+\d+$`)
+
func (c *Client) modelForUUID(dd *DiscoveryDocument, uuid string) (string, error) {
+ if pdhRegexp.MatchString(uuid) {
+ return "Collection", nil
+ }
if len(uuid) != 27 {
return "", fmt.Errorf("invalid UUID: %q", uuid)
}
diff --git a/sdk/go/arvadostest/fixtures.go b/sdk/go/arvadostest/fixtures.go
index 70393a6..299d186 100644
--- a/sdk/go/arvadostest/fixtures.go
+++ b/sdk/go/arvadostest/fixtures.go
@@ -2,17 +2,21 @@ package arvadostest
// IDs of API server's test fixtures
const (
- SpectatorToken = "zw2f4gwx8hw8cjre7yp6v1zylhrhn3m5gvjq73rtpwhmknrybu"
- ActiveToken = "3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi"
- AdminToken = "4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h"
- AnonymousToken = "4kg6k6lzmp9kj4cpkcoxie964cmvjahbt4fod9zru44k4jqdmi"
- DataManagerToken = "320mkve8qkswstz7ff61glpk3mhgghmg67wmic7elw4z41pke1"
- FooCollection = "zzzzz-4zz18-fy296fx3hot09f7"
- NonexistentCollection = "zzzzz-4zz18-totallynotexist"
- HelloWorldCollection = "zzzzz-4zz18-4en62shvi99lxd4"
- FooBarDirCollection = "zzzzz-4zz18-foonbarfilesdir"
- FooPdh = "1f4b0bc7583c2a7f9102c395f4ffc5e3+45"
- HelloWorldPdh = "55713e6a34081eb03609e7ad5fcad129+62"
+ SpectatorToken = "zw2f4gwx8hw8cjre7yp6v1zylhrhn3m5gvjq73rtpwhmknrybu"
+ ActiveToken = "3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi"
+ AdminToken = "4axaw8zxe0qm22wa6urpp5nskcne8z88cvbupv653y1njyi05h"
+ AnonymousToken = "4kg6k6lzmp9kj4cpkcoxie964cmvjahbt4fod9zru44k4jqdmi"
+ DataManagerToken = "320mkve8qkswstz7ff61glpk3mhgghmg67wmic7elw4z41pke1"
+ ActiveUserUUID = "zzzzz-tpzed-xurymjxw79nv3jz"
+ SpectatorUserUUID = "zzzzz-tpzed-l1s2piq4t4mps8r"
+ UserAgreementCollection = "zzzzz-4zz18-uukreo9rbgwsujr" // user_agreement_in_anonymously_accessible_project
+ FooCollection = "zzzzz-4zz18-fy296fx3hot09f7"
+ NonexistentCollection = "zzzzz-4zz18-totallynotexist"
+ HelloWorldCollection = "zzzzz-4zz18-4en62shvi99lxd4"
+ FooBarDirCollection = "zzzzz-4zz18-foonbarfilesdir"
+ UserAgreementPDH = "b519d9cb706a29fc7ea24dbea2f05851+93"
+ FooPdh = "1f4b0bc7583c2a7f9102c395f4ffc5e3+45"
+ HelloWorldPdh = "55713e6a34081eb03609e7ad5fcad129+62"
Dispatch1Token = "kwi8oowusvbutahacwk2geulqewy5oaqmpalczfna4b6bb0hfw"
Dispatch1AuthUUID = "zzzzz-gj3su-k9dvestay1plssr"
diff --git a/services/ws/permission.go b/services/ws/permission.go
index e467e06..8bfcfcb 100644
--- a/services/ws/permission.go
+++ b/services/ws/permission.go
@@ -36,13 +36,22 @@ type cachingPermChecker struct {
*arvados.Client
cache map[string]cacheEnt
maxCurrent int
+
+ nChecks uint64
+ nMisses uint64
+ nInvalid uint64
}
func (pc *cachingPermChecker) SetToken(token string) {
+ if pc.Client.AuthToken == token {
+ return
+ }
pc.Client.AuthToken = token
+ pc.cache = make(map[string]cacheEnt)
}
func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
+ pc.nChecks++
logger := logger(nil).
WithField("token", pc.Client.AuthToken).
WithField("uuid", uuid)
@@ -55,8 +64,11 @@ func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
var buf map[string]interface{}
path, err := pc.PathForUUID("get", uuid)
if err != nil {
+ pc.nInvalid++
return false, err
}
+
+ pc.nMisses++
err = pc.RequestAndDecode(&buf, "GET", path, nil, url.Values{
"select": {`["uuid"]`},
})
@@ -64,12 +76,7 @@ func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
var allowed bool
if err == nil {
allowed = true
- } else if txErr, ok := err.(*arvados.TransactionError); ok && txErr.StatusCode == http.StatusNotFound {
- allowed = false
- } else if txErr.StatusCode == http.StatusForbidden {
- // Some requests are expressly forbidden for reasons
- // other than "you aren't allowed to know whether this
- // UUID exists" (404).
+ } else if txErr, ok := err.(*arvados.TransactionError); ok && pc.isNotAllowed(txErr.StatusCode) {
allowed = false
} else {
logger.WithError(err).Error("lookup error")
@@ -80,6 +87,15 @@ func (pc *cachingPermChecker) Check(uuid string) (bool, error) {
return allowed, nil
}
+func (pc *cachingPermChecker) isNotAllowed(status int) bool {
+ switch status {
+ case http.StatusForbidden, http.StatusUnauthorized, http.StatusNotFound:
+ return true
+ default:
+ return false
+ }
+}
+
func (pc *cachingPermChecker) tidy() {
if len(pc.cache) <= pc.maxCurrent*2 {
return
diff --git a/services/ws/permission_test.go b/services/ws/permission_test.go
new file mode 100644
index 0000000..afaab0e
--- /dev/null
+++ b/services/ws/permission_test.go
@@ -0,0 +1,71 @@
+package main
+
+import (
+ "git.curoverse.com/arvados.git/sdk/go/arvados"
+ "git.curoverse.com/arvados.git/sdk/go/arvadostest"
+ check "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&permSuite{})
+
+type permSuite struct{}
+
+func (s *permSuite) TestCheck(c *check.C) {
+ pc := newPermChecker(*(arvados.NewClientFromEnv())).(*cachingPermChecker)
+ setToken := func(label, token string) {
+ c.Logf("...%s token %q", label, token)
+ pc.SetToken(token)
+ }
+ wantError := func(uuid string) {
+ c.Log(uuid)
+ ok, err := pc.Check(uuid)
+ c.Check(ok, check.Equals, false)
+ c.Check(err, check.NotNil)
+ }
+ wantYes := func(uuid string) {
+ c.Log(uuid)
+ ok, err := pc.Check(uuid)
+ c.Check(ok, check.Equals, true)
+ c.Check(err, check.IsNil)
+ }
+ wantNo := func(uuid string) {
+ c.Log(uuid)
+ ok, err := pc.Check(uuid)
+ c.Check(ok, check.Equals, false)
+ c.Check(err, check.IsNil)
+ }
+
+ setToken("no", "")
+ wantNo(arvadostest.UserAgreementCollection)
+ wantNo(arvadostest.UserAgreementPDH)
+ wantNo(arvadostest.FooBarDirCollection)
+
+ setToken("anonymous", arvadostest.AnonymousToken)
+ wantYes(arvadostest.UserAgreementCollection)
+ wantYes(arvadostest.UserAgreementPDH)
+ wantNo(arvadostest.FooBarDirCollection)
+ wantNo(arvadostest.FooCollection)
+
+ setToken("active", arvadostest.ActiveToken)
+ wantYes(arvadostest.UserAgreementCollection)
+ wantYes(arvadostest.UserAgreementPDH)
+ wantYes(arvadostest.FooBarDirCollection)
+ wantYes(arvadostest.FooCollection)
+
+ setToken("admin", arvadostest.AdminToken)
+ wantYes(arvadostest.UserAgreementCollection)
+ wantYes(arvadostest.UserAgreementPDH)
+ wantYes(arvadostest.FooBarDirCollection)
+ wantYes(arvadostest.FooCollection)
+
+ // hack to empty the cache
+ pc.SetToken("")
+ pc.SetToken(arvadostest.ActiveToken)
+
+ c.Log("...network error")
+ pc.Client.APIHost = "127.0.0.1:discard"
+ wantError(arvadostest.UserAgreementCollection)
+ wantError(arvadostest.FooBarDirCollection)
+
+ c.Logf("%d checks, %d misses, %d invalid, %d cached", pc.nChecks, pc.nMisses, pc.nInvalid, len(pc.cache))
+}
commit ca812f58e63bd4673bb62aa8528e07d6020bfc9a
Author: Tom Clegg <tom at curoverse.com>
Date: Mon Feb 27 17:51:51 2017 -0500
10764: Add unit tests
diff --git a/services/ws/event_source_test.go b/services/ws/event_source_test.go
new file mode 100644
index 0000000..ee1da08
--- /dev/null
+++ b/services/ws/event_source_test.go
@@ -0,0 +1,117 @@
+package main
+
+import (
+ "database/sql"
+ "fmt"
+ "sync"
+ "time"
+
+ "git.curoverse.com/arvados.git/sdk/go/config"
+ check "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&eventSourceSuite{})
+
+type eventSourceSuite struct{}
+
+func testDBConfig() (pgConfig, error) {
+ var railsDB struct {
+ Test struct {
+ Database string
+ Username string
+ Password string
+ Host string
+ }
+ }
+ err := config.LoadFile(&railsDB, "../api/config/database.yml")
+ if err != nil {
+ return nil, err
+ }
+ cfg := pgConfig{
+ "dbname": railsDB.Test.Database,
+ "host": railsDB.Test.Host,
+ "password": railsDB.Test.Password,
+ "user": railsDB.Test.Username,
+ }
+ return cfg, nil
+}
+
+func testDB() (*sql.DB, error) {
+ cfg, err := testDBConfig()
+ if err != nil {
+ return nil, err
+ }
+ return sql.Open("postgres", cfg.ConnectionString())
+}
+
+func (*eventSourceSuite) TestEventSource(c *check.C) {
+ cfg, err := testDBConfig()
+ if err != nil {
+ c.Fatal(err)
+ }
+ pges := &pgEventSource{
+ DataSource: cfg.ConnectionString(),
+ QueueSize: 4,
+ }
+ go pges.Run()
+ sinks := make([]eventSink, 18)
+ for i := range sinks {
+ sinks[i] = pges.NewSink()
+ }
+
+ // wait for listener to start, as evidenced by queue channel
+ // appearing (relying on internal implementation detail here)
+ for deadline := time.Now().Add(10 * time.Second); pges.queue == nil; time.Sleep(10 * time.Millisecond) {
+ c.Assert(time.Now().After(deadline), check.Equals, false)
+ }
+ defer pges.cancel()
+
+ db, err := testDB()
+ c.Assert(err, check.IsNil)
+
+ done := make(chan bool, 1)
+
+ go func() {
+ for i := range sinks {
+ _, err := db.Exec(fmt.Sprintf(`NOTIFY logs, '%d'`, i))
+ if err != nil {
+ done <- true
+ c.Fatal(err)
+ return
+ }
+ }
+ }()
+
+ var wg sync.WaitGroup
+ wg.Add(len(sinks))
+ for si, s := range sinks {
+ go func(si int, s eventSink) {
+ defer wg.Done()
+ defer sinks[si].Stop()
+ for i := 0; i <= si; i++ {
+ ev := <-sinks[si].Channel()
+ c.Logf("sink %d received event %d", si, i)
+ c.Check(ev.LogID, check.Equals, uint64(i))
+ row := ev.Detail()
+ if i == 0 {
+ // no matching row, null event
+ c.Check(row, check.IsNil)
+ } else {
+ c.Check(row, check.NotNil)
+ c.Check(row.ID, check.Equals, uint64(i))
+ c.Check(row.UUID, check.Not(check.Equals), "")
+ }
+ }
+ }(si, s)
+ }
+ go func() {
+ wg.Wait()
+ done <- true
+ }()
+
+ select {
+ case <-done:
+ case <-time.After(10 * time.Second):
+ c.Fatal("timed out")
+ }
+}
diff --git a/services/ws/event_test.go b/services/ws/event_test.go
new file mode 100644
index 0000000..eb67a34
--- /dev/null
+++ b/services/ws/event_test.go
@@ -0,0 +1,44 @@
+package main
+
+import (
+ "database/sql"
+
+ "git.curoverse.com/arvados.git/sdk/go/config"
+ check "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&eventSuite{})
+
+type eventSuite struct{}
+
+func (*eventSuite) TestDetail(c *check.C) {
+ var railsDB struct {
+ Test struct {
+ Database string
+ Username string
+ Password string
+ Host string
+ }
+ }
+ err := config.LoadFile(&railsDB, "../api/config/database.yml")
+ c.Assert(err, check.IsNil)
+ cfg := pgConfig{
+ "dbname": railsDB.Test.Database,
+ "host": railsDB.Test.Host,
+ "password": railsDB.Test.Password,
+ "user": railsDB.Test.Username,
+ }
+ db, err := sql.Open("postgres", cfg.ConnectionString())
+ c.Assert(err, check.IsNil)
+ e := &event{
+ LogID: 17,
+ db: db,
+ }
+ logRow := e.Detail()
+ c.Assert(logRow, check.NotNil)
+ c.Check(logRow, check.Equals, e.logRow)
+ c.Check(logRow.UUID, check.Equals, "zzzzz-57u5n-containerlog006")
+ c.Check(logRow.ObjectUUID, check.Equals, "zzzzz-dz642-logscontainer03")
+ c.Check(logRow.EventType, check.Equals, "crunchstat")
+ c.Check(logRow.Properties["text"], check.Equals, "2013-11-07_23:33:41 zzzzz-8i9sb-ahd7cie8jah9qui 29610 1 stderr crunchstat: cpu 1935.4300 user 59.4100 sys 8 cpus -- interval 10.0002 seconds 12.9900 user 0.9900 sys")
+}
diff --git a/services/ws/gocheck_test.go b/services/ws/gocheck_test.go
new file mode 100644
index 0000000..e86a3c6
--- /dev/null
+++ b/services/ws/gocheck_test.go
@@ -0,0 +1,11 @@
+package main
+
+import (
+ "testing"
+
+ check "gopkg.in/check.v1"
+)
+
+func TestGocheck(t *testing.T) {
+ check.TestingT(t)
+}
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list