Disable LocalKeepBlobBuffersPerVCPU on the single node installer
[arvados.git] / tools / sync-groups / sync-groups_test.go
index 3ef36007976afe04a411bcf613ea24f6bd71ce6a..69326c98d958cacd7709d24c47b9c63abd690b78 100644 (file)
@@ -26,14 +26,6 @@ type TestSuite struct {
        users map[string]arvados.User
 }
 
-func (s *TestSuite) SetUpSuite(c *C) {
-       arvadostest.StartAPI()
-}
-
-func (s *TestSuite) TearDownSuite(c *C) {
-       arvadostest.StopAPI()
-}
-
 func (s *TestSuite) SetUpTest(c *C) {
        ac := arvados.NewClientFromEnv()
        u, err := ac.CurrentUser()
@@ -58,6 +50,7 @@ func (s *TestSuite) SetUpTest(c *C) {
        os.Args = []string{"cmd", "somefile.csv"}
        config, err := GetConfig()
        c.Assert(err, IsNil)
+       config.UserID = "email"
        // Confirm that the parent group was created
        gl = arvados.GroupList{}
        ac.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
@@ -106,7 +99,7 @@ func MakeTempCSVFile(data [][]string) (f *os.File, err error) {
 }
 
 // GroupMembershipExists checks that both needed links exist between user and group
-func GroupMembershipExists(ac *arvados.Client, userUUID string, groupUUID string) bool {
+func GroupMembershipExists(ac *arvados.Client, userUUID string, groupUUID string, perm string) bool {
        ll := LinkList{}
        // Check Group -> User can_read permission
        params := arvados.ResourceListParams{
@@ -145,7 +138,7 @@ func GroupMembershipExists(ac *arvados.Client, userUUID string, groupUUID string
                }, {
                        Attr:     "name",
                        Operator: "=",
-                       Operand:  "can_write",
+                       Operand:  perm,
                }, {
                        Attr:     "tail_uuid",
                        Operator: "=",
@@ -153,10 +146,7 @@ func GroupMembershipExists(ac *arvados.Client, userUUID string, groupUUID string
                }},
        }
        ac.RequestAndDecode(&ll, "GET", "/arvados/v1/links", nil, params)
-       if ll.Len() != 1 {
-               return false
-       }
-       return true
+       return ll.Len() == 1
 }
 
 // If named group exists, return its UUID
@@ -170,7 +160,7 @@ func RemoteGroupExists(cfg *ConfigParams, groupName string) (uuid string, err er
                }, {
                        Attr:     "owner_uuid",
                        Operator: "=",
-                       Operand:  cfg.ParentGroupUUID,
+                       Operand:  cfg.SysUserUUID,
                }, {
                        Attr:     "group_class",
                        Operator: "=",
@@ -197,11 +187,12 @@ func RemoteGroupExists(cfg *ConfigParams, groupName string) (uuid string, err er
 
 func (s *TestSuite) TestParseFlagsWithPositionalArgument(c *C) {
        cfg := ConfigParams{}
-       os.Args = []string{"cmd", "-verbose", "/tmp/somefile.csv"}
+       os.Args = []string{"cmd", "-verbose", "-case-insensitive", "/tmp/somefile.csv"}
        err := ParseFlags(&cfg)
        c.Assert(err, IsNil)
        c.Check(cfg.Path, Equals, "/tmp/somefile.csv")
        c.Check(cfg.Verbose, Equals, true)
+       c.Check(cfg.CaseInsensitive, Equals, true)
 }
 
 func (s *TestSuite) TestParseFlagsWithoutPositionalArgument(c *C) {
@@ -259,10 +250,103 @@ func (s *TestSuite) TestIgnoreSpaces(c *C) {
                groupUUID, err := RemoteGroupExists(s.cfg, groupName)
                c.Assert(err, IsNil)
                c.Assert(groupUUID, Not(Equals), "")
-               c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
+               c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
+       }
+}
+
+// Error out when records have <2 or >3 records
+func (s *TestSuite) TestWrongNumberOfFields(c *C) {
+       for _, testCase := range [][][]string{
+               {{"field1"}},
+               {{"field1", "field2", "field3", "field4"}},
+               {{"field1", "field2", "field3", "field4", "field5"}},
+       } {
+               tmpfile, err := MakeTempCSVFile(testCase)
+               c.Assert(err, IsNil)
+               defer os.Remove(tmpfile.Name())
+               s.cfg.Path = tmpfile.Name()
+               err = doMain(s.cfg)
+               c.Assert(err, Not(IsNil))
+       }
+}
+
+// Check different membership permissions
+func (s *TestSuite) TestMembershipLevels(c *C) {
+       userEmail := s.users[arvadostest.ActiveUserUUID].Email
+       userUUID := s.users[arvadostest.ActiveUserUUID].UUID
+       data := [][]string{
+               {"TestGroup1", userEmail, "can_read"},
+               {"TestGroup2", userEmail, "can_write"},
+               {"TestGroup3", userEmail, "can_manage"},
+               {"TestGroup4", userEmail, "invalid_permission"},
+       }
+       tmpfile, err := MakeTempCSVFile(data)
+       c.Assert(err, IsNil)
+       defer os.Remove(tmpfile.Name()) // clean up
+       s.cfg.Path = tmpfile.Name()
+       err = doMain(s.cfg)
+       c.Assert(err, IsNil)
+       for _, record := range data {
+               groupName := record[0]
+               permLevel := record[2]
+               if permLevel != "invalid_permission" {
+                       groupUUID, err := RemoteGroupExists(s.cfg, groupName)
+                       c.Assert(err, IsNil)
+                       c.Assert(groupUUID, Not(Equals), "")
+                       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, permLevel), Equals, true)
+               } else {
+                       groupUUID, err := RemoteGroupExists(s.cfg, groupName)
+                       c.Assert(err, IsNil)
+                       c.Assert(groupUUID, Equals, "")
+               }
        }
 }
 
+// Check membership level change
+func (s *TestSuite) TestMembershipLevelUpdate(c *C) {
+       userEmail := s.users[arvadostest.ActiveUserUUID].Email
+       userUUID := s.users[arvadostest.ActiveUserUUID].UUID
+       groupName := "TestGroup1"
+       // Give read permissions
+       tmpfile, err := MakeTempCSVFile([][]string{{groupName, userEmail, "can_read"}})
+       c.Assert(err, IsNil)
+       defer os.Remove(tmpfile.Name()) // clean up
+       s.cfg.Path = tmpfile.Name()
+       err = doMain(s.cfg)
+       c.Assert(err, IsNil)
+       // Check permissions
+       groupUUID, err := RemoteGroupExists(s.cfg, groupName)
+       c.Assert(err, IsNil)
+       c.Assert(groupUUID, Not(Equals), "")
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_read"), Equals, true)
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_write"), Equals, false)
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_manage"), Equals, false)
+
+       // Give write permissions
+       tmpfile, err = MakeTempCSVFile([][]string{{groupName, userEmail, "can_write"}})
+       c.Assert(err, IsNil)
+       defer os.Remove(tmpfile.Name()) // clean up
+       s.cfg.Path = tmpfile.Name()
+       err = doMain(s.cfg)
+       c.Assert(err, IsNil)
+       // Check permissions
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_read"), Equals, false)
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_write"), Equals, true)
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_manage"), Equals, false)
+
+       // Give manage permissions
+       tmpfile, err = MakeTempCSVFile([][]string{{groupName, userEmail, "can_manage"}})
+       c.Assert(err, IsNil)
+       defer os.Remove(tmpfile.Name()) // clean up
+       s.cfg.Path = tmpfile.Name()
+       err = doMain(s.cfg)
+       c.Assert(err, IsNil)
+       // Check permissions
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_read"), Equals, false)
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_write"), Equals, false)
+       c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_manage"), Equals, true)
+}
+
 // The absence of a user membership on the CSV file implies its removal
 func (s *TestSuite) TestMembershipRemoval(c *C) {
        localUserEmail := s.users[arvadostest.ActiveUserUUID].Email
@@ -286,8 +370,8 @@ func (s *TestSuite) TestMembershipRemoval(c *C) {
                groupUUID, err := RemoteGroupExists(s.cfg, groupName)
                c.Assert(err, IsNil)
                c.Assert(groupUUID, Not(Equals), "")
-               c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID), Equals, true)
-               c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID), Equals, true)
+               c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID, "can_write"), Equals, true)
+               c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID, "can_write"), Equals, true)
        }
        // New CSV with some previous membership missing
        data = [][]string{
@@ -304,14 +388,14 @@ func (s *TestSuite) TestMembershipRemoval(c *C) {
        groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
        c.Assert(err, IsNil)
        c.Assert(groupUUID, Not(Equals), "")
-       c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID), Equals, true)
-       c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID), Equals, false)
+       c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID, "can_write"), Equals, true)
+       c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID, "can_write"), Equals, false)
        // Confirm TestGroup1 memberships
        groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup2")
        c.Assert(err, IsNil)
        c.Assert(groupUUID, Not(Equals), "")
