[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