20610: Tweaks postgresql access control to allow multiple controller hosts.
[arvados.git] / tools / sync-groups / sync-groups_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package main
6
7 import (
8         "fmt"
9         "io/ioutil"
10         "os"
11         "strings"
12         "testing"
13
14         "git.arvados.org/arvados.git/sdk/go/arvados"
15         "git.arvados.org/arvados.git/sdk/go/arvadostest"
16         . "gopkg.in/check.v1"
17 )
18
19 // Gocheck boilerplate
20 func Test(t *testing.T) {
21         TestingT(t)
22 }
23
24 type TestSuite struct {
25         cfg   *ConfigParams
26         users map[string]arvados.User
27 }
28
29 func (s *TestSuite) SetUpTest(c *C) {
30         ac := arvados.NewClientFromEnv()
31         u, err := ac.CurrentUser()
32         c.Assert(err, IsNil)
33         // Check that the parent group doesn't exist
34         sysUserUUID := u.UUID[:12] + "000000000000000"
35         gl := arvados.GroupList{}
36         params := arvados.ResourceListParams{
37                 Filters: []arvados.Filter{{
38                         Attr:     "owner_uuid",
39                         Operator: "=",
40                         Operand:  sysUserUUID,
41                 }, {
42                         Attr:     "name",
43                         Operator: "=",
44                         Operand:  "Externally synchronized groups",
45                 }},
46         }
47         ac.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
48         c.Assert(gl.ItemsAvailable, Equals, 0)
49         // Set up config
50         os.Args = []string{"cmd", "somefile.csv"}
51         config, err := GetConfig()
52         c.Assert(err, IsNil)
53         config.UserID = "email"
54         // Confirm that the parent group was created
55         gl = arvados.GroupList{}
56         ac.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
57         c.Assert(gl.ItemsAvailable, Equals, 1)
58         // Config set up complete, save config for further testing
59         s.cfg = &config
60
61         // Fetch current user list
62         ul := arvados.UserList{}
63         params = arvados.ResourceListParams{
64                 Filters: []arvados.Filter{{
65                         Attr:     "uuid",
66                         Operator: "!=",
67                         Operand:  s.cfg.SysUserUUID,
68                 }},
69         }
70         ac.RequestAndDecode(&ul, "GET", "/arvados/v1/users", nil, params)
71         c.Assert(ul.ItemsAvailable, Not(Equals), 0)
72         s.users = make(map[string]arvados.User)
73         for _, u := range ul.Items {
74                 s.users[u.UUID] = u
75         }
76         c.Assert(len(s.users), Not(Equals), 0)
77 }
78
79 func (s *TestSuite) TearDownTest(c *C) {
80         var dst interface{}
81         // Reset database to fixture state after every test run.
82         err := s.cfg.Client.RequestAndDecode(&dst, "POST", "/database/reset", nil, nil)
83         c.Assert(err, IsNil)
84 }
85
86 var _ = Suite(&TestSuite{})
87
88 // MakeTempCSVFile creates a temp file with data as comma separated values
89 func MakeTempCSVFile(data [][]string) (f *os.File, err error) {
90         f, err = ioutil.TempFile("", "test_sync_remote_groups")
91         if err != nil {
92                 return
93         }
94         for _, line := range data {
95                 fmt.Fprintf(f, "%s\n", strings.Join(line, ","))
96         }
97         err = f.Close()
98         return
99 }
100
101 // GroupMembershipExists checks that both needed links exist between user and group
102 func GroupMembershipExists(ac *arvados.Client, userUUID string, groupUUID string, perm string) bool {
103         ll := LinkList{}
104         // Check Group -> User can_read permission
105         params := arvados.ResourceListParams{
106                 Filters: []arvados.Filter{{
107                         Attr:     "link_class",
108                         Operator: "=",
109                         Operand:  "permission",
110                 }, {
111                         Attr:     "tail_uuid",
112                         Operator: "=",
113                         Operand:  groupUUID,
114                 }, {
115                         Attr:     "name",
116                         Operator: "=",
117                         Operand:  "can_read",
118                 }, {
119                         Attr:     "head_uuid",
120                         Operator: "=",
121                         Operand:  userUUID,
122                 }},
123         }
124         ac.RequestAndDecode(&ll, "GET", "/arvados/v1/links", nil, params)
125         if ll.Len() != 1 {
126                 return false
127         }
128         // Check User -> Group can_write permission
129         params = arvados.ResourceListParams{
130                 Filters: []arvados.Filter{{
131                         Attr:     "link_class",
132                         Operator: "=",
133                         Operand:  "permission",
134                 }, {
135                         Attr:     "head_uuid",
136                         Operator: "=",
137                         Operand:  groupUUID,
138                 }, {
139                         Attr:     "name",
140                         Operator: "=",
141                         Operand:  perm,
142                 }, {
143                         Attr:     "tail_uuid",
144                         Operator: "=",
145                         Operand:  userUUID,
146                 }},
147         }
148         ac.RequestAndDecode(&ll, "GET", "/arvados/v1/links", nil, params)
149         return ll.Len() == 1
150 }
151
152 // If named group exists, return its UUID
153 func RemoteGroupExists(cfg *ConfigParams, groupName string) (uuid string, err error) {
154         gl := arvados.GroupList{}
155         params := arvados.ResourceListParams{
156                 Filters: []arvados.Filter{{
157                         Attr:     "name",
158                         Operator: "=",
159                         Operand:  groupName,
160                 }, {
161                         Attr:     "owner_uuid",
162                         Operator: "=",
163                         Operand:  cfg.SysUserUUID,
164                 }, {
165                         Attr:     "group_class",
166                         Operator: "=",
167                         Operand:  "role",
168                 }},
169         }
170         err = cfg.Client.RequestAndDecode(&gl, "GET", "/arvados/v1/groups", nil, params)
171         if err != nil {
172                 return "", err
173         }
174         if gl.ItemsAvailable == 0 {
175                 // No group with this name
176                 uuid = ""
177         } else if gl.ItemsAvailable == 1 {
178                 // Group found
179                 uuid = gl.Items[0].UUID
180         } else {
181                 // This should never happen
182                 uuid = ""
183                 err = fmt.Errorf("more than 1 group found with the same name and parent")
184         }
185         return
186 }
187
188 func (s *TestSuite) TestParseFlagsWithPositionalArgument(c *C) {
189         cfg := ConfigParams{}
190         os.Args = []string{"cmd", "-verbose", "-case-insensitive", "/tmp/somefile.csv"}
191         err := ParseFlags(&cfg)
192         c.Assert(err, IsNil)
193         c.Check(cfg.Path, Equals, "/tmp/somefile.csv")
194         c.Check(cfg.Verbose, Equals, true)
195         c.Check(cfg.CaseInsensitive, Equals, true)
196 }
197
198 func (s *TestSuite) TestParseFlagsWithoutPositionalArgument(c *C) {
199         os.Args = []string{"cmd", "-verbose"}
200         err := ParseFlags(&ConfigParams{})
201         c.Assert(err, NotNil)
202 }
203
204 func (s *TestSuite) TestGetUserID(c *C) {
205         u := arvados.User{
206                 Email:    "testuser@example.com",
207                 Username: "Testuser",
208         }
209         email, err := GetUserID(u, "email")
210         c.Assert(err, IsNil)
211         c.Check(email, Equals, "testuser@example.com")
212         _, err = GetUserID(u, "bogus")
213         c.Assert(err, NotNil)
214 }
215
216 func (s *TestSuite) TestGetConfig(c *C) {
217         os.Args = []string{"cmd", "/tmp/somefile.csv"}
218         cfg, err := GetConfig()
219         c.Assert(err, IsNil)
220         c.Check(cfg.SysUserUUID, NotNil)
221         c.Check(cfg.Client, NotNil)
222         c.Check(cfg.ParentGroupUUID, NotNil)
223         c.Check(cfg.ParentGroupName, Equals, "Externally synchronized groups")
224 }
225
226 // Ignore leading & trailing spaces on group & users names
227 func (s *TestSuite) TestIgnoreSpaces(c *C) {
228         activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
229         activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
230         // Confirm that the groups don't exist
231         for _, groupName := range []string{"TestGroup1", "TestGroup2", "Test Group 3"} {
232                 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
233                 c.Assert(err, IsNil)
234                 c.Assert(groupUUID, Equals, "")
235         }
236         data := [][]string{
237                 {" TestGroup1", activeUserEmail},
238                 {"TestGroup2 ", " " + activeUserEmail},
239                 {" Test Group 3 ", activeUserEmail + " "},
240         }
241         tmpfile, err := MakeTempCSVFile(data)
242         c.Assert(err, IsNil)
243         defer os.Remove(tmpfile.Name()) // clean up
244         s.cfg.Path = tmpfile.Name()
245         err = doMain(s.cfg)
246         c.Assert(err, IsNil)
247         // Check that 3 groups were created correctly, and have the active user as
248         // a member.
249         for _, groupName := range []string{"TestGroup1", "TestGroup2", "Test Group 3"} {
250                 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
251                 c.Assert(err, IsNil)
252                 c.Assert(groupUUID, Not(Equals), "")
253                 c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
254         }
255 }
256
257 // Error out when records have <2 or >3 records
258 func (s *TestSuite) TestWrongNumberOfFields(c *C) {
259         for _, testCase := range [][][]string{
260                 {{"field1"}},
261                 {{"field1", "field2", "field3", "field4"}},
262                 {{"field1", "field2", "field3", "field4", "field5"}},
263         } {
264                 tmpfile, err := MakeTempCSVFile(testCase)
265                 c.Assert(err, IsNil)
266                 defer os.Remove(tmpfile.Name())
267                 s.cfg.Path = tmpfile.Name()
268                 err = doMain(s.cfg)
269                 c.Assert(err, Not(IsNil))
270         }
271 }
272
273 // Check different membership permissions
274 func (s *TestSuite) TestMembershipLevels(c *C) {
275         userEmail := s.users[arvadostest.ActiveUserUUID].Email
276         userUUID := s.users[arvadostest.ActiveUserUUID].UUID
277         data := [][]string{
278                 {"TestGroup1", userEmail, "can_read"},
279                 {"TestGroup2", userEmail, "can_write"},
280                 {"TestGroup3", userEmail, "can_manage"},
281                 {"TestGroup4", userEmail, "invalid_permission"},
282         }
283         tmpfile, err := MakeTempCSVFile(data)
284         c.Assert(err, IsNil)
285         defer os.Remove(tmpfile.Name()) // clean up
286         s.cfg.Path = tmpfile.Name()
287         err = doMain(s.cfg)
288         c.Assert(err, IsNil)
289         for _, record := range data {
290                 groupName := record[0]
291                 permLevel := record[2]
292                 if permLevel != "invalid_permission" {
293                         groupUUID, err := RemoteGroupExists(s.cfg, groupName)
294                         c.Assert(err, IsNil)
295                         c.Assert(groupUUID, Not(Equals), "")
296                         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, permLevel), Equals, true)
297                 } else {
298                         groupUUID, err := RemoteGroupExists(s.cfg, groupName)
299                         c.Assert(err, IsNil)
300                         c.Assert(groupUUID, Equals, "")
301                 }
302         }
303 }
304
305 // Check membership level change
306 func (s *TestSuite) TestMembershipLevelUpdate(c *C) {
307         userEmail := s.users[arvadostest.ActiveUserUUID].Email
308         userUUID := s.users[arvadostest.ActiveUserUUID].UUID
309         groupName := "TestGroup1"
310         // Give read permissions
311         tmpfile, err := MakeTempCSVFile([][]string{{groupName, userEmail, "can_read"}})
312         c.Assert(err, IsNil)
313         defer os.Remove(tmpfile.Name()) // clean up
314         s.cfg.Path = tmpfile.Name()
315         err = doMain(s.cfg)
316         c.Assert(err, IsNil)
317         // Check permissions
318         groupUUID, err := RemoteGroupExists(s.cfg, groupName)
319         c.Assert(err, IsNil)
320         c.Assert(groupUUID, Not(Equals), "")
321         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_read"), Equals, true)
322         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_write"), Equals, false)
323         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_manage"), Equals, false)
324
325         // Give write permissions
326         tmpfile, err = MakeTempCSVFile([][]string{{groupName, userEmail, "can_write"}})
327         c.Assert(err, IsNil)
328         defer os.Remove(tmpfile.Name()) // clean up
329         s.cfg.Path = tmpfile.Name()
330         err = doMain(s.cfg)
331         c.Assert(err, IsNil)
332         // Check permissions
333         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_read"), Equals, false)
334         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_write"), Equals, true)
335         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_manage"), Equals, false)
336
337         // Give manage permissions
338         tmpfile, err = MakeTempCSVFile([][]string{{groupName, userEmail, "can_manage"}})
339         c.Assert(err, IsNil)
340         defer os.Remove(tmpfile.Name()) // clean up
341         s.cfg.Path = tmpfile.Name()
342         err = doMain(s.cfg)
343         c.Assert(err, IsNil)
344         // Check permissions
345         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_read"), Equals, false)
346         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_write"), Equals, false)
347         c.Assert(GroupMembershipExists(s.cfg.Client, userUUID, groupUUID, "can_manage"), Equals, true)
348 }
349
350 // The absence of a user membership on the CSV file implies its removal
351 func (s *TestSuite) TestMembershipRemoval(c *C) {
352         localUserEmail := s.users[arvadostest.ActiveUserUUID].Email
353         localUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
354         remoteUserEmail := s.users[arvadostest.FederatedActiveUserUUID].Email
355         remoteUserUUID := s.users[arvadostest.FederatedActiveUserUUID].UUID
356         data := [][]string{
357                 {"TestGroup1", localUserEmail},
358                 {"TestGroup1", remoteUserEmail},
359                 {"TestGroup2", localUserEmail},
360                 {"TestGroup2", remoteUserEmail},
361         }
362         tmpfile, err := MakeTempCSVFile(data)
363         c.Assert(err, IsNil)
364         defer os.Remove(tmpfile.Name()) // clean up
365         s.cfg.Path = tmpfile.Name()
366         err = doMain(s.cfg)
367         c.Assert(err, IsNil)
368         // Confirm that memberships exist
369         for _, groupName := range []string{"TestGroup1", "TestGroup2"} {
370                 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
371                 c.Assert(err, IsNil)
372                 c.Assert(groupUUID, Not(Equals), "")
373                 c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID, "can_write"), Equals, true)
374                 c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID, "can_write"), Equals, true)
375         }
376         // New CSV with some previous membership missing
377         data = [][]string{
378                 {"TestGroup1", localUserEmail},
379                 {"TestGroup2", remoteUserEmail},
380         }
381         tmpfile2, err := MakeTempCSVFile(data)
382         c.Assert(err, IsNil)
383         defer os.Remove(tmpfile2.Name()) // clean up
384         s.cfg.Path = tmpfile2.Name()
385         err = doMain(s.cfg)
386         c.Assert(err, IsNil)
387         // Confirm TestGroup1 memberships
388         groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
389         c.Assert(err, IsNil)
390         c.Assert(groupUUID, Not(Equals), "")
391         c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID, "can_write"), Equals, true)
392         c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID, "can_write"), Equals, false)
393         // Confirm TestGroup1 memberships
394         groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup2")
395         c.Assert(err, IsNil)
396         c.Assert(groupUUID, Not(Equals), "")
397         c.Assert(GroupMembershipExists(s.cfg.Client, localUserUUID, groupUUID, "can_write"), Equals, false)
398         c.Assert(GroupMembershipExists(s.cfg.Client, remoteUserUUID, groupUUID, "can_write"), Equals, true)
399 }
400
401 // If a group doesn't exist on the system, create it before adding users
402 func (s *TestSuite) TestAutoCreateGroupWhenNotExisting(c *C) {
403         groupName := "Testers"
404         // Confirm that group doesn't exist
405         groupUUID, err := RemoteGroupExists(s.cfg, groupName)
406         c.Assert(err, IsNil)
407         c.Assert(groupUUID, Equals, "")
408         // Make a tmp CSV file
409         data := [][]string{
410                 {groupName, s.users[arvadostest.ActiveUserUUID].Email},
411         }
412         tmpfile, err := MakeTempCSVFile(data)
413         c.Assert(err, IsNil)
414         defer os.Remove(tmpfile.Name()) // clean up
415         s.cfg.Path = tmpfile.Name()
416         err = doMain(s.cfg)
417         c.Assert(err, IsNil)
418         // "Testers" group should now exist
419         groupUUID, err = RemoteGroupExists(s.cfg, groupName)
420         c.Assert(err, IsNil)
421         c.Assert(groupUUID, Not(Equals), "")
422         // active user should be a member
423         c.Assert(GroupMembershipExists(s.cfg.Client, arvadostest.ActiveUserUUID, groupUUID, "can_write"), Equals, true)
424 }
425
426 // Users listed on the file that don't exist on the system are ignored
427 func (s *TestSuite) TestIgnoreNonexistantUsers(c *C) {
428         activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
429         activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
430         // Confirm that group doesn't exist
431         groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup4")
432         c.Assert(err, IsNil)
433         c.Assert(groupUUID, Equals, "")
434         // Create file & run command
435         data := [][]string{
436                 {"TestGroup4", "nonexistantuser@unknowndomain.com"}, // Processed first
437                 {"TestGroup4", activeUserEmail},
438         }
439         tmpfile, err := MakeTempCSVFile(data)
440         c.Assert(err, IsNil)
441         defer os.Remove(tmpfile.Name()) // clean up
442         s.cfg.Path = tmpfile.Name()
443         err = doMain(s.cfg)
444         c.Assert(err, IsNil)
445         // Confirm that memberships exist
446         groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup4")
447         c.Assert(err, IsNil)
448         c.Assert(groupUUID, Not(Equals), "")
449         c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
450 }
451
452 // Entries with missing data are ignored.
453 func (s *TestSuite) TestIgnoreEmptyFields(c *C) {
454         activeUserEmail := s.users[arvadostest.ActiveUserUUID].Email
455         activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
456         // Confirm that group doesn't exist
457         for _, groupName := range []string{"TestGroup4", "TestGroup5"} {
458                 groupUUID, err := RemoteGroupExists(s.cfg, groupName)
459                 c.Assert(err, IsNil)
460                 c.Assert(groupUUID, Equals, "")
461         }
462         // Create file & run command
463         data := [][]string{
464                 {"", activeUserEmail},               // Empty field
465                 {"TestGroup5", ""},                  // Empty field
466                 {"TestGroup5", activeUserEmail, ""}, // Empty 3rd field: is optional but cannot be empty
467                 {"TestGroup4", activeUserEmail},
468         }
469         tmpfile, err := MakeTempCSVFile(data)
470         c.Assert(err, IsNil)
471         defer os.Remove(tmpfile.Name()) // clean up
472         s.cfg.Path = tmpfile.Name()
473         err = doMain(s.cfg)
474         c.Assert(err, IsNil)
475         // Confirm that records about TestGroup5 were skipped
476         groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup5")
477         c.Assert(err, IsNil)
478         c.Assert(groupUUID, Equals, "")
479         // Confirm that membership exists
480         groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup4")
481         c.Assert(err, IsNil)
482         c.Assert(groupUUID, Not(Equals), "")
483         c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
484 }
485
486 // Instead of emails, use username as identifier
487 func (s *TestSuite) TestUseUsernames(c *C) {
488         activeUserName := s.users[arvadostest.ActiveUserUUID].Username
489         activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
490         // Confirm that group doesn't exist
491         groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
492         c.Assert(err, IsNil)
493         c.Assert(groupUUID, Equals, "")
494         // Create file & run command
495         data := [][]string{
496                 {"TestGroup1", activeUserName},
497         }
498         tmpfile, err := MakeTempCSVFile(data)
499         c.Assert(err, IsNil)
500         defer os.Remove(tmpfile.Name()) // clean up
501         s.cfg.Path = tmpfile.Name()
502         s.cfg.UserID = "username"
503         err = doMain(s.cfg)
504         c.Assert(err, IsNil)
505         // Confirm that memberships exist
506         groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup1")
507         c.Assert(err, IsNil)
508         c.Assert(groupUUID, Not(Equals), "")
509         c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
510 }
511
512 func (s *TestSuite) TestUseUsernamesWithCaseInsensitiveMatching(c *C) {
513         activeUserName := strings.ToUpper(s.users[arvadostest.ActiveUserUUID].Username)
514         activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
515         // Confirm that group doesn't exist
516         groupUUID, err := RemoteGroupExists(s.cfg, "TestGroup1")
517         c.Assert(err, IsNil)
518         c.Assert(groupUUID, Equals, "")
519         // Create file & run command
520         data := [][]string{
521                 {"TestGroup1", activeUserName},
522         }
523         tmpfile, err := MakeTempCSVFile(data)
524         c.Assert(err, IsNil)
525         defer os.Remove(tmpfile.Name()) // clean up
526         s.cfg.Path = tmpfile.Name()
527         s.cfg.UserID = "username"
528         s.cfg.CaseInsensitive = true
529         err = doMain(s.cfg)
530         c.Assert(err, IsNil)
531         // Confirm that memberships exist
532         groupUUID, err = RemoteGroupExists(s.cfg, "TestGroup1")
533         c.Assert(err, IsNil)
534         c.Assert(groupUUID, Not(Equals), "")
535         c.Assert(GroupMembershipExists(s.cfg.Client, activeUserUUID, groupUUID, "can_write"), Equals, true)
536 }
537
538 func (s *TestSuite) TestUsernamesCaseInsensitiveCollision(c *C) {
539         activeUserName := s.users[arvadostest.ActiveUserUUID].Username
540         activeUserUUID := s.users[arvadostest.ActiveUserUUID].UUID
541
542         nu := arvados.User{}
543         nuUsername := strings.ToUpper(activeUserName)
544         err := s.cfg.Client.RequestAndDecode(&nu, "POST", "/arvados/v1/users", nil, map[string]interface{}{
545                 "user": map[string]string{
546                         "username": nuUsername,
547                 },
548         })
549         c.Assert(err, IsNil)
550
551         // Manually remove non-fixture user because /database/reset fails otherwise
552         defer s.cfg.Client.RequestAndDecode(nil, "DELETE", "/arvados/v1/users/"+nu.UUID, nil, nil)
553
554         c.Assert(nu.Username, Equals, nuUsername)
555         c.Assert(nu.UUID, Not(Equals), activeUserUUID)
556         c.Assert(nu.Username, Not(Equals), activeUserName)
557
558         data := [][]string{
559                 {"SomeGroup", activeUserName},
560         }
561         tmpfile, err := MakeTempCSVFile(data)
562         c.Assert(err, IsNil)
563         defer os.Remove(tmpfile.Name()) // clean up
564
565         s.cfg.Path = tmpfile.Name()
566         s.cfg.UserID = "username"
567         s.cfg.CaseInsensitive = true
568         err = doMain(s.cfg)
569         // Should get an error because of "ACTIVE" and "Active" usernames
570         c.Assert(err, NotNil)
571         c.Assert(err, ErrorMatches, ".*case insensitive collision.*")
572 }