| OLD | NEW |
| 1 // Copyright 2017 The LUCI Authors. | 1 // Copyright 2017 The LUCI Authors. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 package apiservers | 15 package apiservers |
| 16 | 16 |
| 17 import ( | 17 import ( |
| 18 "fmt" | 18 "fmt" |
| 19 "testing" | 19 "testing" |
| 20 "time" | 20 "time" |
| 21 | 21 |
| 22 "google.golang.org/grpc/codes" | 22 "google.golang.org/grpc/codes" |
| 23 "google.golang.org/grpc/status" | 23 "google.golang.org/grpc/status" |
| 24 | 24 |
| 25 "golang.org/x/net/context" | 25 "golang.org/x/net/context" |
| 26 | 26 |
| 27 "github.com/golang/protobuf/proto" | 27 "github.com/golang/protobuf/proto" |
| 28 "github.com/golang/protobuf/ptypes/empty" | 28 "github.com/golang/protobuf/ptypes/empty" |
| 29 "github.com/luci/luci-go/appengine/gaetesting" | 29 "github.com/luci/luci-go/appengine/gaetesting" |
| 30 "github.com/luci/luci-go/server/auth" | |
| 31 "github.com/luci/luci-go/server/auth/authtest" | |
| 32 "github.com/luci/luci-go/server/auth/identity" | 30 "github.com/luci/luci-go/server/auth/identity" |
| 33 | 31 |
| 34 "github.com/luci/luci-go/scheduler/api/scheduler/v1" | 32 "github.com/luci/luci-go/scheduler/api/scheduler/v1" |
| 35 "github.com/luci/luci-go/scheduler/appengine/catalog" | 33 "github.com/luci/luci-go/scheduler/appengine/catalog" |
| 36 "github.com/luci/luci-go/scheduler/appengine/engine" | 34 "github.com/luci/luci-go/scheduler/appengine/engine" |
| 37 "github.com/luci/luci-go/scheduler/appengine/messages" | 35 "github.com/luci/luci-go/scheduler/appengine/messages" |
| 38 "github.com/luci/luci-go/scheduler/appengine/task" | 36 "github.com/luci/luci-go/scheduler/appengine/task" |
| 39 "github.com/luci/luci-go/scheduler/appengine/task/urlfetch" | 37 "github.com/luci/luci-go/scheduler/appengine/task/urlfetch" |
| 40 | 38 |
| 41 . "github.com/smartystreets/goconvey/convey" | 39 . "github.com/smartystreets/goconvey/convey" |
| 42 ) | 40 ) |
| 43 | 41 |
| 44 func TestGetJobsApi(t *testing.T) { | 42 func TestGetJobsApi(t *testing.T) { |
| 45 t.Parallel() | 43 t.Parallel() |
| 46 | 44 |
| 47 Convey("Scheduler GetJobs API works", t, func() { | 45 Convey("Scheduler GetJobs API works", t, func() { |
| 48 ctx := gaetesting.TestingContext() | 46 ctx := gaetesting.TestingContext() |
| 49 fakeEng, catalog := newTestEngine() | 47 fakeEng, catalog := newTestEngine() |
| 50 fakeTaskBlob, err := registerUrlFetcher(catalog) | 48 fakeTaskBlob, err := registerUrlFetcher(catalog) |
| 51 So(err, ShouldBeNil) | 49 So(err, ShouldBeNil) |
| 52 ss := SchedulerServer{fakeEng, catalog} | 50 ss := SchedulerServer{fakeEng, catalog} |
| 53 | 51 |
| 54 Convey("Empty", func() { | 52 Convey("Empty", func() { |
| 55 » » » fakeEng.getAllJobs = func() ([]*engine.Job, error) { ret
urn []*engine.Job{}, nil } | 53 » » » fakeEng.getVisibleJobs = func() ([]*engine.Job, error) {
return []*engine.Job{}, nil } |
| 56 reply, err := ss.GetJobs(ctx, nil) | 54 reply, err := ss.GetJobs(ctx, nil) |
| 57 So(err, ShouldBeNil) | 55 So(err, ShouldBeNil) |
| 58 So(len(reply.GetJobs()), ShouldEqual, 0) | 56 So(len(reply.GetJobs()), ShouldEqual, 0) |
| 59 }) | 57 }) |
| 60 | 58 |
| 61 Convey("All Projects", func() { | 59 Convey("All Projects", func() { |
| 62 » » » fakeEng.getAllJobs = func() ([]*engine.Job, error) { | 60 » » » fakeEng.getVisibleJobs = func() ([]*engine.Job, error) { |
| 63 return []*engine.Job{ | 61 return []*engine.Job{ |
| 64 { | 62 { |
| 65 JobID: "bar/foo", | 63 JobID: "bar/foo", |
| 66 ProjectID: "bar", | 64 ProjectID: "bar", |
| 67 Schedule: "0 * * * * * *", | 65 Schedule: "0 * * * * * *", |
| 68 State: engine.JobState{State
: engine.JobStateRunning}, | 66 State: engine.JobState{State
: engine.JobStateRunning}, |
| 69 Task: fakeTaskBlob, | 67 Task: fakeTaskBlob, |
| 70 }, | 68 }, |
| 71 { | 69 { |
| 72 JobID: "baz/faz", | 70 JobID: "baz/faz", |
| (...skipping 17 matching lines...) Expand all Loading... |
| 90 { | 88 { |
| 91 JobRef: &scheduler.JobRef{Job: "faz",
Project: "baz"}, | 89 JobRef: &scheduler.JobRef{Job: "faz",
Project: "baz"}, |
| 92 Schedule: "with 1m interval", | 90 Schedule: "with 1m interval", |
| 93 State: &scheduler.JobState{UiStatus:
"PAUSED"}, | 91 State: &scheduler.JobState{UiStatus:
"PAUSED"}, |
| 94 Paused: true, | 92 Paused: true, |
| 95 }, | 93 }, |
| 96 }) | 94 }) |
| 97 }) | 95 }) |
| 98 | 96 |
| 99 Convey("One Project", func() { | 97 Convey("One Project", func() { |
| 100 » » » fakeEng.getProjectJobs = func(projectID string) ([]*engi
ne.Job, error) { | 98 » » » fakeEng.getVisibleProjectJobs = func(projectID string) (
[]*engine.Job, error) { |
| 101 So(projectID, ShouldEqual, "bar") | 99 So(projectID, ShouldEqual, "bar") |
| 102 return []*engine.Job{ | 100 return []*engine.Job{ |
| 103 { | 101 { |
| 104 JobID: "bar/foo", | 102 JobID: "bar/foo", |
| 105 ProjectID: "bar", | 103 ProjectID: "bar", |
| 106 Schedule: "0 * * * * * *", | 104 Schedule: "0 * * * * * *", |
| 107 State: engine.JobState{State
: engine.JobStateRunning}, | 105 State: engine.JobState{State
: engine.JobStateRunning}, |
| 108 Task: fakeTaskBlob, | 106 Task: fakeTaskBlob, |
| 109 }, | 107 }, |
| 110 }, nil | 108 }, nil |
| 111 } | 109 } |
| 112 reply, err := ss.GetJobs(ctx, &scheduler.JobsRequest{Pro
ject: "bar"}) | 110 reply, err := ss.GetJobs(ctx, &scheduler.JobsRequest{Pro
ject: "bar"}) |
| 113 So(err, ShouldBeNil) | 111 So(err, ShouldBeNil) |
| 114 So(reply.GetJobs(), ShouldResemble, []*scheduler.Job{ | 112 So(reply.GetJobs(), ShouldResemble, []*scheduler.Job{ |
| 115 { | 113 { |
| 116 JobRef: &scheduler.JobRef{Job: "foo",
Project: "bar"}, | 114 JobRef: &scheduler.JobRef{Job: "foo",
Project: "bar"}, |
| 117 Schedule: "0 * * * * * *", | 115 Schedule: "0 * * * * * *", |
| 118 State: &scheduler.JobState{UiStatus:
"RUNNING"}, | 116 State: &scheduler.JobState{UiStatus:
"RUNNING"}, |
| 119 Paused: false, | 117 Paused: false, |
| 120 }, | 118 }, |
| 121 }) | 119 }) |
| 122 }) | 120 }) |
| 123 | 121 |
| 124 Convey("Paused but currently running job", func() { | 122 Convey("Paused but currently running job", func() { |
| 125 » » » fakeEng.getProjectJobs = func(projectID string) ([]*engi
ne.Job, error) { | 123 » » » fakeEng.getVisibleProjectJobs = func(projectID string) (
[]*engine.Job, error) { |
| 126 So(projectID, ShouldEqual, "bar") | 124 So(projectID, ShouldEqual, "bar") |
| 127 return []*engine.Job{ | 125 return []*engine.Job{ |
| 128 { | 126 { |
| 129 // Job which is paused but its l
atest invocation still running. | 127 // Job which is paused but its l
atest invocation still running. |
| 130 JobID: "bar/foo", | 128 JobID: "bar/foo", |
| 131 ProjectID: "bar", | 129 ProjectID: "bar", |
| 132 Schedule: "0 * * * * * *", | 130 Schedule: "0 * * * * * *", |
| 133 State: engine.JobState{State
: engine.JobStateRunning}, | 131 State: engine.JobState{State
: engine.JobStateRunning}, |
| 134 Paused: true, | 132 Paused: true, |
| 135 Task: fakeTaskBlob, | 133 Task: fakeTaskBlob, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 154 t.Parallel() | 152 t.Parallel() |
| 155 | 153 |
| 156 Convey("Scheduler GetInvocations API works", t, func() { | 154 Convey("Scheduler GetInvocations API works", t, func() { |
| 157 ctx := gaetesting.TestingContext() | 155 ctx := gaetesting.TestingContext() |
| 158 fakeEng, catalog := newTestEngine() | 156 fakeEng, catalog := newTestEngine() |
| 159 _, err := registerUrlFetcher(catalog) | 157 _, err := registerUrlFetcher(catalog) |
| 160 So(err, ShouldBeNil) | 158 So(err, ShouldBeNil) |
| 161 ss := SchedulerServer{fakeEng, catalog} | 159 ss := SchedulerServer{fakeEng, catalog} |
| 162 | 160 |
| 163 Convey("Job not found", func() { | 161 Convey("Job not found", func() { |
| 164 » » » fakeEng.getJob = func(JobID string) (*engine.Job, error)
{ return nil, nil } | 162 » » » fakeEng.getVisibleJob = func(JobID string) (*engine.Job,
error) { return nil, nil } |
| 165 _, err := ss.GetInvocations(ctx, &scheduler.InvocationsR
equest{ | 163 _, err := ss.GetInvocations(ctx, &scheduler.InvocationsR
equest{ |
| 166 JobRef: &scheduler.JobRef{Project: "not", Job: "
exists"}, | 164 JobRef: &scheduler.JobRef{Project: "not", Job: "
exists"}, |
| 167 }) | 165 }) |
| 168 s, ok := status.FromError(err) | 166 s, ok := status.FromError(err) |
| 169 So(ok, ShouldBeTrue) | 167 So(ok, ShouldBeTrue) |
| 170 So(s.Code(), ShouldEqual, codes.NotFound) | 168 So(s.Code(), ShouldEqual, codes.NotFound) |
| 171 }) | 169 }) |
| 172 | 170 |
| 173 Convey("DS error", func() { | 171 Convey("DS error", func() { |
| 174 » » » fakeEng.getJob = func(JobID string) (*engine.Job, error)
{ return nil, fmt.Errorf("ds error") } | 172 » » » fakeEng.getVisibleJob = func(JobID string) (*engine.Job,
error) { return nil, fmt.Errorf("ds error") } |
| 175 _, err := ss.GetInvocations(ctx, &scheduler.InvocationsR
equest{ | 173 _, err := ss.GetInvocations(ctx, &scheduler.InvocationsR
equest{ |
| 176 JobRef: &scheduler.JobRef{Project: "proj", Job:
"job"}, | 174 JobRef: &scheduler.JobRef{Project: "proj", Job:
"job"}, |
| 177 }) | 175 }) |
| 178 s, ok := status.FromError(err) | 176 s, ok := status.FromError(err) |
| 179 So(ok, ShouldBeTrue) | 177 So(ok, ShouldBeTrue) |
| 180 So(s.Code(), ShouldEqual, codes.Internal) | 178 So(s.Code(), ShouldEqual, codes.Internal) |
| 181 }) | 179 }) |
| 182 | 180 |
| 183 » » fakeEng.getJob = func(JobID string) (*engine.Job, error) { | 181 » » fakeEng.getVisibleJob = func(JobID string) (*engine.Job, error)
{ |
| 184 return &engine.Job{JobID: "proj/job", ProjectID: "proj"}
, nil | 182 return &engine.Job{JobID: "proj/job", ProjectID: "proj"}
, nil |
| 185 } | 183 } |
| 186 | 184 |
| 187 Convey("Emtpy with huge pagesize", func() { | 185 Convey("Emtpy with huge pagesize", func() { |
| 188 » » » fakeEng.listInvocations = func(pageSize int, cursor stri
ng) ([]*engine.Invocation, string, error) { | 186 » » » fakeEng.listVisibleInvocations = func(pageSize int, curs
or string) ([]*engine.Invocation, string, error) { |
| 189 So(pageSize, ShouldEqual, 50) | 187 So(pageSize, ShouldEqual, 50) |
| 190 So(cursor, ShouldEqual, "") | 188 So(cursor, ShouldEqual, "") |
| 191 return nil, "", nil | 189 return nil, "", nil |
| 192 } | 190 } |
| 193 r, err := ss.GetInvocations(ctx, &scheduler.InvocationsR
equest{ | 191 r, err := ss.GetInvocations(ctx, &scheduler.InvocationsR
equest{ |
| 194 JobRef: &scheduler.JobRef{Project: "proj", Job
: "job"}, | 192 JobRef: &scheduler.JobRef{Project: "proj", Job
: "job"}, |
| 195 PageSize: 1e9, | 193 PageSize: 1e9, |
| 196 }) | 194 }) |
| 197 So(err, ShouldBeNil) | 195 So(err, ShouldBeNil) |
| 198 So(r.GetNextCursor(), ShouldEqual, "") | 196 So(r.GetNextCursor(), ShouldEqual, "") |
| 199 So(r.GetInvocations(), ShouldBeEmpty) | 197 So(r.GetInvocations(), ShouldBeEmpty) |
| 200 }) | 198 }) |
| 201 | 199 |
| 202 Convey("Some with custom pagesize and cursor", func() { | 200 Convey("Some with custom pagesize and cursor", func() { |
| 203 started := time.Unix(123123123, 0).UTC() | 201 started := time.Unix(123123123, 0).UTC() |
| 204 finished := time.Unix(321321321, 0).UTC() | 202 finished := time.Unix(321321321, 0).UTC() |
| 205 » » » fakeEng.listInvocations = func(pageSize int, cursor stri
ng) ([]*engine.Invocation, string, error) { | 203 » » » fakeEng.listVisibleInvocations = func(pageSize int, curs
or string) ([]*engine.Invocation, string, error) { |
| 206 So(pageSize, ShouldEqual, 5) | 204 So(pageSize, ShouldEqual, 5) |
| 207 So(cursor, ShouldEqual, "cursor") | 205 So(cursor, ShouldEqual, "cursor") |
| 208 return []*engine.Invocation{ | 206 return []*engine.Invocation{ |
| 209 {ID: 12, Revision: "deadbeef", Status: t
ask.StatusRunning, Started: started, | 207 {ID: 12, Revision: "deadbeef", Status: t
ask.StatusRunning, Started: started, |
| 210 TriggeredBy: identity.Identity("
user:bot@example.com")}, | 208 TriggeredBy: identity.Identity("
user:bot@example.com")}, |
| 211 {ID: 13, Revision: "deadbeef", Status: t
ask.StatusAborted, Started: started, Finished: finished, | 209 {ID: 13, Revision: "deadbeef", Status: t
ask.StatusAborted, Started: started, Finished: finished, |
| 212 ViewURL: "https://example.com/13
"}, | 210 ViewURL: "https://example.com/13
"}, |
| 213 }, "next", nil | 211 }, "next", nil |
| 214 } | 212 } |
| 215 r, err := ss.GetInvocations(ctx, &scheduler.InvocationsR
equest{ | 213 r, err := ss.GetInvocations(ctx, &scheduler.InvocationsR
equest{ |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 | 248 |
| 251 func TestJobActionsApi(t *testing.T) { | 249 func TestJobActionsApi(t *testing.T) { |
| 252 t.Parallel() | 250 t.Parallel() |
| 253 | 251 |
| 254 Convey("works", t, func() { | 252 Convey("works", t, func() { |
| 255 ctx := gaetesting.TestingContext() | 253 ctx := gaetesting.TestingContext() |
| 256 fakeEng, catalog := newTestEngine() | 254 fakeEng, catalog := newTestEngine() |
| 257 ss := SchedulerServer{fakeEng, catalog} | 255 ss := SchedulerServer{fakeEng, catalog} |
| 258 | 256 |
| 259 Convey("PermissionDenied", func() { | 257 Convey("PermissionDenied", func() { |
| 260 » » » ctx = auth.WithState(ctx, &authtest.FakeState{ | 258 » » » onAction := func(jobID string) error { |
| 261 » » » » Identity: "user:dog@example.com", | 259 » » » » return engine.ErrNoOwnerPermission |
| 262 » » » » IdentityGroups: []string{"dogs"}, | 260 » » » } |
| 263 » » » }) | |
| 264 | |
| 265 Convey("Pause", func() { | 261 Convey("Pause", func() { |
| 262 fakeEng.pauseJob = onAction |
| 266 _, err := ss.PauseJob(ctx, &scheduler.JobRef{Pro
ject: "proj", Job: "job"}) | 263 _, err := ss.PauseJob(ctx, &scheduler.JobRef{Pro
ject: "proj", Job: "job"}) |
| 267 s, ok := status.FromError(err) | 264 s, ok := status.FromError(err) |
| 268 So(ok, ShouldBeTrue) | 265 So(ok, ShouldBeTrue) |
| 269 So(s.Code(), ShouldEqual, codes.PermissionDenied
) | 266 So(s.Code(), ShouldEqual, codes.PermissionDenied
) |
| 270 }) | 267 }) |
| 271 | 268 |
| 272 Convey("Abort", func() { | 269 Convey("Abort", func() { |
| 270 fakeEng.abortJob = onAction |
| 273 _, err := ss.AbortJob(ctx, &scheduler.JobRef{Pro
ject: "proj", Job: "job"}) | 271 _, err := ss.AbortJob(ctx, &scheduler.JobRef{Pro
ject: "proj", Job: "job"}) |
| 274 s, ok := status.FromError(err) | 272 s, ok := status.FromError(err) |
| 275 So(ok, ShouldBeTrue) | 273 So(ok, ShouldBeTrue) |
| 276 So(s.Code(), ShouldEqual, codes.PermissionDenied
) | 274 So(s.Code(), ShouldEqual, codes.PermissionDenied
) |
| 277 }) | 275 }) |
| 278 }) | 276 }) |
| 279 | 277 |
| 280 ctx = auth.WithState(ctx, &authtest.FakeState{ | |
| 281 Identity: "user:admin@example.com", | |
| 282 IdentityGroups: []string{"administrators"}, | |
| 283 }) | |
| 284 | |
| 285 Convey("OK", func() { | 278 Convey("OK", func() { |
| 286 » » » onAction := func(jobID string, who identity.Identity) er
ror { | 279 » » » onAction := func(jobID string) error { |
| 287 So(jobID, ShouldEqual, "proj/job") | 280 So(jobID, ShouldEqual, "proj/job") |
| 288 So(who.Email(), ShouldEqual, "admin@example.com"
) | |
| 289 return nil | 281 return nil |
| 290 } | 282 } |
| 291 | 283 |
| 292 Convey("Pause", func() { | 284 Convey("Pause", func() { |
| 293 fakeEng.pauseJob = onAction | 285 fakeEng.pauseJob = onAction |
| 294 r, err := ss.PauseJob(ctx, &scheduler.JobRef{Pro
ject: "proj", Job: "job"}) | 286 r, err := ss.PauseJob(ctx, &scheduler.JobRef{Pro
ject: "proj", Job: "job"}) |
| 295 So(err, ShouldBeNil) | 287 So(err, ShouldBeNil) |
| 296 So(r, ShouldResemble, &empty.Empty{}) | 288 So(r, ShouldResemble, &empty.Empty{}) |
| 297 }) | 289 }) |
| 298 | 290 |
| 299 Convey("Resume", func() { | 291 Convey("Resume", func() { |
| 300 fakeEng.resumeJob = onAction | 292 fakeEng.resumeJob = onAction |
| 301 r, err := ss.ResumeJob(ctx, &scheduler.JobRef{Pr
oject: "proj", Job: "job"}) | 293 r, err := ss.ResumeJob(ctx, &scheduler.JobRef{Pr
oject: "proj", Job: "job"}) |
| 302 So(err, ShouldBeNil) | 294 So(err, ShouldBeNil) |
| 303 So(r, ShouldResemble, &empty.Empty{}) | 295 So(r, ShouldResemble, &empty.Empty{}) |
| 304 }) | 296 }) |
| 305 | 297 |
| 306 Convey("Abort", func() { | 298 Convey("Abort", func() { |
| 307 fakeEng.abortJob = onAction | 299 fakeEng.abortJob = onAction |
| 308 r, err := ss.AbortJob(ctx, &scheduler.JobRef{Pro
ject: "proj", Job: "job"}) | 300 r, err := ss.AbortJob(ctx, &scheduler.JobRef{Pro
ject: "proj", Job: "job"}) |
| 309 So(err, ShouldBeNil) | 301 So(err, ShouldBeNil) |
| 310 So(r, ShouldResemble, &empty.Empty{}) | 302 So(r, ShouldResemble, &empty.Empty{}) |
| 311 }) | 303 }) |
| 312 }) | 304 }) |
| 313 | 305 |
| 314 Convey("NotFound", func() { | 306 Convey("NotFound", func() { |
| 315 » » » fakeEng.pauseJob = func(jobID string, who identity.Ident
ity) error { | 307 » » » fakeEng.pauseJob = func(jobID string) error { |
| 316 return engine.ErrNoSuchJob | 308 return engine.ErrNoSuchJob |
| 317 } | 309 } |
| 318 _, err := ss.PauseJob(ctx, &scheduler.JobRef{Project: "p
roj", Job: "job"}) | 310 _, err := ss.PauseJob(ctx, &scheduler.JobRef{Project: "p
roj", Job: "job"}) |
| 319 s, ok := status.FromError(err) | 311 s, ok := status.FromError(err) |
| 320 So(ok, ShouldBeTrue) | 312 So(ok, ShouldBeTrue) |
| 321 So(s.Code(), ShouldEqual, codes.NotFound) | 313 So(s.Code(), ShouldEqual, codes.NotFound) |
| 322 }) | 314 }) |
| 323 }) | 315 }) |
| 324 } | 316 } |
| 325 | 317 |
| 326 func TestAbortInvocationApi(t *testing.T) { | 318 func TestAbortInvocationApi(t *testing.T) { |
| 327 t.Parallel() | 319 t.Parallel() |
| 328 | 320 |
| 329 Convey("works", t, func() { | 321 Convey("works", t, func() { |
| 330 ctx := gaetesting.TestingContext() | 322 ctx := gaetesting.TestingContext() |
| 331 fakeEng, catalog := newTestEngine() | 323 fakeEng, catalog := newTestEngine() |
| 332 ss := SchedulerServer{fakeEng, catalog} | 324 ss := SchedulerServer{fakeEng, catalog} |
| 333 | 325 |
| 334 Convey("PermissionDenied", func() { | 326 Convey("PermissionDenied", func() { |
| 335 » » » ctx = auth.WithState(ctx, &authtest.FakeState{ | 327 » » » fakeEng.abortInvocation = func(jobID string, invID int64
) error { |
| 336 » » » » Identity: "user:dog@example.com", | 328 » » » » return engine.ErrNoOwnerPermission |
| 337 » » » » IdentityGroups: []string{"dogs"}, | 329 » » » } |
| 338 » » » }) | |
| 339 _, err := ss.AbortInvocation(ctx, &scheduler.InvocationR
ef{ | 330 _, err := ss.AbortInvocation(ctx, &scheduler.InvocationR
ef{ |
| 340 JobRef: &scheduler.JobRef{Project: "proj",
Job: "job"}, | 331 JobRef: &scheduler.JobRef{Project: "proj",
Job: "job"}, |
| 341 InvocationId: 12, | 332 InvocationId: 12, |
| 342 }) | 333 }) |
| 343 s, ok := status.FromError(err) | 334 s, ok := status.FromError(err) |
| 344 So(ok, ShouldBeTrue) | 335 So(ok, ShouldBeTrue) |
| 345 So(s.Code(), ShouldEqual, codes.PermissionDenied) | 336 So(s.Code(), ShouldEqual, codes.PermissionDenied) |
| 346 }) | 337 }) |
| 347 | 338 |
| 348 ctx = auth.WithState(ctx, &authtest.FakeState{ | |
| 349 Identity: "user:admin@example.com", | |
| 350 IdentityGroups: []string{"administrators"}, | |
| 351 }) | |
| 352 | |
| 353 Convey("OK", func() { | 339 Convey("OK", func() { |
| 354 » » » fakeEng.abortInvocation = func(jobID string, invID int64
, who identity.Identity) error { | 340 » » » fakeEng.abortInvocation = func(jobID string, invID int64
) error { |
| 355 So(jobID, ShouldEqual, "proj/job") | 341 So(jobID, ShouldEqual, "proj/job") |
| 356 So(who.Email(), ShouldEqual, "admin@example.com"
) | |
| 357 So(invID, ShouldEqual, 12) | 342 So(invID, ShouldEqual, 12) |
| 358 return nil | 343 return nil |
| 359 } | 344 } |
| 360 r, err := ss.AbortInvocation(ctx, &scheduler.InvocationR
ef{ | 345 r, err := ss.AbortInvocation(ctx, &scheduler.InvocationR
ef{ |
| 361 JobRef: &scheduler.JobRef{Project: "proj",
Job: "job"}, | 346 JobRef: &scheduler.JobRef{Project: "proj",
Job: "job"}, |
| 362 InvocationId: 12, | 347 InvocationId: 12, |
| 363 }) | 348 }) |
| 364 So(err, ShouldBeNil) | 349 So(err, ShouldBeNil) |
| 365 So(r, ShouldResemble, &empty.Empty{}) | 350 So(r, ShouldResemble, &empty.Empty{}) |
| 366 }) | 351 }) |
| 367 | 352 |
| 368 Convey("Error", func() { | 353 Convey("Error", func() { |
| 369 » » » fakeEng.abortInvocation = func(jobID string, invID int64
, who identity.Identity) error { | 354 » » » fakeEng.abortInvocation = func(jobID string, invID int64
) error { |
| 370 return engine.ErrNoSuchInvocation | 355 return engine.ErrNoSuchInvocation |
| 371 } | 356 } |
| 372 _, err := ss.AbortInvocation(ctx, &scheduler.InvocationR
ef{ | 357 _, err := ss.AbortInvocation(ctx, &scheduler.InvocationR
ef{ |
| 373 JobRef: &scheduler.JobRef{Project: "proj",
Job: "job"}, | 358 JobRef: &scheduler.JobRef{Project: "proj",
Job: "job"}, |
| 374 InvocationId: 12, | 359 InvocationId: 12, |
| 375 }) | 360 }) |
| 376 s, ok := status.FromError(err) | 361 s, ok := status.FromError(err) |
| 377 So(ok, ShouldBeTrue) | 362 So(ok, ShouldBeTrue) |
| 378 So(s.Code(), ShouldEqual, codes.NotFound) | 363 So(s.Code(), ShouldEqual, codes.NotFound) |
| 379 }) | 364 }) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 390 UrlFetch: &messages.UrlFetchTask{Url: "http://example.com/path"}
, | 375 UrlFetch: &messages.UrlFetchTask{Url: "http://example.com/path"}
, |
| 391 }) | 376 }) |
| 392 } | 377 } |
| 393 | 378 |
| 394 func newTestEngine() (*fakeEngine, catalog.Catalog) { | 379 func newTestEngine() (*fakeEngine, catalog.Catalog) { |
| 395 cat := catalog.New("scheduler.cfg") | 380 cat := catalog.New("scheduler.cfg") |
| 396 return &fakeEngine{}, cat | 381 return &fakeEngine{}, cat |
| 397 } | 382 } |
| 398 | 383 |
| 399 type fakeEngine struct { | 384 type fakeEngine struct { |
| 400 » getAllJobs func() ([]*engine.Job, error) | 385 » getVisibleJobs func() ([]*engine.Job, error) |
| 401 » getProjectJobs func(projectID string) ([]*engine.Job, error) | 386 » getVisibleProjectJobs func(projectID string) ([]*engine.Job, error) |
| 402 » getJob func(jobID string) (*engine.Job, error) | 387 » getVisibleJob func(jobID string) (*engine.Job, error) |
| 403 » listInvocations func(pageSize int, cursor string) ([]*engine.Invocation,
string, error) | 388 » listVisibleInvocations func(pageSize int, cursor string) ([]*engine.Invo
cation, string, error) |
| 404 | 389 |
| 405 » pauseJob func(jobID string, who identity.Identity) error | 390 » pauseJob func(jobID string) error |
| 406 » resumeJob func(jobID string, who identity.Identity) error | 391 » resumeJob func(jobID string) error |
| 407 » abortJob func(jobID string, who identity.Identity) error | 392 » abortJob func(jobID string) error |
| 408 » abortInvocation func(jobID string, invID int64, who identity.Identity) e
rror | 393 » abortInvocation func(jobID string, invID int64) error |
| 409 } | 394 } |
| 410 | 395 |
| 411 func (f *fakeEngine) GetAllProjects(c context.Context) ([]string, error) { | 396 func (f *fakeEngine) GetVisibleJobs(c context.Context) ([]*engine.Job, error) { |
| 397 » return f.getVisibleJobs() |
| 398 } |
| 399 |
| 400 func (f *fakeEngine) GetVisibleProjectJobs(c context.Context, projectID string)
([]*engine.Job, error) { |
| 401 » return f.getVisibleProjectJobs(projectID) |
| 402 } |
| 403 |
| 404 func (f *fakeEngine) GetVisibleJob(c context.Context, jobID string) (*engine.Job
, error) { |
| 405 » return f.getVisibleJob(jobID) |
| 406 } |
| 407 |
| 408 func (f *fakeEngine) ListVisibleInvocations(c context.Context, jobID string, pag
eSize int, cursor string) ([]*engine.Invocation, string, error) { |
| 409 » return f.listVisibleInvocations(pageSize, cursor) |
| 410 } |
| 411 |
| 412 func (f *fakeEngine) PauseJob(c context.Context, jobID string) error { |
| 413 » return f.pauseJob(jobID) |
| 414 } |
| 415 |
| 416 func (f *fakeEngine) ResumeJob(c context.Context, jobID string) error { |
| 417 » return f.resumeJob(jobID) |
| 418 } |
| 419 |
| 420 func (f *fakeEngine) AbortInvocation(c context.Context, jobID string, invID int6
4) error { |
| 421 » return f.abortInvocation(jobID, invID) |
| 422 } |
| 423 |
| 424 func (f *fakeEngine) AbortJob(c context.Context, jobID string) error { |
| 425 » return f.abortJob(jobID) |
| 426 } |
| 427 |
| 428 func (f *fakeEngine) GetVisibleInvocation(c context.Context, jobID string, invID
int64) (*engine.Invocation, error) { |
| 412 panic("not implemented") | 429 panic("not implemented") |
| 413 } | 430 } |
| 414 | 431 |
| 415 func (f *fakeEngine) GetAllJobs(c context.Context) ([]*engine.Job, error) { | 432 func (f *fakeEngine) GetVisibleInvocationsByNonce(c context.Context, invNonce in
t64) ([]*engine.Invocation, error) { |
| 416 » return f.getAllJobs() | |
| 417 } | |
| 418 | |
| 419 func (f *fakeEngine) GetProjectJobs(c context.Context, projectID string) ([]*eng
ine.Job, error) { | |
| 420 » return f.getProjectJobs(projectID) | |
| 421 } | |
| 422 | |
| 423 func (f *fakeEngine) GetJob(c context.Context, jobID string) (*engine.Job, error
) { | |
| 424 » return f.getJob(jobID) | |
| 425 } | |
| 426 | |
| 427 func (f *fakeEngine) ListInvocations(c context.Context, jobID string, pageSize i
nt, cursor string) ([]*engine.Invocation, string, error) { | |
| 428 » return f.listInvocations(pageSize, cursor) | |
| 429 } | |
| 430 | |
| 431 func (f *fakeEngine) GetInvocation(c context.Context, jobID string, invID int64)
(*engine.Invocation, error) { | |
| 432 panic("not implemented") | 433 panic("not implemented") |
| 433 } | 434 } |
| 434 | 435 |
| 435 func (f *fakeEngine) GetInvocationsByNonce(c context.Context, invNonce int64) ([
]*engine.Invocation, error) { | 436 func (f *fakeEngine) TriggerInvocation(c context.Context, jobID string) (int64,
error) { |
| 436 panic("not implemented") | 437 panic("not implemented") |
| 437 } | 438 } |
| 438 | 439 |
| 439 func (f *fakeEngine) UpdateProjectJobs(c context.Context, projectID string, defs
[]catalog.Definition) error { | 440 func (f *fakeEngine) InternalAPI() engine.EngineInternal { |
| 440 panic("not implemented") | 441 panic("not implemented") |
| 441 } | 442 } |
| 442 | |
| 443 func (f *fakeEngine) ResetAllJobsOnDevServer(c context.Context) error { | |
| 444 panic("not implemented") | |
| 445 } | |
| 446 | |
| 447 func (f *fakeEngine) ExecuteSerializedAction(c context.Context, body []byte, ret
ryCount int) error { | |
| 448 panic("not implemented") | |
| 449 } | |
| 450 | |
| 451 func (f *fakeEngine) ProcessPubSubPush(c context.Context, body []byte) error { | |
| 452 panic("not implemented") | |
| 453 } | |
| 454 | |
| 455 func (f *fakeEngine) PullPubSubOnDevServer(c context.Context, taskManagerName st
ring, publisher string) error { | |
| 456 panic("not implemented") | |
| 457 } | |
| 458 | |
| 459 func (f *fakeEngine) TriggerInvocation(c context.Context, jobID string, triggere
dBy identity.Identity) (int64, error) { | |
| 460 panic("not implemented") | |
| 461 } | |
| 462 | |
| 463 func (f *fakeEngine) PauseJob(c context.Context, jobID string, who identity.Iden
tity) error { | |
| 464 return f.pauseJob(jobID, who) | |
| 465 } | |
| 466 | |
| 467 func (f *fakeEngine) ResumeJob(c context.Context, jobID string, who identity.Ide
ntity) error { | |
| 468 return f.resumeJob(jobID, who) | |
| 469 } | |
| 470 | |
| 471 func (f *fakeEngine) AbortInvocation(c context.Context, jobID string, invID int6
4, who identity.Identity) error { | |
| 472 return f.abortInvocation(jobID, invID, who) | |
| 473 } | |
| 474 | |
| 475 func (f *fakeEngine) AbortJob(c context.Context, jobID string, who identity.Iden
tity) error { | |
| 476 return f.abortJob(jobID, who) | |
| 477 } | |
| OLD | NEW |