Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: scheduler/appengine/apiservers/scheduler_test.go

Issue 2948163002: scheduler: add GetJobInvocations api. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The LUCI Authors. All rights reserved. 1 // Copyright 2017 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package apiservers 5 package apiservers
6 6
7 import ( 7 import (
8 "fmt"
8 "testing" 9 "testing"
10 "time"
11
12 "google.golang.org/grpc/codes"
13 "google.golang.org/grpc/status"
9 14
10 "golang.org/x/net/context" 15 "golang.org/x/net/context"
11 16
12 "github.com/golang/protobuf/proto" 17 "github.com/golang/protobuf/proto"
13 "github.com/luci/luci-go/appengine/gaetesting" 18 "github.com/luci/luci-go/appengine/gaetesting"
19 "github.com/luci/luci-go/common/clock"
20 "github.com/luci/luci-go/common/clock/testclock"
14 "github.com/luci/luci-go/server/auth/identity" 21 "github.com/luci/luci-go/server/auth/identity"
15 22
16 scheduler "github.com/luci/luci-go/scheduler/api/scheduler/v1" 23 scheduler "github.com/luci/luci-go/scheduler/api/scheduler/v1"
17 "github.com/luci/luci-go/scheduler/appengine/catalog" 24 "github.com/luci/luci-go/scheduler/appengine/catalog"
18 "github.com/luci/luci-go/scheduler/appengine/engine" 25 "github.com/luci/luci-go/scheduler/appengine/engine"
19 "github.com/luci/luci-go/scheduler/appengine/messages" 26 "github.com/luci/luci-go/scheduler/appengine/messages"
27 "github.com/luci/luci-go/scheduler/appengine/task"
20 "github.com/luci/luci-go/scheduler/appengine/task/urlfetch" 28 "github.com/luci/luci-go/scheduler/appengine/task/urlfetch"
21 29
22 . "github.com/smartystreets/goconvey/convey" 30 . "github.com/smartystreets/goconvey/convey"
23 ) 31 )
24 32
25 func TestGetJobsApi(t *testing.T) { 33 func TestGetJobsApi(t *testing.T) {
26 t.Parallel() 34 t.Parallel()
27 35
28 Convey("Scheduler GetJobs API works", t, func() { 36 Convey("Scheduler GetJobs API works", t, func() {
29 ctx := gaetesting.TestingContext() 37 ctx := gaetesting.TestingContext()
30 fakeEng, catalog := newTestEngine() 38 fakeEng, catalog := newTestEngine()
31 » » So(catalog.RegisterTaskManager(&urlfetch.TaskManager{}), ShouldB eNil) 39 » » fakeTaskBlob, err := registerUrlFetcher(catalog)
32 40 » » So(err, ShouldBeNil)
33 ss := SchedulerServer{fakeEng, catalog} 41 ss := SchedulerServer{fakeEng, catalog}
34 taskBlob, err := proto.Marshal(&messages.TaskDefWrapper{
35 UrlFetch: &messages.UrlFetchTask{Url: "http://example.co m/path"},
36 })
37 So(err, ShouldBeNil)
38 42
39 Convey("Empty", func() { 43 Convey("Empty", func() {
40 fakeEng.getAllJobs = func() ([]*engine.Job, error) { ret urn []*engine.Job{}, nil } 44 fakeEng.getAllJobs = func() ([]*engine.Job, error) { ret urn []*engine.Job{}, nil }
41 reply, err := ss.GetJobs(ctx, nil) 45 reply, err := ss.GetJobs(ctx, nil)
42 So(err, ShouldBeNil) 46 So(err, ShouldBeNil)
43 So(len(reply.GetJobs()), ShouldEqual, 0) 47 So(len(reply.GetJobs()), ShouldEqual, 0)
44 }) 48 })
45 49
46 Convey("All Projects", func() { 50 Convey("All Projects", func() {
47 fakeEng.getAllJobs = func() ([]*engine.Job, error) { 51 fakeEng.getAllJobs = func() ([]*engine.Job, error) {
48 return []*engine.Job{ 52 return []*engine.Job{
49 { 53 {
50 JobID: "bar/foo", 54 JobID: "bar/foo",
51 ProjectID: "bar", 55 ProjectID: "bar",
52 Schedule: "0 * * * * * *", 56 Schedule: "0 * * * * * *",
53 State: engine.JobState{State : engine.JobStateRunning}, 57 State: engine.JobState{State : engine.JobStateRunning},
54 » » » » » » Task: taskBlob, 58 » » » » » » Task: fakeTaskBlob,
55 }, 59 },
56 { 60 {
57 JobID: "baz/faz", 61 JobID: "baz/faz",
58 Paused: true, 62 Paused: true,
59 ProjectID: "baz", 63 ProjectID: "baz",
60 Schedule: "with 1m interval", 64 Schedule: "with 1m interval",
61 State: engine.JobState{State : engine.JobStateSuspended}, 65 State: engine.JobState{State : engine.JobStateSuspended},
62 » » » » » » Task: taskBlob, 66 » » » » » » Task: fakeTaskBlob,
63 }, 67 },
64 }, nil 68 }, nil
65 } 69 }
66 reply, err := ss.GetJobs(ctx, nil) 70 reply, err := ss.GetJobs(ctx, nil)
67 So(err, ShouldBeNil) 71 So(err, ShouldBeNil)
68 So(reply.GetJobs(), ShouldResemble, []*scheduler.Job{ 72 So(reply.GetJobs(), ShouldResemble, []*scheduler.Job{
69 { 73 {
70 Name: "foo", 74 Name: "foo",
71 Project: "bar", 75 Project: "bar",
72 Schedule: "0 * * * * * *", 76 Schedule: "0 * * * * * *",
(...skipping 10 matching lines...) Expand all
83 87
84 Convey("One Project", func() { 88 Convey("One Project", func() {
85 fakeEng.getProjectJobs = func(projectID string) ([]*engi ne.Job, error) { 89 fakeEng.getProjectJobs = func(projectID string) ([]*engi ne.Job, error) {
86 So(projectID, ShouldEqual, "bar") 90 So(projectID, ShouldEqual, "bar")
87 return []*engine.Job{ 91 return []*engine.Job{
88 { 92 {
89 JobID: "bar/foo", 93 JobID: "bar/foo",
90 ProjectID: "bar", 94 ProjectID: "bar",
91 Schedule: "0 * * * * * *", 95 Schedule: "0 * * * * * *",
92 State: engine.JobState{State : engine.JobStateRunning}, 96 State: engine.JobState{State : engine.JobStateRunning},
93 » » » » » » Task: taskBlob, 97 » » » » » » Task: fakeTaskBlob,
94 }, 98 },
95 }, nil 99 }, nil
96 } 100 }
97 reply, err := ss.GetJobs(ctx, &scheduler.JobsRequest{Pro ject: "bar"}) 101 reply, err := ss.GetJobs(ctx, &scheduler.JobsRequest{Pro ject: "bar"})
98 So(err, ShouldBeNil) 102 So(err, ShouldBeNil)
99 So(reply.GetJobs(), ShouldResemble, []*scheduler.Job{ 103 So(reply.GetJobs(), ShouldResemble, []*scheduler.Job{
100 { 104 {
101 Name: "foo", 105 Name: "foo",
102 Project: "bar", 106 Project: "bar",
103 Schedule: "0 * * * * * *", 107 Schedule: "0 * * * * * *",
104 State: &scheduler.JobState{UiStatus: "RUNNING"}, 108 State: &scheduler.JobState{UiStatus: "RUNNING"},
105 }, 109 },
106 }) 110 })
107 }) 111 })
108 }) 112 })
109 } 113 }
110 114
115 func TestGetInvocationsApi(t *testing.T) {
116 t.Parallel()
117
118 Convey("Scheduler GetInvocations API works", t, func() {
119 ctx := gaetesting.TestingContext()
120 fakeNow := time.Unix(1442270520, 0).UTC()
121 ctx = clock.Set(ctx, testclock.New(fakeNow))
122 fakeEng, catalog := newTestEngine()
123 _, err := registerUrlFetcher(catalog)
124 So(err, ShouldBeNil)
125 ss := SchedulerServer{fakeEng, catalog}
126
127 Convey("Job not found", func() {
128 fakeEng.getJob = func(JobID string) (*engine.Job, error) { return nil, nil }
129 _, err := ss.GetInvocations(ctx, &scheduler.InvocationsR equest{Project: "not", Job: "exists"})
130 s, ok := status.FromError(err)
131 So(ok, ShouldBeTrue)
132 So(s.Code(), ShouldEqual, codes.NotFound)
133 })
134
135 Convey("DS error", func() {
136 fakeEng.getJob = func(JobID string) (*engine.Job, error) { return nil, fmt.Errorf("ds error") }
137 _, err := ss.GetInvocations(ctx, &scheduler.InvocationsR equest{Project: "proj", Job: "job"})
138 s, ok := status.FromError(err)
139 So(ok, ShouldBeTrue)
140 So(s.Code(), ShouldEqual, codes.Internal)
141 })
142
143 fakeEng.getJob = func(JobID string) (*engine.Job, error) {
144 return &engine.Job{JobID: "proj/job", ProjectID: "proj"} , nil
145 }
146
147 Convey("Emtpy with huge pagesize", func() {
148 fakeEng.listInvocations = func(pageSize int, cursor stri ng) ([]*engine.Invocation, string, error) {
149 So(pageSize, ShouldEqual, 50)
150 So(cursor, ShouldEqual, "")
151 return nil, "", nil
152 }
153 r, err := ss.GetInvocations(ctx, &scheduler.InvocationsR equest{Project: "proj", Job: "job", PageSize: 1e9})
154 So(err, ShouldBeNil)
155 So(r.GetNextCursor(), ShouldEqual, "")
156 So(r.GetInvocations(), ShouldBeEmpty)
157 So(r.GetNowTs(), ShouldEqual, fakeNow.UnixNano()/1000)
158 })
159
160 Convey("Some with custom pagesize and cursor", func() {
161 earlier := fakeNow.Add(-10 * time.Second)
162 later := fakeNow.Add(-5 * time.Second)
163 fakeEng.listInvocations = func(pageSize int, cursor stri ng) ([]*engine.Invocation, string, error) {
164 So(pageSize, ShouldEqual, 5)
165 So(cursor, ShouldEqual, "cursor")
166 return []*engine.Invocation{
167 {ID: 12, Revision: "deadbeef", Status: t ask.StatusRunning, Started: earlier,
168 TriggeredBy: identity.Identity(" user:bot@example.com")},
169 {ID: 13, Revision: "deadbeef", Status: t ask.StatusAborted, Started: earlier, Finished: later,
170 ViewURL: "https://example.com/13 "},
171 }, "next", nil
172 }
173 r, err := ss.GetInvocations(ctx, &scheduler.InvocationsR equest{
174 Project: "proj", Job: "job", PageSize: 5, Cursor : "cursor"})
175 So(err, ShouldBeNil)
176 So(r.GetNextCursor(), ShouldEqual, "next")
177 So(r.GetNowTs(), ShouldEqual, fakeNow.UnixNano()/1000)
178 So(r.GetInvocations(), ShouldResemble, []*scheduler.Invo cation{
179 {
180 Project: "proj", Job: "job", ConfigRevis ion: "deadbeef",
181 Id: 12, Final: false, Status: "RUNNING",
182 StartedTs: earlier.UnixNano() / 1000,
183 TriggeredBy: "user:bot@example.com",
184 },
185 {
186 Project: "proj", Job: "job", ConfigRevis ion: "deadbeef",
187 Id: 13, Final: true, Status: "ABORTED",
188 StartedTs: earlier.UnixNano() / 1000, Fi nishedTs: later.UnixNano() / 1000,
189 ViewUrl: "https://example.com/13",
190 },
191 })
192 })
193
194 })
195 }
196
111 //// 197 ////
112 198
199 func registerUrlFetcher(cat catalog.Catalog) ([]byte, error) {
200 if err := cat.RegisterTaskManager(&urlfetch.TaskManager{}); err != nil {
201 return nil, err
202 }
203 return proto.Marshal(&messages.TaskDefWrapper{
204 UrlFetch: &messages.UrlFetchTask{Url: "http://example.com/path"} ,
205 })
206 }
207
113 func newTestEngine() (*fakeEngine, catalog.Catalog) { 208 func newTestEngine() (*fakeEngine, catalog.Catalog) {
114 cat := catalog.New("scheduler.cfg") 209 cat := catalog.New("scheduler.cfg")
115 return &fakeEngine{}, cat 210 return &fakeEngine{}, cat
116 } 211 }
117 212
118 type fakeEngine struct { 213 type fakeEngine struct {
119 » getAllJobs func() ([]*engine.Job, error) 214 » getAllJobs func() ([]*engine.Job, error)
120 » getProjectJobs func(projectID string) ([]*engine.Job, error) 215 » getProjectJobs func(projectID string) ([]*engine.Job, error)
216 » getJob func(jobID string) (*engine.Job, error)
217 » listInvocations func(pageSize int, cursor string) ([]*engine.Invocation, string, error)
121 } 218 }
122 219
123 func (f *fakeEngine) GetAllProjects(c context.Context) ([]string, error) { 220 func (f *fakeEngine) GetAllProjects(c context.Context) ([]string, error) {
124 panic("not implemented") 221 panic("not implemented")
125 } 222 }
126 223
127 func (f *fakeEngine) GetAllJobs(c context.Context) ([]*engine.Job, error) { 224 func (f *fakeEngine) GetAllJobs(c context.Context) ([]*engine.Job, error) {
128 return f.getAllJobs() 225 return f.getAllJobs()
129 } 226 }
130 227
131 func (f *fakeEngine) GetProjectJobs(c context.Context, projectID string) ([]*eng ine.Job, error) { 228 func (f *fakeEngine) GetProjectJobs(c context.Context, projectID string) ([]*eng ine.Job, error) {
132 return f.getProjectJobs(projectID) 229 return f.getProjectJobs(projectID)
133 } 230 }
134 231
135 func (f *fakeEngine) GetJob(c context.Context, jobID string) (*engine.Job, error ) { 232 func (f *fakeEngine) GetJob(c context.Context, jobID string) (*engine.Job, error ) {
136 » panic("not implemented") 233 » return f.getJob(jobID)
137 } 234 }
138 235
139 func (f *fakeEngine) ListInvocations(c context.Context, jobID string, pageSize i nt, cursor string) ([]*engine.Invocation, string, error) { 236 func (f *fakeEngine) ListInvocations(c context.Context, jobID string, pageSize i nt, cursor string) ([]*engine.Invocation, string, error) {
140 » panic("not implemented") 237 » return f.listInvocations(pageSize, cursor)
141 } 238 }
142 239
143 func (f *fakeEngine) GetInvocation(c context.Context, jobID string, invID int64) (*engine.Invocation, error) { 240 func (f *fakeEngine) GetInvocation(c context.Context, jobID string, invID int64) (*engine.Invocation, error) {
144 panic("not implemented") 241 panic("not implemented")
145 } 242 }
146 243
147 func (f *fakeEngine) GetInvocationsByNonce(c context.Context, invNonce int64) ([ ]*engine.Invocation, error) { 244 func (f *fakeEngine) GetInvocationsByNonce(c context.Context, invNonce int64) ([ ]*engine.Invocation, error) {
148 panic("not implemented") 245 panic("not implemented")
149 } 246 }
150 247
(...skipping 29 matching lines...) Expand all
180 panic("not implemented") 277 panic("not implemented")
181 } 278 }
182 279
183 func (f *fakeEngine) AbortInvocation(c context.Context, jobID string, invID int6 4, who identity.Identity) error { 280 func (f *fakeEngine) AbortInvocation(c context.Context, jobID string, invID int6 4, who identity.Identity) error {
184 panic("not implemented") 281 panic("not implemented")
185 } 282 }
186 283
187 func (f *fakeEngine) AbortJob(c context.Context, jobID string, who identity.Iden tity) error { 284 func (f *fakeEngine) AbortJob(c context.Context, jobID string, who identity.Iden tity) error {
188 panic("not implemented") 285 panic("not implemented")
189 } 286 }
OLDNEW
« scheduler/appengine/apiservers/scheduler.go ('K') | « scheduler/appengine/apiservers/scheduler.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698