1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
10 "git.arvados.org/arvados.git/lib/config"
11 "git.arvados.org/arvados.git/lib/controller/rpc"
12 "git.arvados.org/arvados.git/sdk/go/arvados"
13 "git.arvados.org/arvados.git/sdk/go/arvadostest"
14 "git.arvados.org/arvados.git/sdk/go/auth"
15 "git.arvados.org/arvados.git/sdk/go/ctxlog"
16 check "gopkg.in/check.v1"
19 var _ = check.Suite(&GroupSuite{})
21 type GroupSuite struct {
22 cluster *arvados.Cluster
24 railsSpy *arvadostest.Proxy
27 func (s *GroupSuite) SetUpSuite(c *check.C) {
28 cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
29 c.Assert(err, check.IsNil)
30 s.cluster, err = cfg.GetCluster("")
31 c.Assert(err, check.IsNil)
32 s.localdb = NewConn(s.cluster)
33 s.railsSpy = arvadostest.NewProxy(c, s.cluster.Services.RailsAPI)
34 *s.localdb.railsProxy = *rpc.NewConn(s.cluster.ClusterID, s.railsSpy.URL, true, rpc.PassthroughTokenProvider)
37 func (s *GroupSuite) TearDownSuite(c *check.C) {
39 // Undo any changes/additions to the user database so they
40 // don't affect subsequent tests.
41 arvadostest.ResetEnv()
42 c.Check(arvados.NewClientFromEnv().RequestAndDecode(nil, "POST", "database/reset", nil, nil), check.IsNil)
45 func (s *GroupSuite) setUpVocabulary(c *check.C, testVocabulary string) {
46 if testVocabulary == "" {
52 "labels": [{"label": "Importance"}, {"label": "Priority"}],
54 "IDVALIMPORTANCES1": { "labels": [{"label": "Critical"}, {"label": "Urgent"}, {"label": "High"}] },
55 "IDVALIMPORTANCES2": { "labels": [{"label": "Normal"}, {"label": "Moderate"}] },
56 "IDVALIMPORTANCES3": { "labels": [{"label": "Low"}] }
62 voc, err := arvados.NewVocabulary([]byte(testVocabulary), []string{})
63 c.Assert(err, check.IsNil)
64 s.localdb.vocabularyCache = voc
65 s.cluster.API.VocabularyPath = "foo"
68 func (s *GroupSuite) TestGroupCreateWithProperties(c *check.C) {
69 s.setUpVocabulary(c, "")
70 ctx := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.ActiveTokenV2}})
74 props map[string]interface{}
77 {"Invalid prop key", map[string]interface{}{"Priority": "IDVALIMPORTANCES1"}, false},
78 {"Invalid prop value", map[string]interface{}{"IDTAGIMPORTANCES": "high"}, false},
79 {"Valid prop key & value", map[string]interface{}{"IDTAGIMPORTANCES": "IDVALIMPORTANCES1"}, true},
80 {"Empty properties", map[string]interface{}{}, true},
82 for _, tt := range tests {
83 c.Log(c.TestName()+" ", tt.name)
85 grp, err := s.localdb.GroupCreate(ctx, arvados.CreateOptions{
86 Select: []string{"uuid", "properties"},
87 Attrs: map[string]interface{}{
88 "group_class": "project",
89 "properties": tt.props,
92 c.Assert(err, check.IsNil)
93 c.Assert(grp.Properties, check.DeepEquals, tt.props)
95 c.Assert(err, check.NotNil)
100 func (s *GroupSuite) TestGroupUpdateWithProperties(c *check.C) {
101 s.setUpVocabulary(c, "")
102 ctx := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.ActiveTokenV2}})
106 props map[string]interface{}
109 {"Invalid prop key", map[string]interface{}{"Priority": "IDVALIMPORTANCES1"}, false},
110 {"Invalid prop value", map[string]interface{}{"IDTAGIMPORTANCES": "high"}, false},
111 {"Valid prop key & value", map[string]interface{}{"IDTAGIMPORTANCES": "IDVALIMPORTANCES1"}, true},
112 {"Empty properties", map[string]interface{}{}, true},
114 for _, tt := range tests {
115 c.Log(c.TestName()+" ", tt.name)
116 grp, err := s.localdb.GroupCreate(ctx, arvados.CreateOptions{
117 Attrs: map[string]interface{}{
118 "group_class": "project",
121 c.Assert(err, check.IsNil)
122 grp, err = s.localdb.GroupUpdate(ctx, arvados.UpdateOptions{
124 Select: []string{"uuid", "properties"},
125 Attrs: map[string]interface{}{
126 "properties": tt.props,
129 c.Assert(err, check.IsNil)
130 c.Assert(grp.Properties, check.DeepEquals, tt.props)
132 c.Assert(err, check.NotNil)
137 func (s *GroupSuite) TestCanWriteCanManageResponses(c *check.C) {
138 ctxUser1 := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.ActiveTokenV2}})
139 ctxUser2 := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.SpectatorToken}})
140 ctxAdmin := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.AdminToken}})
141 project, err := s.localdb.GroupCreate(ctxUser1, arvados.CreateOptions{
142 Attrs: map[string]interface{}{
143 "group_class": "project",
146 c.Assert(err, check.IsNil)
147 c.Check(project.CanWrite, check.Equals, true)
148 c.Check(project.CanManage, check.Equals, true)
150 subproject, err := s.localdb.GroupCreate(ctxUser1, arvados.CreateOptions{
151 Attrs: map[string]interface{}{
152 "owner_uuid": project.UUID,
153 "group_class": "project",
156 c.Assert(err, check.IsNil)
157 c.Check(subproject.CanWrite, check.Equals, true)
158 c.Check(subproject.CanManage, check.Equals, true)
160 projlist, err := s.localdb.GroupList(ctxUser1, arvados.ListOptions{
162 Filters: []arvados.Filter{{"uuid", "in", []string{project.UUID, subproject.UUID}}},
164 c.Assert(err, check.IsNil)
165 c.Assert(projlist.Items, check.HasLen, 2)
166 for _, p := range projlist.Items {
167 c.Check(p.CanWrite, check.Equals, true)
168 c.Check(p.CanManage, check.Equals, true)
171 // Give 2nd user permission to read
172 permlink, err := s.localdb.LinkCreate(ctxAdmin, arvados.CreateOptions{
173 Attrs: map[string]interface{}{
174 "link_class": "permission",
176 "tail_uuid": arvadostest.SpectatorUserUUID,
177 "head_uuid": project.UUID,
180 c.Assert(err, check.IsNil)
182 // As 2nd user: can read, cannot manage, cannot write
183 project2, err := s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: project.UUID})
184 c.Assert(err, check.IsNil)
185 c.Check(project2.CanWrite, check.Equals, false)
186 c.Check(project2.CanManage, check.Equals, false)
188 _, err = s.localdb.LinkUpdate(ctxAdmin, arvados.UpdateOptions{
190 Attrs: map[string]interface{}{
194 c.Assert(err, check.IsNil)
196 // As 2nd user: cannot manage, can write
197 project2, err = s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: project.UUID})
198 c.Assert(err, check.IsNil)
199 c.Check(project2.CanWrite, check.Equals, true)
200 c.Check(project2.CanManage, check.Equals, false)
202 // As owner: after freezing, can manage (owner), cannot write (frozen)
203 project, err = s.localdb.GroupUpdate(ctxUser1, arvados.UpdateOptions{
205 Attrs: map[string]interface{}{
206 "frozen_by_uuid": arvadostest.ActiveUserUUID,
208 c.Assert(err, check.IsNil)
209 c.Check(project.CanWrite, check.Equals, false)
210 c.Check(project.CanManage, check.Equals, true)
212 // As admin: can manage (admin), cannot write (frozen)
213 project, err = s.localdb.GroupGet(ctxAdmin, arvados.GetOptions{UUID: project.UUID})
214 c.Assert(err, check.IsNil)
215 c.Check(project.CanWrite, check.Equals, false)
216 c.Check(project.CanManage, check.Equals, true)
218 // As 2nd user: cannot manage (perm), cannot write (frozen)
219 project2, err = s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: project.UUID})
220 c.Assert(err, check.IsNil)
221 c.Check(project2.CanWrite, check.Equals, false)
222 c.Check(project2.CanManage, check.Equals, false)
224 // After upgrading perm to "manage", as 2nd user: can manage (perm), cannot write (frozen)
225 _, err = s.localdb.LinkUpdate(ctxAdmin, arvados.UpdateOptions{
227 Attrs: map[string]interface{}{
228 "name": "can_manage",
231 c.Assert(err, check.IsNil)
232 project2, err = s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: project.UUID})
233 c.Assert(err, check.IsNil)
234 c.Check(project2.CanWrite, check.Equals, false)
235 c.Check(project2.CanManage, check.Equals, true)
237 // 2nd user can also manage (but not write) the subject inside the frozen project
238 subproject2, err := s.localdb.GroupGet(ctxUser2, arvados.GetOptions{UUID: subproject.UUID})
239 c.Assert(err, check.IsNil)
240 c.Check(subproject2.CanWrite, check.Equals, false)
241 c.Check(subproject2.CanManage, check.Equals, true)
243 u, err := s.localdb.UserGet(ctxUser1, arvados.GetOptions{
244 UUID: arvadostest.ActiveUserUUID,
246 c.Assert(err, check.IsNil)
247 c.Check(u.CanWrite, check.Equals, true)
248 c.Check(u.CanManage, check.Equals, true)
250 for _, selectParam := range [][]string{
252 {"can_write", "can_manage"},
254 c.Logf("selectParam: %+v", selectParam)
255 ulist, err := s.localdb.UserList(ctxUser1, arvados.ListOptions{
257 Filters: []arvados.Filter{{"uuid", "=", arvadostest.ActiveUserUUID}},
260 c.Assert(err, check.IsNil)
261 c.Assert(ulist.Items, check.HasLen, 1)
262 c.Logf("%+v", ulist.Items)
263 for _, u := range ulist.Items {
264 c.Check(u.CanWrite, check.Equals, true)
265 c.Check(u.CanManage, check.Equals, true)