1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
14 "git.arvados.org/arvados.git/sdk/go/arvados"
15 "git.arvados.org/arvados.git/sdk/go/arvadostest"
19 // Gocheck boilerplate
20 func Test(t *testing.T) {
24 type TestSuite struct {
26 users map[string]arvados.User
29 func (s *TestSuite) SetUpSuite(c *C) {
30 arvadostest.StartAPI()
33 func (s *TestSuite) TearDownSuite(c *C) {
37 func (s *TestSuite) SetUpTest(c *C) {
38 ac := arvados.NewClientFromEnv()
39 u, err := ac.CurrentUser()
41 // Check that the parent group doesn't exist
42 sysUserUUID := u.UUID[:12] + "000000000000000"
43 gl := arvados.GroupList{}
44 params := arvados.ResourceListParams{
45 Filters: []arvados.Filter{{
52 Operand: "Externally synchronized groups",
55 ac.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
56 c.Assert(gl.ItemsAvailable, Equals, 0)
58 os.Args = []string{"cmd", "somefile.csv"}
59 config, err := GetConfig()
61 // Confirm that the parent group was created
62 gl = arvados.GroupList{}
63 ac.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
64 c.Assert(gl.ItemsAvailable, Equals, 1)
65 // Config set up complete, save config for further testing
68 // Fetch current user list
69 ul := arvados.UserList{}
70 params = arvados.ResourceListParams{
71 Filters: []arvados.Filter{{
74 Operand: s.cfg.SysUserUUID,
77 ac.RequestAndDecode(&ul, "GET", "/arvados/v1/users", nil, params)
78 c.Assert(ul.ItemsAvailable, Not(Equals), 0)
79 s.users = make(map[string]arvados.User)
80 for _, u := range ul.Items {
83 c.Assert(len(s.users), Not(Equals), 0)
86 func (s *TestSuite) TearDownTest(c *C) {
88 // Reset database to fixture state after every test run.
89 err := s.cfg.Client.RequestAndDecode(&dst, "POST", "/database/reset", nil, nil)
93 var _ = Suite(&TestSuite{})
95 // MakeTempCSVFile creates a temp file with data as comma separated values
96 func MakeTempCSVFile(data [][]string) (f *os.File, err error) {
97 f, err = ioutil.TempFile("", "test_sync_remote_groups")
101 for _, line := range data {
102 fmt.Fprintf(f, "%s\n", strings.Join(line, ","))
108 // GroupMembershipExists checks that both needed links exist between user and group
109 func GroupMembershipExists(ac *arvados.Client, userUUID string, groupUUID string) bool {
111 // Check Group -> User can_read permission
112 params := arvados.ResourceListParams{
113 Filters: []arvados.Filter{{
116 Operand: "permission",
131 ac.RequestAndDecode(&ll, "GET", "/arvados/v1/links", nil, params)
135 // Check User -> Group can_write permission
136 params = arvados.ResourceListParams{
137 Filters: []arvados.Filter{{
140 Operand: "permission",
148 Operand: "can_write",
155 ac.RequestAndDecode(&ll, "GET", "/arvados/v1/links", nil, params)
162 // If named group exists, return its UUID
163 func RemoteGroupExists(cfg *ConfigParams, groupName string) (uuid string, err error) {
164 gl := arvados.GroupList{}
165 params := arvados.ResourceListParams{
166 Filters: []arvados.Filter{{
173 Operand: cfg.ParentGroupUUID,
180 err = cfg.Client.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
184 if gl.ItemsAvailable == 0 {
185 // No group with this name
187 } else if gl.ItemsAvailable == 1 {
189 uuid = gl.Items[0].UUID
191 // This should never happen
193 err = fmt.Errorf("more than 1 group found with the same name and parent")
198 func (s *TestSuite) TestParseFlagsWithPositionalArgument(c *C) {
199 cfg := ConfigParams{}
200 os.Args = []string{"cmd", "-verbose", "/tmp/somefile.csv"}
201 err := ParseFlags(&cfg)
203 c.Check(cfg.Path, Equals, "/tmp/somefile.csv")
204 c.Check(cfg.Verbose, Equals, true)
207 func (s *TestSuite) TestParseFlagsWithoutPositionalArgument(c *C) {
208 os.Args = []string{"cmd", "-verbose"}
209 err := ParseFlags(&ConfigParams{})
210 c.Assert(err, NotNil)
213 func (s *TestSuite) TestGetUserID(c *C) {
215 Email: "testuser@example.com",
216 Username: "Testuser",
218 email, err := GetUserID(u, "email")
220 c.Check(email, Equals, "testuser@example.com")
221 _, err = GetUserID(u, "bogus")
222 c.Assert(err, NotNil)
225 func (s *TestSuite) TestGetConfig(c *C) {
226 os.Args = []string{"cmd", "/tmp/somefile.csv"}
227 cfg, err := GetConfig()
229 c.Check(cfg.SysUserUUID, NotNil)
230 c.Check(cfg.Client, NotNil)
231 c.Check(cfg.ParentGroupUUID, NotNil)
232 c.Check(cfg.ParentGroupName, Equals, "Externally synchronized groups")
235 // Ignore leading & trailing spaces on group & users names
236 func (s *TestSuite) TestIgnoreSpaces(c *C) {
237 activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
238 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
239 // Confirm that the groups don't exist
240 for _, groupName := range []string{"TestGroup1", "TestGroup2", "Test Group 3"} {
241 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
243 c.Assert(groupUUID, Equals, "")
246 {" TestGroup1", activeUserEmail},
247 {"TestGroup2 ", " " + activeUserEmail},
248 {" Test Group 3 ", activeUserEmail + " "},
250 tmpfile, err := MakeTempCSVFile(data)
252 defer os.Remove(tmpfile.Name()) // clean up
253 s.cfg.Path = tmpfile.Name()
256 // Check that 3 groups were created correctly, and have the active user as
258 for _, groupName := range []string{"TestGroup1", "TestGroup2", "Test Group 3"} {
259 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
261 c.Assert(groupUUID, Not(Equals), "")
262 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
266 // The absence of a user membership on the CSV file implies its removal
267 func (s *TestSuite) TestMembershipRemoval(c *C) {
268 localUserEmail := s.users[arvadostest.ActiveUserUUID].Email
269 localUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
270 remoteUserEmail := s.users[arvadostest.FederatedActiveUserUUID].Email
271 remoteUserUUID := s.users[arvadostest.FederatedActiveUserUUID].UUID
273 {"TestGroup1", localUserEmail},
274 {"TestGroup1", remoteUserEmail},
275 {"TestGroup2", localUserEmail},
276 {"TestGroup2", remoteUserEmail},
278 tmpfile, err := MakeTempCSVFile(data)
280 defer os.Remove(tmpfile.Name()) // clean up
281 s.cfg.Path = tmpfile.Name()
284 // Confirm that memberships exist
285 for _, groupName := range []string{"TestGroup1", "TestGroup2"} {
286 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
288 c.Assert(groupUUID, Not(Equals), "")
289 c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID), Equals, true)
290 c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID), Equals, true)
292 // New CSV with some previous membership missing
294 {"TestGroup1", localUserEmail},
295 {"TestGroup2", remoteUserEmail},
297 tmpfile2, err := MakeTempCSVFile(data)
299 defer os.Remove(tmpfile2.Name()) // clean up
300 s.cfg.Path = tmpfile2.Name()
303 // Confirm TestGroup1 memberships
304 groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
306 c.Assert(groupUUID, Not(Equals), "")
307 c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID), Equals, true)
308 c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID), Equals, false)
309 // Confirm TestGroup1 memberships
310 groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup2")
312 c.Assert(groupUUID, Not(Equals), "")
313 c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID), Equals, false)
314 c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID), Equals, true)
317 // If a group doesn't exist on the system, create it before adding users
318 func (s *TestSuite) TestAutoCreateGroupWhenNotExisting(c *C) {
319 groupName := "Testers"
320 // Confirm that group doesn't exist
321 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
323 c.Assert(groupUUID, Equals, "")
324 // Make a tmp CSV file
326 {groupName, s.users[arvadostest.ActiveUserUUID].Email},
328 tmpfile, err := MakeTempCSVFile(data)
330 defer os.Remove(tmpfile.Name()) // clean up
331 s.cfg.Path = tmpfile.Name()
334 // "Testers" group should now exist
335 groupUUID, err = RemoteGroupExists(s.cfg, groupName)
337 c.Assert(groupUUID, Not(Equals), "")
338 // active user should be a member
339 c.Assert(GroupMembershipExists(s.cfg.Client, arvadostest.ActiveUserUUID, groupUUID), Equals, true)
342 // Users listed on the file that don't exist on the system are ignored
343 func (s *TestSuite) TestIgnoreNonexistantUsers(c *C) {
344 activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
345 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
346 // Confirm that group doesn't exist
347 groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup4")
349 c.Assert(groupUUID, Equals, "")
350 // Create file & run command
352 {"TestGroup4", "nonexistantuser@unknowndomain.com"}, // Processed first
353 {"TestGroup4", activeUserEmail},
355 tmpfile, err := MakeTempCSVFile(data)
357 defer os.Remove(tmpfile.Name()) // clean up
358 s.cfg.Path = tmpfile.Name()
361 // Confirm that memberships exist
362 groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup4")
364 c.Assert(groupUUID, Not(Equals), "")
365 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
368 // Users listed on the file that don't exist on the system are ignored
369 func (s *TestSuite) TestIgnoreEmptyFields(c *C) {
370 activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
371 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
372 // Confirm that group doesn't exist
373 groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup4")
375 c.Assert(groupUUID, Equals, "")
376 // Create file & run command
378 {"", activeUserEmail}, // Empty field
379 {"TestGroup5", ""}, // Empty field
380 {"TestGroup4", activeUserEmail},
382 tmpfile, err := MakeTempCSVFile(data)
384 defer os.Remove(tmpfile.Name()) // clean up
385 s.cfg.Path = tmpfile.Name()
388 // Confirm that memberships exist
389 groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup4")
391 c.Assert(groupUUID, Not(Equals), "")
392 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
395 // Instead of emails, use username as identifier
396 func (s *TestSuite) TestUseUsernames(c *C) {
397 activeUserName := s.users[arvadostest.ActiveUserUUID].Username
398 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
399 // Confirm that group doesn't exist
400 groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
402 c.Assert(groupUUID, Equals, "")
403 // Create file & run command
405 {"TestGroup1", activeUserName},
407 tmpfile, err := MakeTempCSVFile(data)
409 defer os.Remove(tmpfile.Name()) // clean up
410 s.cfg.Path = tmpfile.Name()
411 s.cfg.UserID = "username"
413 s.cfg.UserID = "email"
415 // Confirm that memberships exist
416 groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup1")
418 c.Assert(groupUUID, Not(Equals), "")
419 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)