-       c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID), Equals, false)
-       c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID), Equals, true)
+       c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID, "can_write"), Equals, false)
+       c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID, "can_write"), Equals, true)
 }
 
 // If a group doesn't exist on the system, create it before adding users
@@ -336,7 +420,7 @@ func (s *TestSuite) TestAutoCreateGroupWhenNotExisting(c *C) {
        c.Assert(err, IsNil)
        c.Assert(groupUUID, Not(Equals), "")
        // active user should be a member
-       c.Assert(GroupMembershipExists(s.cfg.Client, arvadostest.ActiveUserUUID, groupUUID), Equals, true)
+       c.Assert(GroupMembershipExists(s.cfg.Client, arvadostest.ActiveUserUUID, groupUUID, "can_write"), Equals, true)
 }
 
 // Users listed on the file that don't exist on the system are ignored
@@ -362,21 +446,24 @@ func (s *TestSuite) TestIgnoreNonexistantUsers(c *C) {
        groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup4")
        c.Assert(err, IsNil)
        c.Assert(groupUUID, Not(Equals), "")
-       c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
+       c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
 }
 
-// Users listed on the file that don't exist on the system are ignored
+// Entries with missing data are ignored.
 func (s *TestSuite) TestIgnoreEmptyFields(c *C) {
        activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
        activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
        // Confirm that group doesn't exist
-       groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup4")
-       c.Assert(err, IsNil)
-       c.Assert(groupUUID, Equals, "")
+       for _, groupName := range []string{"TestGroup4", "TestGroup5"} {
+               groupUUID, err := RemoteGroupExists(s.cfg, groupName)
+               c.Assert(err, IsNil)
+               c.Assert(groupUUID, Equals, "")
+       }
        // Create file & run command
        data := [][]string{
-               {"", activeUserEmail}, // Empty field
-               {"TestGroup5", ""},    // Empty field
+               {"", activeUserEmail},               // Empty field
+               {"TestGroup5", ""},                  // Empty field
+               {"TestGroup5", activeUserEmail, ""}, // Empty 3rd field: is optional but cannot be empty
                {"TestGroup4", activeUserEmail},
        }
        tmpfile, err := MakeTempCSVFile(data)
@@ -385,11 +472,15 @@ func (s *TestSuite) TestIgnoreEmptyFields(c *C) {
        s.cfg.Path = tmpfile.Name()
        err = doMain(s.cfg)
        c.Assert(err, IsNil)
-       // Confirm that memberships exist
+       // Confirm that records about TestGroup5 were skipped
+       groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup5")
+       c.Assert(err, IsNil)
+       c.Assert(groupUUID, Equals, "")
+       // Confirm that membership exists
        groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup4")
        c.Assert(err, IsNil)
        c.Assert(groupUUID, Not(Equals), "")
-       c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
+       c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
 }
 
 // Instead of emails, use username as identifier
@@ -410,11 +501,72 @@ func (s *TestSuite) TestUseUsernames(c *C) {
        s.cfg.Path = tmpfile.Name()
        s.cfg.UserID = "username"
        err = doMain(s.cfg)
-       s.cfg.UserID = "email"
        c.Assert(err, IsNil)
        // Confirm that memberships exist
        groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup1")
        c.Assert(err, IsNil)
        c.Assert(groupUUID, Not(Equals), "")
-       c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
+       c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
+}
+
+func (s *TestSuite) TestUseUsernamesWithCaseInsensitiveMatching(c *C) {
+       activeUserName := strings.ToUpper(s.users[arvadostest.ActiveUserUUID].Username)
+       activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
+       // Confirm that group doesn't exist
+       groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
+       c.Assert(err, IsNil)
+       c.Assert(groupUUID, Equals, "")
+       // Create file & run command
+       data := [][]string{
+               {"TestGroup1", activeUserName},
+       }
+       tmpfile, err := MakeTempCSVFile(data)
+       c.Assert(err, IsNil)
+       defer os.Remove(tmpfile.Name()) // clean up
+       s.cfg.Path = tmpfile.Name()
+       s.cfg.UserID = "username"
+       s.cfg.CaseInsensitive = true
+       err = doMain(s.cfg)
+       c.Assert(err, IsNil)
+       // Confirm that memberships exist
+       groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup1")
+       c.Assert(err, IsNil)
+       c.Assert(groupUUID, Not(Equals), "")
+       c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
+}
+
+func (s *TestSuite) TestUsernamesCaseInsensitiveCollision(c *C) {
+       activeUserName := s.users[arvadostest.ActiveUserUUID].Username
+       activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
+
+       nu := arvados.User{}
+       nuUsername := strings.ToUpper(activeUserName)
+       err := s.cfg.Client.RequestAndDecode(&nu, "POST", "/arvados/v1/users", nil, map[string]interface{}{
+               "user": map[string]string{
+                       "username": nuUsername,
+               },
+       })
+       c.Assert(err, IsNil)
+
+       // Manually remove non-fixture user because /database/reset fails otherwise
+       defer s.cfg.Client.RequestAndDecode(nil, "DELETE", "/arvados/v1/users/"+nu.UUID, nil, nil)
+
+       c.Assert(nu.Username, Equals, nuUsername)
+       c.Assert(nu.UUID, Not(Equals), activeUserUUID)
+       c.Assert(nu.Username, Not(Equals), activeUserName)
+
+       data := [][]string{
+               {"SomeGroup", activeUserName},
+       }
+       tmpfile, err := MakeTempCSVFile(data)
+       c.Assert(err, IsNil)
+       defer os.Remove(tmpfile.Name()) // clean up
+
+       s.cfg.Path = tmpfile.Name()
+       s.cfg.UserID = "username"
+       s.cfg.CaseInsensitive = true
+       err = doMain(s.cfg)
+       // Should get an error because of "ACTIVE" and "Active" usernames
+       c.Assert(err, NotNil)
+       c.Assert(err, ErrorMatches, ".*case insensitive collision.*")
 }