X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/47eb67e4c084abde49d5463d4ced8b4436a59dfd..f3cb43d4be379703a965a1cb14cae5f5c855728f:/tools/sync-groups/sync-groups_test.go diff --git a/tools/sync-groups/sync-groups_test.go b/tools/sync-groups/sync-groups_test.go index 4a3e470c42..69326c98d9 100644 --- a/tools/sync-groups/sync-groups_test.go +++ b/tools/sync-groups/sync-groups_test.go @@ -11,8 +11,8 @@ import ( "strings" "testing" - "git.curoverse.com/arvados.git/sdk/go/arvados" - "git.curoverse.com/arvados.git/sdk/go/arvadostest" + "git.arvados.org/arvados.git/sdk/go/arvados" + "git.arvados.org/arvados.git/sdk/go/arvadostest" . "gopkg.in/check.v1" ) @@ -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.*") }