1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
14 "git.curoverse.com/arvados.git/sdk/go/arvados"
15 "git.curoverse.com/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 // Clean any membership link and remote group created by the test
87 func (s *TestSuite) TearDownTest(c *C) {
89 // Reset database to fixture state after every test run.
90 err := s.cfg.Client.RequestAndDecode(&dst, "POST", "/database/reset", nil, nil)
94 var _ = Suite(&TestSuite{})
96 // MakeTempCVSFile creates a temp file with data as comma separated values
97 func MakeTempCSVFile(data [][]string) (f *os.File, err error) {
98 f, err = ioutil.TempFile("", "test_sync_remote_groups")
102 for _, line := range data {
103 fmt.Fprintf(f, "%s\n", strings.Join(line, ","))
109 // GroupMembershipExists checks that both needed links exist between user and group
110 func GroupMembershipExists(ac *arvados.Client, userUUID string, groupUUID string) bool {
112 // Check Group -> User can_read permission
113 params := arvados.ResourceListParams{
114 Filters: []arvados.Filter{{
117 Operand: "permission",
132 ac.RequestAndDecode(&ll, "GET", "/arvados/v1/links", nil, params)
136 // Check User -> Group can_write permission
137 params = arvados.ResourceListParams{
138 Filters: []arvados.Filter{{
141 Operand: "permission",
149 Operand: "can_write",
156 ac.RequestAndDecode(&ll, "GET", "/arvados/v1/links", nil, params)
163 // If named group exists, return its UUID
164 func RemoteGroupExists(cfg *ConfigParams, groupName string) (uuid string, err error) {
165 gl := arvados.GroupList{}
166 params := arvados.ResourceListParams{
167 Filters: []arvados.Filter{{
174 Operand: cfg.ParentGroupUUID,
181 err = cfg.Client.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
185 if gl.ItemsAvailable == 0 {
186 // No group with this name
188 } else if gl.ItemsAvailable == 1 {
190 uuid = gl.Items[0].UUID
192 // This should never happen
194 err = fmt.Errorf("more than 1 group found with the same name and parent")
199 func (s *TestSuite) TestParseFlagsWithPositionalArgument(c *C) {
200 cfg := ConfigParams{}
201 os.Args = []string{"cmd", "-verbose", "/tmp/somefile.csv"}
202 err := ParseFlags(&cfg)
204 c.Check(cfg.Path, Equals, "/tmp/somefile.csv")
205 c.Check(cfg.Verbose, Equals, true)
208 func (s *TestSuite) TestParseFlagsWithoutPositionalArgument(c *C) {
209 os.Args = []string{"cmd", "-verbose"}
210 err := ParseFlags(&ConfigParams{})
211 c.Assert(err, NotNil)
214 func (s *TestSuite) TestGetUserID(c *C) {
216 Email: "testuser@example.com",
217 Username: "Testuser",
219 email, err := GetUserID(u, "email")
221 c.Check(email, Equals, "testuser@example.com")
222 _, err = GetUserID(u, "bogus")
223 c.Assert(err, NotNil)
226 func (s *TestSuite) TestGetConfig(c *C) {
227 os.Args = []string{"cmd", "/tmp/somefile.csv"}
228 cfg, err := GetConfig()
230 c.Check(cfg.SysUserUUID, NotNil)
231 c.Check(cfg.Client, NotNil)
232 c.Check(cfg.ParentGroupUUID, NotNil)
233 c.Check(cfg.ParentGroupName, Equals, "Externally synchronized groups")
236 // Ignore leading & trailing spaces on group & users names
237 func (s *TestSuite) TestIgnoreSpaces(c *C) {
238 activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
239 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
240 // Confirm that the groups don't exist
241 for _, groupName := range []string{"TestGroup1", "TestGroup2", "Test Group 3"} {
242 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
244 c.Assert(groupUUID, Equals, "")
247 {" TestGroup1", activeUserEmail},
248 {"TestGroup2 ", " " + activeUserEmail},
249 {" Test Group 3 ", activeUserEmail + " "},
251 tmpfile, err := MakeTempCSVFile(data)
253 defer os.Remove(tmpfile.Name()) // clean up
254 s.cfg.Path = tmpfile.Name()
257 // Check that 3 groups were created correctly, and have the active user as
259 for _, groupName := range []string{"TestGroup1", "TestGroup2", "Test Group 3"} {
260 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
262 c.Assert(groupUUID, Not(Equals), "")
263 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
267 // The absence of a user membership on the CSV file implies its removal
268 func (s *TestSuite) TestMembershipRemoval(c *C) {
269 activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
270 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
272 {"TestGroup1", activeUserEmail},
273 {"TestGroup2", activeUserEmail},
275 tmpfile, err := MakeTempCSVFile(data)
277 defer os.Remove(tmpfile.Name()) // clean up
278 s.cfg.Path = tmpfile.Name()
281 // Confirm that memberships exist
282 for _, groupName := range []string{"TestGroup1", "TestGroup2"} {
283 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
285 c.Assert(groupUUID, Not(Equals), "")
286 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
288 // New CSV with one previous membership missing
290 {"TestGroup1", activeUserEmail},
292 tmpfile2, err := MakeTempCSVFile(data)
294 defer os.Remove(tmpfile2.Name()) // clean up
295 s.cfg.Path = tmpfile2.Name()
298 // Confirm TestGroup1 membership still exist
299 groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
301 c.Assert(groupUUID, Not(Equals), "")
302 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
303 // Confirm TestGroup2 membership was removed
304 groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup2")
306 c.Assert(groupUUID, Not(Equals), "")
307 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, false)
310 // If a group doesn't exist on the system, create it before adding users
311 func (s *TestSuite) TestAutoCreateGroupWhenNotExisting(c *C) {
312 groupName := "Testers"
313 // Confirm that group doesn't exist
314 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
316 c.Assert(groupUUID, Equals, "")
317 // Make a tmp CSV file
319 {groupName, s.users[arvadostest.ActiveUserUUID].Email},
321 tmpfile, err := MakeTempCSVFile(data)
323 defer os.Remove(tmpfile.Name()) // clean up
324 s.cfg.Path = tmpfile.Name()
327 // "Testers" group should now exist
328 groupUUID, err = RemoteGroupExists(s.cfg, groupName)
330 c.Assert(groupUUID, Not(Equals), "")
331 // active user should be a member
332 c.Assert(GroupMembershipExists(s.cfg.Client, arvadostest.ActiveUserUUID, groupUUID), Equals, true)
335 // Users listed on the file that don't exist on the system are ignored
336 func (s *TestSuite) TestIgnoreNonexistantUsers(c *C) {
337 activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
338 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
339 // Confirm that group doesn't exist
340 groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup4")
342 c.Assert(groupUUID, Equals, "")
343 // Create file & run command
345 {"TestGroup4", "nonexistantuser@unknowndomain.com"}, // Processed first
346 {"TestGroup4", activeUserEmail},
348 tmpfile, err := MakeTempCSVFile(data)
350 defer os.Remove(tmpfile.Name()) // clean up
351 s.cfg.Path = tmpfile.Name()
354 // Confirm that memberships exist
355 groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup4")
357 c.Assert(groupUUID, Not(Equals), "")
358 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
361 // Users listed on the file that don't exist on the system are ignored
362 func (s *TestSuite) TestIgnoreEmptyFields(c *C) {
363 activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
364 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
365 // Confirm that group doesn't exist
366 groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup4")
368 c.Assert(groupUUID, Equals, "")
369 // Create file & run command
371 {"", activeUserEmail}, // Empty field
372 {"TestGroup5", ""}, // Empty field
373 {"TestGroup4", activeUserEmail},
375 tmpfile, err := MakeTempCSVFile(data)
377 defer os.Remove(tmpfile.Name()) // clean up
378 s.cfg.Path = tmpfile.Name()
381 // Confirm that memberships exist
382 groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup4")
384 c.Assert(groupUUID, Not(Equals), "")
385 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)
388 // Instead of emails, use username as identifier
389 func (s *TestSuite) TestUseUsernames(c *C) {
390 activeUserName := s.users[arvadostest.ActiveUserUUID].Username
391 activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
392 // Confirm that group doesn't exist
393 groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
395 c.Assert(groupUUID, Equals, "")
396 // Create file & run command
398 {"TestGroup1", activeUserName},
400 tmpfile, err := MakeTempCSVFile(data)
402 defer os.Remove(tmpfile.Name()) // clean up
403 s.cfg.Path = tmpfile.Name()
404 s.cfg.UserID = "username"
406 s.cfg.UserID = "email"
408 // Confirm that memberships exist
409 groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup1")
411 c.Assert(groupUUID, Not(Equals), "")
412 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID), Equals, true)