| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 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 deps | 5 package deps |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 "testing" | 9 "testing" |
| 10 "time" | 10 "time" |
| 11 | 11 |
| 12 "github.com/luci/gae/service/datastore" | 12 "github.com/luci/gae/service/datastore" |
| 13 "github.com/luci/luci-go/appengine/cmd/dm/distributor" |
| 14 "github.com/luci/luci-go/appengine/cmd/dm/distributor/fake" |
| 13 "github.com/luci/luci-go/appengine/cmd/dm/model" | 15 "github.com/luci/luci-go/appengine/cmd/dm/model" |
| 14 "github.com/luci/luci-go/appengine/tumble" | |
| 15 dm "github.com/luci/luci-go/common/api/dm/service/v1" | 16 dm "github.com/luci/luci-go/common/api/dm/service/v1" |
| 16 "github.com/luci/luci-go/common/clock" | 17 "github.com/luci/luci-go/common/clock" |
| 17 "github.com/luci/luci-go/common/clock/testclock" | 18 "github.com/luci/luci-go/common/clock/testclock" |
| 18 google_pb "github.com/luci/luci-go/common/proto/google" | 19 google_pb "github.com/luci/luci-go/common/proto/google" |
| 19 . "github.com/smartystreets/goconvey/convey" | 20 . "github.com/smartystreets/goconvey/convey" |
| 20 "golang.org/x/net/context" | 21 "golang.org/x/net/context" |
| 21 ) | 22 ) |
| 22 | 23 |
| 23 type breakFwdDepLoads struct { | 24 type breakFwdDepLoads struct { |
| 24 datastore.RawInterface | 25 datastore.RawInterface |
| 25 } | 26 } |
| 26 | 27 |
| 27 func (b breakFwdDepLoads) GetMulti(keys []*datastore.Key, mg datastore.MultiMeta
Getter, cb datastore.GetMultiCB) error { | 28 func (b breakFwdDepLoads) GetMulti(keys []*datastore.Key, mg datastore.MultiMeta
Getter, cb datastore.GetMultiCB) error { |
| 28 for _, k := range keys { | 29 for _, k := range keys { |
| 29 if k.Kind() == "FwdDep" { | 30 if k.Kind() == "FwdDep" { |
| 30 return fmt.Errorf("Loading FwdDeps is currently broken") | 31 return fmt.Errorf("Loading FwdDeps is currently broken") |
| 31 } | 32 } |
| 32 } | 33 } |
| 33 return b.RawInterface.GetMulti(keys, mg, cb) | 34 return b.RawInterface.GetMulti(keys, mg, cb) |
| 34 } | 35 } |
| 35 | 36 |
| 36 func TestWalkGraph(t *testing.T) { | 37 func TestWalkGraph(t *testing.T) { |
| 37 t.Parallel() | 38 t.Parallel() |
| 38 | 39 |
| 39 Convey("WalkGraph", t, func() { | 40 Convey("WalkGraph", t, func() { |
| 40 » » ttest := &tumble.Testing{} | 41 » » ttest, c, dist, s := testSetup() |
| 41 » » c := ttest.Context() | |
| 42 | 42 |
| 43 ds := datastore.Get(c) | 43 ds := datastore.Get(c) |
| 44 s := newDecoratedDeps() | |
| 45 | 44 |
| 46 req := &dm.WalkGraphReq{ | 45 req := &dm.WalkGraphReq{ |
| 47 Query: dm.AttemptListQueryL(map[string][]uint32{"quest":
{1}}), | 46 Query: dm.AttemptListQueryL(map[string][]uint32{"quest":
{1}}), |
| 48 Limit: &dm.WalkGraphReq_Limit{MaxDepth: 1}, | 47 Limit: &dm.WalkGraphReq_Limit{MaxDepth: 1}, |
| 49 } | 48 } |
| 50 So(req.Normalize(), ShouldBeNil) | 49 So(req.Normalize(), ShouldBeNil) |
| 51 | 50 |
| 52 Convey("no attempt", func() { | 51 Convey("no attempt", func() { |
| 53 » » » So(req, WalkShouldReturn(c), &dm.GraphData{ | 52 » » » So(req, fake.WalkShouldReturn(c, s), &dm.GraphData{ |
| 54 Quests: map[string]*dm.Quest{"quest": { | 53 Quests: map[string]*dm.Quest{"quest": { |
| 55 Attempts: map[uint32]*dm.Attempt{ | 54 Attempts: map[uint32]*dm.Attempt{ |
| 56 1: {DNE: true}, | 55 1: {DNE: true}, |
| 57 }, | 56 }, |
| 58 }}, | 57 }}, |
| 59 }) | 58 }) |
| 60 }) | 59 }) |
| 61 | 60 |
| 62 Convey("good", func() { | 61 Convey("good", func() { |
| 63 ds.Testable().Consistent(true) | 62 ds.Testable().Consistent(true) |
| 64 | 63 |
| 65 » » » wDesc := &dm.Quest_Desc{ | 64 » » » wDesc := fake.QuestDesc("w") |
| 66 » » » » DistributorConfigName: "foof", | 65 » » » w := s.ensureQuest(c, "w", 1) |
| 67 » » » » JsonPayload: `{"name":"w"}`, | |
| 68 » » » } | |
| 69 » » » w := ensureQuest(c, "w", 1) | |
| 70 ttest.Drain(c) | 66 ttest.Drain(c) |
| 71 aid := dm.NewAttemptID(w, 1) | |
| 72 | 67 |
| 73 req.Query.AttemptList = dm.NewAttemptList( | 68 req.Query.AttemptList = dm.NewAttemptList( |
| 74 map[string][]uint32{w: {1}}) | 69 map[string][]uint32{w: {1}}) |
| 75 | 70 |
| 76 Convey("include nothing", func() { | 71 Convey("include nothing", func() { |
| 77 » » » » So(req, WalkShouldReturn(c), &dm.GraphData{ | 72 » » » » So(req, fake.WalkShouldReturn(c, s), &dm.GraphDa
ta{ |
| 78 Quests: map[string]*dm.Quest{ | 73 Quests: map[string]*dm.Quest{ |
| 79 w: { | 74 w: { |
| 80 Attempts: map[uint32]*dm
.Attempt{1: {}}, | 75 Attempts: map[uint32]*dm
.Attempt{1: {}}, |
| 81 }, | 76 }, |
| 82 }, | 77 }, |
| 83 }) | 78 }) |
| 84 }) | 79 }) |
| 85 | 80 |
| 86 Convey("quest dne", func() { | 81 Convey("quest dne", func() { |
| 87 req.Include.QuestData = true | 82 req.Include.QuestData = true |
| 88 req.Limit.MaxDepth = 1 | 83 req.Limit.MaxDepth = 1 |
| 89 req.Query.AttemptList = dm.NewAttemptList( | 84 req.Query.AttemptList = dm.NewAttemptList( |
| 90 map[string][]uint32{"noex": {1}}) | 85 map[string][]uint32{"noex": {1}}) |
| 91 » » » » So(req, WalkShouldReturn(c), &dm.GraphData{ | 86 » » » » So(req, fake.WalkShouldReturn(c, s), &dm.GraphDa
ta{ |
| 92 Quests: map[string]*dm.Quest{ | 87 Quests: map[string]*dm.Quest{ |
| 93 "noex": { | 88 "noex": { |
| 94 DNE: true, | 89 DNE: true, |
| 95 Attempts: map[uint32]*dm
.Attempt{1: {DNE: true}}, | 90 Attempts: map[uint32]*dm
.Attempt{1: {DNE: true}}, |
| 96 }, | 91 }, |
| 97 }, | 92 }, |
| 98 }) | 93 }) |
| 99 }) | 94 }) |
| 100 | 95 |
| 101 Convey("no dependencies", func() { | 96 Convey("no dependencies", func() { |
| 102 req.Include.AttemptData = true | 97 req.Include.AttemptData = true |
| 103 req.Include.QuestData = true | 98 req.Include.QuestData = true |
| 104 req.Include.NumExecutions = 128 | 99 req.Include.NumExecutions = 128 |
| 105 | 100 » » » » tok := string(fake.MkToken(dm.NewExecutionID(w,
1, 1))) |
| 106 » » » » So(req, WalkShouldReturn(c), &dm.GraphData{ | 101 » » » » aExpect := dm.NewAttemptExecuting(1) |
| 102 » » » » aExpect.Executions = map[uint32]*dm.Execution{1:
dm.NewExecutionScheduling()} |
| 103 » » » » aExpect.Executions[1].Data.DistributorInfo = &dm
.Execution_Data_DistributorInfo{ |
| 104 » » » » » ConfigName: "fakeDistributor", |
| 105 » » » » » ConfigVersion: "testing", |
| 106 » » » » » Token: tok, |
| 107 » » » » } |
| 108 » » » » So(req, fake.WalkShouldReturn(c, s), &dm.GraphDa
ta{ |
| 107 Quests: map[string]*dm.Quest{ | 109 Quests: map[string]*dm.Quest{ |
| 108 w: { | 110 w: { |
| 109 Data: &dm.Quest_Data{ | 111 Data: &dm.Quest_Data{ |
| 110 Desc: wDesc, | 112 Desc: wDesc, |
| 111 }, | 113 }, |
| 112 » » » » » » » Attempts: map[uint32]*dm
.Attempt{ | 114 » » » » » » » Attempts: map[uint32]*dm
.Attempt{1: aExpect}, |
| 113 » » » » » » » » 1: dm.NewAttempt
NeedsExecution(time.Time{}), | |
| 114 » » » » » » » }, | |
| 115 }, | 115 }, |
| 116 }, | 116 }, |
| 117 }) | 117 }) |
| 118 }) | 118 }) |
| 119 | 119 |
| 120 Convey("finished", func() { | 120 Convey("finished", func() { |
| 121 » » » » _, err := s.FinishAttempt(c, &dm.FinishAttemptRe
q{ | 121 » » » » wEx := dm.NewExecutionID(w, 1, 1) |
| 122 » » » » » Auth: activate(c, execute(c, aid))
, | 122 » » » » dist.RunTask(c, wEx, func(tsk *fake.Task) error
{ |
| 123 » » » » » JsonResult: `{"data": ["very", "yes"]}`, | 123 » » » » » tsk.MustActivate(c, s).Finish( |
| 124 » » » » » Expiration: google_pb.NewTimestamp(clock
.Now(c).Add(time.Hour * 24 * 4)), | 124 » » » » » » `{"data": ["very", "yes"]}`, clo
ck.Now(c).Add(time.Hour*24*4)) |
| 125 » » » » » tsk.State = "distributorState" |
| 126 » » » » » return nil |
| 125 }) | 127 }) |
| 126 » » » » So(err, ShouldBeNil) | 128 » » » » ttest.Drain(c) |
| 127 | |
| 128 » » » » ex := &model.Execution{ID: 1, Attempt: ds.MakeKe
y("Attempt", aid.DMEncoded())} | |
| 129 » » » » So(ds.Get(ex), ShouldBeNil) | |
| 130 » » » » ex.State = dm.Execution_FINISHED | |
| 131 » » » » So(ds.Put(ex), ShouldBeNil) | |
| 132 | 129 |
| 133 req.Include.AttemptData = true | 130 req.Include.AttemptData = true |
| 134 req.Include.AttemptResult = true | 131 req.Include.AttemptResult = true |
| 135 req.Include.NumExecutions = 128 | 132 req.Include.NumExecutions = 128 |
| 133 req.Include.ExecutionInfoUrl = true |
| 136 data := `{"data":["very","yes"]}` | 134 data := `{"data":["very","yes"]}` |
| 137 » » » » aExpect := dm.NewAttemptFinished(time.Time{}, ui
nt32(len(data)), data) | 135 » » » » aExpect := dm.NewAttemptFinished(time.Time{}, ui
nt32(len(data)), data, "distributorState") |
| 138 aExpect.Data.NumExecutions = 1 | 136 aExpect.Data.NumExecutions = 1 |
| 139 » » » » aExpect.Executions = map[uint32]*dm.Execution{1:
{ | 137 » » » » aExpect.Executions = map[uint32]*dm.Execution{ |
| 140 » » » » » Data: &dm.Execution_Data{ | 138 » » » » » 1: dm.NewExecutionFinished("distributorS
tate"), |
| 141 » » » » » » State: dm.Execution_FINISHED, | 139 » » » » } |
| 142 » » » » » }, | 140 » » » » tok := string(fake.MkToken(dm.NewExecutionID(w,
1, 1))) |
| 143 » » » » }} | 141 » » » » aExpect.Executions[1].Data.DistributorInfo = &dm
.Execution_Data_DistributorInfo{ |
| 144 » » » » So(req, WalkShouldReturn(c), &dm.GraphData{ | 142 » » » » » ConfigName: "fakeDistributor", |
| 143 » » » » » ConfigVersion: "testing", |
| 144 » » » » » Token: tok, |
| 145 » » » » » Url: dist.InfoURL(distributor.
Token(tok)), |
| 146 » » » » } |
| 147 |
| 148 » » » » So(req, fake.WalkShouldReturn(c, s), &dm.GraphDa
ta{ |
| 145 Quests: map[string]*dm.Quest{ | 149 Quests: map[string]*dm.Quest{ |
| 146 w: { | 150 w: { |
| 147 Attempts: map[uint32]*dm
.Attempt{1: aExpect}, | 151 Attempts: map[uint32]*dm
.Attempt{1: aExpect}, |
| 148 }, | 152 }, |
| 149 }, | 153 }, |
| 150 }) | 154 }) |
| 151 }) | 155 }) |
| 152 | 156 |
| 153 Convey("limited attempt results", func() { | 157 Convey("limited attempt results", func() { |
| 154 » » » » _, err := s.FinishAttempt(c, &dm.FinishAttemptRe
q{ | 158 » » » » wEx := dm.NewExecutionID(w, 1, 1) |
| 155 » » » » » Auth: activate(c, execute(c, aid))
, | 159 » » » » dist.RunTask(c, wEx, func(tsk *fake.Task) error
{ |
| 156 » » » » » JsonResult: `{"data": ["very", "yes"]}`, | 160 » » » » » tsk.MustActivate(c, s).Finish( |
| 157 » » » » » Expiration: google_pb.NewTimestamp(clock
.Now(c).Add(time.Hour * 24 * 4)), | 161 » » » » » » `{"data": ["very", "yes"]}`, clo
ck.Now(c).Add(time.Hour*24*4)) |
| 162 » » » » » tsk.State = "distributorState" |
| 163 » » » » » return nil |
| 158 }) | 164 }) |
| 159 » » » » So(err, ShouldBeNil) | 165 » » » » ttest.Drain(c) |
| 160 | |
| 161 » » » » ex := &model.Execution{ID: 1, Attempt: ds.MakeKe
y("Attempt", aid.DMEncoded())} | |
| 162 » » » » So(ds.Get(ex), ShouldBeNil) | |
| 163 » » » » ex.State = dm.Execution_FINISHED | |
| 164 » » » » So(ds.Put(ex), ShouldBeNil) | |
| 165 | 166 |
| 166 req.Include.AttemptResult = true | 167 req.Include.AttemptResult = true |
| 167 req.Limit.MaxDataSize = 10 | 168 req.Limit.MaxDataSize = 10 |
| 168 data := `{"data":["very","yes"]}` | 169 data := `{"data":["very","yes"]}` |
| 169 » » » » aExpect := dm.NewAttemptFinished(time.Time{}, ui
nt32(len(data)), "") | 170 » » » » aExpect := dm.NewAttemptFinished(time.Time{}, ui
nt32(len(data)), "", "") |
| 170 aExpect.Data.NumExecutions = 1 | 171 aExpect.Data.NumExecutions = 1 |
| 171 aExpect.Partial = &dm.Attempt_Partial{Result: dm
.Attempt_Partial_DATA_SIZE_LIMIT} | 172 aExpect.Partial = &dm.Attempt_Partial{Result: dm
.Attempt_Partial_DATA_SIZE_LIMIT} |
| 172 » » » » So(req, WalkShouldReturn(c), &dm.GraphData{ | 173 » » » » So(req, fake.WalkShouldReturn(c, s), &dm.GraphDa
ta{ |
| 173 Quests: map[string]*dm.Quest{ | 174 Quests: map[string]*dm.Quest{ |
| 174 w: { | 175 w: { |
| 175 Attempts: map[uint32]*dm
.Attempt{1: aExpect}, | 176 Attempts: map[uint32]*dm
.Attempt{1: aExpect}, |
| 176 }, | 177 }, |
| 177 }, | 178 }, |
| 178 }) | 179 }) |
| 179 }) | 180 }) |
| 180 | 181 |
| 181 Convey("attemptRange", func() { | 182 Convey("attemptRange", func() { |
| 182 » » » » x := ensureQuest(c, "x", 1) | 183 » » » » x := s.ensureQuest(c, "x", 1) |
| 183 ttest.Drain(c) | 184 ttest.Drain(c) |
| 184 » » » » depOn(c, activate(c, execute(c, dm.NewAttemptID(
w, 1))), | 185 |
| 185 » » » » » dm.NewAttemptID(x, 1), dm.NewAttemptID(x
, 2), dm.NewAttemptID(x, 3), | 186 » » » » wEx := dm.NewExecutionID(w, 1, 1) |
| 186 » » » » » dm.NewAttemptID(x, 4)) | 187 » » » » dist.RunTask(c, wEx, func(tsk *fake.Task) error
{ |
| 188 » » » » » tsk.MustActivate(c, s).DepOn( |
| 189 » » » » » » dm.NewAttemptID(x, 1), dm.NewAtt
emptID(x, 2), dm.NewAttemptID(x, 3), |
| 190 » » » » » » dm.NewAttemptID(x, 4)) |
| 191 » » » » » return nil |
| 192 » » » » }) |
| 187 ttest.Drain(c) | 193 ttest.Drain(c) |
| 188 | 194 |
| 189 req.Limit.MaxDepth = 1 | 195 req.Limit.MaxDepth = 1 |
| 190 Convey("normal", func() { | 196 Convey("normal", func() { |
| 191 req.Query = dm.AttemptRangeQuery(x, 2, 4
) | 197 req.Query = dm.AttemptRangeQuery(x, 2, 4
) |
| 192 » » » » » So(req, WalkShouldReturn(c), &dm.GraphDa
ta{ | 198 » » » » » So(req, fake.WalkShouldReturn(c, s), &dm
.GraphData{ |
| 193 Quests: map[string]*dm.Quest{ | 199 Quests: map[string]*dm.Quest{ |
| 194 x: {Attempts: map[uint32
]*dm.Attempt{2: {}, 3: {}}}, | 200 x: {Attempts: map[uint32
]*dm.Attempt{2: {}, 3: {}}}, |
| 195 }, | 201 }, |
| 196 }) | 202 }) |
| 197 }) | 203 }) |
| 198 | 204 |
| 199 Convey("oob range", func() { | 205 Convey("oob range", func() { |
| 200 req.Query = dm.AttemptRangeQuery(x, 2, 6
) | 206 req.Query = dm.AttemptRangeQuery(x, 2, 6
) |
| 201 » » » » » So(req, WalkShouldReturn(c), &dm.GraphDa
ta{ | 207 » » » » » So(req, fake.WalkShouldReturn(c, s), &dm
.GraphData{ |
| 202 Quests: map[string]*dm.Quest{ | 208 Quests: map[string]*dm.Quest{ |
| 203 x: {Attempts: map[uint32
]*dm.Attempt{ | 209 x: {Attempts: map[uint32
]*dm.Attempt{ |
| 204 2: {}, 3: {}, 4:
{}, 5: {DNE: true}}}, | 210 2: {}, 3: {}, 4:
{}, 5: {DNE: true}}}, |
| 205 }, | 211 }, |
| 206 }) | 212 }) |
| 207 }) | 213 }) |
| 208 }) | 214 }) |
| 209 | 215 |
| 210 Convey("filtered attempt results", func() { | 216 Convey("filtered attempt results", func() { |
| 211 » » » » x := ensureQuest(c, "x", 2) | 217 » » » » x := s.ensureQuest(c, "x", 2) |
| 212 » » » » ttest.Drain(c) | |
| 213 » » » » depOn(c, activate(c, execute(c, dm.NewAttemptID(
w, 1))), dm.NewAttemptID(x, 1)) | |
| 214 ttest.Drain(c) | 218 ttest.Drain(c) |
| 215 | 219 |
| 216 » » » » exp := google_pb.NewTimestamp(datastore.RoundTim
e(clock.Now(c).Add(time.Hour * 24 * 4))) | 220 » » » » dist.RunTask(c, dm.NewExecutionID(w, 1, 1), func
(tsk *fake.Task) error { |
| 221 » » » » » tsk.MustActivate(c, s).DepOn(dm.NewAttem
ptID(x, 1)) |
| 222 » » » » » tsk.State = "originalState" |
| 223 » » » » » return nil |
| 224 » » » » }) |
| 225 » » » » ttest.Drain(c) |
| 226 |
| 227 » » » » exp := datastore.RoundTime(clock.Now(c).Add(time
.Hour * 24 * 4)) |
| 217 | 228 |
| 218 x1data := `{"data":["I can see this"]}` | 229 x1data := `{"data":["I can see this"]}` |
| 219 » » » » _, err := s.FinishAttempt(c, &dm.FinishAttemptRe
q{ | 230 » » » » dist.RunTask(c, dm.NewExecutionID(x, 1, 1), func
(tsk *fake.Task) error { |
| 220 » » » » » Auth: activate(c, execute(c, dm.Ne
wAttemptID(x, 1))), | 231 » » » » » tsk.MustActivate(c, s).Finish(x1data, ex
p) |
| 221 » » » » » JsonResult: x1data, | 232 » » » » » tsk.State = "atmpt1" |
| 222 » » » » » Expiration: exp, | 233 » » » » » return nil |
| 223 }) | 234 }) |
| 224 So(err, ShouldBeNil) | |
| 225 | 235 |
| 226 x2data := `{"data":["nope"]}` | 236 x2data := `{"data":["nope"]}` |
| 227 » » » » _, err = s.FinishAttempt(c, &dm.FinishAttemptReq
{ | 237 » » » » dist.RunTask(c, dm.NewExecutionID(x, 2, 1), func
(tsk *fake.Task) error { |
| 228 » » » » » Auth: activate(c, execute(c, dm.Ne
wAttemptID(x, 2))), | 238 » » » » » tsk.MustActivate(c, s).Finish(x2data, ex
p) |
| 229 » » » » » JsonResult: x2data, | 239 » » » » » tsk.State = "atmpt2" |
| 230 » » » » » Expiration: exp, | 240 » » » » » return nil |
| 231 }) | 241 }) |
| 232 » » » » So(err, ShouldBeNil) | 242 |
| 243 » » » » // This Drain does: |
| 244 » » » » // RecordCompletion -> AckFwdDep -> ScheduleEx
ecution |
| 245 » » » » // which attempts to load the configuration from
the context, and |
| 246 » » » » // panics if it's missing. |
| 233 ttest.Drain(c) | 247 ttest.Drain(c) |
| 234 | 248 |
| 235 » » » » req.Auth = activate(c, execute(c, dm.NewAttemptI
D(w, 1))) | 249 » » » » wEID := dm.NewExecutionID(w, 1, 2) |
| 236 » » » » req.Limit.MaxDepth = 2 | 250 » » » » wEx := model.ExecutionFromID(c, wEID) |
| 237 » » » » req.Include.AttemptResult = true | 251 » » » » So(ds.Get(wEx), ShouldBeNil) |
| 238 » » » » req.Query = dm.AttemptListQueryL(map[string][]ui
nt32{x: nil}) | |
| 239 | 252 |
| 240 » » » » x1Expect := dm.NewAttemptFinished(time.Time{}, u
int32(len(x1data)), x1data) | 253 » » » » dist.RunTask(c, wEID, func(tsk *fake.Task) error
{ |
| 241 » » » » x1Expect.Data.NumExecutions = 1 | 254 » » » » » So(tsk.State, ShouldEqual, "originalStat
e") |
| 242 | 255 |
| 243 » » » » x2Expect := dm.NewAttemptFinished(time.Time{}, u
int32(len(x2data)), "") | 256 » » » » » act := tsk.MustActivate(c, s) |
| 244 » » » » x2Expect.Partial = &dm.Attempt_Partial{Result: d
m.Attempt_Partial_NOT_AUTHORIZED} | 257 » » » » » req.Limit.MaxDepth = 2 |
| 245 » » » » x2Expect.Data.NumExecutions = 1 | 258 » » » » » req.Include.AttemptResult = true |
| 259 » » » » » req.Query = dm.AttemptListQueryL(map[str
ing][]uint32{x: nil}) |
| 246 | 260 |
| 247 » » » » So(req, WalkShouldReturn(c), &dm.GraphData{ | 261 » » » » » x1Expect := dm.NewAttemptFinished(time.T
ime{}, uint32(len(x1data)), x1data, "atmpt1") |
| 248 » » » » » Quests: map[string]*dm.Quest{ | 262 » » » » » x1Expect.Data.NumExecutions = 1 |
| 249 » » » » » » x: {Attempts: map[uint32]*dm.Att
empt{ | 263 |
| 250 » » » » » » » 1: x1Expect, | 264 » » » » » x2Expect := dm.NewAttemptFinished(time.T
ime{}, uint32(len(x2data)), "", "") |
| 251 » » » » » » » 2: x2Expect, | 265 » » » » » x2Expect.Partial = &dm.Attempt_Partial{R
esult: dm.Attempt_Partial_NOT_AUTHORIZED} |
| 252 » » » » » » }}, | 266 » » » » » x2Expect.Data.NumExecutions = 1 |
| 253 » » » » » }}) | 267 |
| 268 » » » » » So(req, act.WalkShouldReturn, &dm.GraphD
ata{ |
| 269 » » » » » » Quests: map[string]*dm.Quest{ |
| 270 » » » » » » » x: {Attempts: map[uint32
]*dm.Attempt{ |
| 271 » » » » » » » » 1: x1Expect, |
| 272 » » » » » » » » 2: x2Expect, |
| 273 » » » » » » » }}, |
| 274 » » » » » » }, |
| 275 » » » » » }) |
| 276 » » » » » return nil |
| 277 » » » » }) |
| 254 }) | 278 }) |
| 255 | 279 |
| 256 Convey("own attempt results", func() { | 280 Convey("own attempt results", func() { |
| 257 » » » » x := ensureQuest(c, "x", 2) | 281 » » » » x := s.ensureQuest(c, "x", 2) |
| 258 ttest.Drain(c) | 282 ttest.Drain(c) |
| 259 » » » » depOn(c, activate(c, execute(c, dm.NewAttemptID(
w, 1))), dm.NewAttemptID(x, 1)) | 283 » » » » dist.RunTask(c, dm.NewExecutionID(w, 1, 1), func
(tsk *fake.Task) error { |
| 284 » » » » » tsk.MustActivate(c, s).DepOn(dm.NewAttem
ptID(x, 1)) |
| 285 » » » » » return nil |
| 286 » » » » }) |
| 260 ttest.Drain(c) | 287 ttest.Drain(c) |
| 261 | 288 |
| 262 » » » » exp := google_pb.NewTimestamp(datastore.RoundTim
e(clock.Now(c).Add(time.Hour * 24 * 4))) | 289 » » » » exp := datastore.RoundTime(clock.Now(c).Add(time
.Hour * 24 * 4)) |
| 263 | 290 |
| 264 x1data := `{"data":["I can see this"]}` | 291 x1data := `{"data":["I can see this"]}` |
| 265 » » » » _, err := s.FinishAttempt(c, &dm.FinishAttemptRe
q{ | 292 » » » » dist.RunTask(c, dm.NewExecutionID(x, 1, 1), func
(tsk *fake.Task) error { |
| 266 » » » » » Auth: activate(c, execute(c, dm.Ne
wAttemptID(x, 1))), | 293 » » » » » tsk.MustActivate(c, s).Finish(x1data, ex
p) |
| 267 » » » » » JsonResult: x1data, | 294 » » » » » tsk.State = "state" |
| 268 » » » » » Expiration: exp, | 295 » » » » » return nil |
| 269 }) | 296 }) |
| 270 So(err, ShouldBeNil) | |
| 271 ttest.Drain(c) | 297 ttest.Drain(c) |
| 272 | 298 |
| 273 » » » » req.Auth = activate(c, execute(c, dm.NewAttemptI
D(w, 1))) | 299 » » » » dist.RunTask(c, dm.NewExecutionID(w, 1, 2), func
(tsk *fake.Task) error { |
| 274 » » » » req.Limit.MaxDepth = 2 | 300 » » » » » act := tsk.MustActivate(c, s) |
| 275 » » » » req.Include.AttemptResult = true | 301 » » » » » req.Limit.MaxDepth = 2 |
| 276 » » » » req.Query = dm.AttemptListQueryL(map[string][]ui
nt32{w: {1}}) | 302 » » » » » req.Include.AttemptResult = true |
| 303 » » » » » req.Query = dm.AttemptListQueryL(map[str
ing][]uint32{w: {1}}) |
| 277 | 304 |
| 278 » » » » x1Expect := dm.NewAttemptFinished(time.Time{}, u
int32(len(x1data)), x1data) | 305 » » » » » x1Expect := dm.NewAttemptFinished(time.T
ime{}, uint32(len(x1data)), x1data, "state") |
| 279 » » » » x1Expect.Data.NumExecutions = 1 | 306 » » » » » x1Expect.Data.NumExecutions = 1 |
| 280 | 307 |
| 281 » » » » w1Exepct := dm.NewAttemptExecuting(2) | 308 » » » » » w1Exepct := dm.NewAttemptExecuting(2) |
| 282 » » » » w1Exepct.Data.NumExecutions = 2 | 309 » » » » » w1Exepct.Data.NumExecutions = 2 |
| 283 | 310 |
| 284 » » » » // This filter ensures that WalkShouldReturn is
using the optimized | 311 » » » » » // This filter ensures that WalkShouldRe
turn is using the optimized |
| 285 » » » » // path for deps traversal when starting from an
authed attempt. | 312 » » » » » // path for deps traversal when starting
from an authed attempt. |
| 286 » » » » c = datastore.AddRawFilters(c, func(c context.Co
ntext, ri datastore.RawInterface) datastore.RawInterface { | 313 » » » » » c = datastore.AddRawFilters(c, func(c co
ntext.Context, ri datastore.RawInterface) datastore.RawInterface { |
| 287 » » » » » return breakFwdDepLoads{ri} | 314 » » » » » » return breakFwdDepLoads{ri} |
| 315 » » » » » }) |
| 316 |
| 317 » » » » » So(req, act.WalkShouldReturn, &dm.GraphD
ata{ |
| 318 » » » » » » Quests: map[string]*dm.Quest{ |
| 319 » » » » » » » w: {Attempts: map[uint32
]*dm.Attempt{1: w1Exepct}}, |
| 320 » » » » » » » x: {Attempts: map[uint32
]*dm.Attempt{1: x1Expect}}, |
| 321 » » » » » » }, |
| 322 » » » » » }) |
| 323 » » » » » return nil |
| 288 }) | 324 }) |
| 289 | |
| 290 So(req, WalkShouldReturn(c), &dm.GraphData{ | |
| 291 Quests: map[string]*dm.Quest{ | |
| 292 w: {Attempts: map[uint32]*dm.Att
empt{1: w1Exepct}}, | |
| 293 x: {Attempts: map[uint32]*dm.Att
empt{1: x1Expect}}, | |
| 294 }}) | |
| 295 }) | 325 }) |
| 296 | 326 |
| 297 Convey("deps (no dest attempts)", func() { | 327 Convey("deps (no dest attempts)", func() { |
| 298 req.Limit.MaxDepth = 3 | 328 req.Limit.MaxDepth = 3 |
| 299 » » » » w1auth := activate(c, execute(c, dm.NewAttemptID
(w, 1))) | 329 |
| 300 » » » » x := ensureQuest(c, "x", 1) | 330 » » » » x := s.ensureQuest(c, "x", 1) |
| 301 ttest.Drain(c) | 331 ttest.Drain(c) |
| 302 depOn(c, w1auth, dm.NewAttemptID(x, 1), dm.NewAt
temptID(x, 2)) | |
| 303 | 332 |
| 304 » » » » Convey("before tumble", func() { | 333 » » » » dist.RunTask(c, dm.NewExecutionID(w, 1, 1), func
(tsk *fake.Task) error { |
| 305 » » » » » Convey("deps", func() { | 334 » » » » » tsk.MustActivate(c, s).DepOn(dm.NewAttem
ptID(x, 1), dm.NewAttemptID(x, 2)) |
| 335 |
| 336 » » » » » Convey("before tumble", func() { |
| 306 req.Include.FwdDeps = true | 337 req.Include.FwdDeps = true |
| 307 // didn't run tumble, so that x|
1 and x|2 don't get created. | 338 // didn't run tumble, so that x|
1 and x|2 don't get created. |
| 308 » » » » » » So(req, WalkShouldReturn(c), &dm
.GraphData{ | 339 » » » » » » // don't use act.WalkShouldRetur
n; we want to observe the graph |
| 340 » » » » » » // state from |
| 341 » » » » » » So(req, fake.WalkShouldReturn(c,
s), &dm.GraphData{ |
| 309 Quests: map[string]*dm.Q
uest{ | 342 Quests: map[string]*dm.Q
uest{ |
| 310 w: {Attempts: ma
p[uint32]*dm.Attempt{1: { | 343 w: {Attempts: ma
p[uint32]*dm.Attempt{1: { |
| 311 FwdDeps:
dm.NewAttemptList(map[string][]uint32{ | 344 FwdDeps:
dm.NewAttemptList(map[string][]uint32{ |
| 312
x: {2, 1}, | 345
x: {2, 1}, |
| 313 }), | 346 }), |
| 314 }}}, | 347 }}}, |
| 315 x: {Attempts: ma
p[uint32]*dm.Attempt{ | 348 x: {Attempts: ma
p[uint32]*dm.Attempt{ |
| 316 1: {FwdD
eps: &dm.AttemptList{}}, // exists, but has no fwddeps | 349 1: {FwdD
eps: &dm.AttemptList{}}, // exists, but has no fwddeps |
| 317 2: {DNE:
true}, | 350 2: {DNE:
true}, |
| 318 }}, | 351 }}, |
| 319 }, | 352 }, |
| 320 }) | 353 }) |
| 321 }) | 354 }) |
| 355 return nil |
| 322 }) | 356 }) |
| 323 | 357 |
| 324 Convey("after tumble", func() { | 358 Convey("after tumble", func() { |
| 325 ttest.Drain(c) | 359 ttest.Drain(c) |
| 360 |
| 326 Convey("deps (with dest attempts)", func
() { | 361 Convey("deps (with dest attempts)", func
() { |
| 327 req.Include.FwdDeps = true | 362 req.Include.FwdDeps = true |
| 328 req.Include.BackDeps = true | 363 req.Include.BackDeps = true |
| 329 » » » » » » So(req, WalkShouldReturn(c), &dm
.GraphData{ | 364 » » » » » » So(req, fake.WalkShouldReturn(c,
s), &dm.GraphData{ |
| 330 Quests: map[string]*dm.Q
uest{ | 365 Quests: map[string]*dm.Q
uest{ |
| 331 w: {Attempts: ma
p[uint32]*dm.Attempt{1: { | 366 w: {Attempts: ma
p[uint32]*dm.Attempt{1: { |
| 332 FwdDeps:
dm.NewAttemptList(map[string][]uint32{x: {2, 1}}), | 367 FwdDeps:
dm.NewAttemptList(map[string][]uint32{x: {2, 1}}), |
| 333 BackDeps
: &dm.AttemptList{}, | 368 BackDeps
: &dm.AttemptList{}, |
| 334 }}}, | 369 }}}, |
| 335 x: {Attempts: ma
p[uint32]*dm.Attempt{1: { | 370 x: {Attempts: ma
p[uint32]*dm.Attempt{1: { |
| 336 FwdDeps:
&dm.AttemptList{}, | 371 FwdDeps:
&dm.AttemptList{}, |
| 337 BackDeps
: dm.NewAttemptList(map[string][]uint32{w: {1}}), | 372 BackDeps
: dm.NewAttemptList(map[string][]uint32{w: {1}}), |
| 338 }, 2: { | 373 }, 2: { |
| 339 FwdDeps:
&dm.AttemptList{}, | 374 FwdDeps:
&dm.AttemptList{}, |
| 340 BackDeps
: dm.NewAttemptList(map[string][]uint32{w: {1}}), | 375 BackDeps
: dm.NewAttemptList(map[string][]uint32{w: {1}}), |
| 341 }}}, | 376 }}}, |
| 342 }, | 377 }, |
| 343 }) | 378 }) |
| 344 }) | 379 }) |
| 345 | 380 |
| 346 Convey("diamond", func() { | 381 Convey("diamond", func() { |
| 347 » » » » » » z := ensureQuest(c, "z", 1) | 382 » » » » » » z := s.ensureQuest(c, "z", 1) |
| 348 » » » » » » ttest.Drain(c) | |
| 349 » » » » » » depOn(c, activate(c, execute(c,
dm.NewAttemptID(x, 1))), dm.NewAttemptID(z, 1)) | |
| 350 » » » » » » depOn(c, activate(c, execute(c,
dm.NewAttemptID(x, 2))), dm.NewAttemptID(z, 1)) | |
| 351 ttest.Drain(c) | 383 ttest.Drain(c) |
| 352 | 384 |
| 353 » » » » » » So(req, WalkShouldReturn(c), &dm
.GraphData{ | 385 » » » » » » dist.RunTask(c, dm.NewExecutionI
D(x, 1, 1), func(tsk *fake.Task) error { |
| 354 » » » » » » » Quests: map[string]*dm.Q
uest{ | 386 » » » » » » » tsk.MustActivate(c, s).D
epOn(dm.NewAttemptID(z, 1)) |
| 355 » » » » » » » » w: {Attempts: ma
p[uint32]*dm.Attempt{1: {}}}, | 387 » » » » » » » return nil |
| 356 » » » » » » » » x: {Attempts: ma
p[uint32]*dm.Attempt{1: {}, 2: {}}}, | |
| 357 » » » » » » » » z: {Attempts: ma
p[uint32]*dm.Attempt{1: {}}}, | |
| 358 » » » » » » » }, | |
| 359 }) | 388 }) |
| 360 » » » » » }) | 389 » » » » » » dist.RunTask(c, dm.NewExecutionI
D(x, 2, 1), func(tsk *fake.Task) error { |
| 361 | 390 » » » » » » » tsk.MustActivate(c, s).D
epOn(dm.NewAttemptID(z, 1)) |
| 362 » » » » » Convey("diamond (dfs)", func() { | 391 » » » » » » » return nil |
| 363 » » » » » » z := ensureQuest(c, "z", 1) | 392 » » » » » » }) |
| 364 » » » » » » ttest.Drain(c) | |
| 365 » » » » » » depOn(c, activate(c, execute(c,
dm.NewAttemptID(x, 1))), dm.NewAttemptID(z, 1)) | |
| 366 » » » » » » depOn(c, activate(c, execute(c,
dm.NewAttemptID(x, 2))), dm.NewAttemptID(z, 1)) | |
| 367 ttest.Drain(c) | 393 ttest.Drain(c) |
| 368 | 394 |
| 369 » » » » » » req.Mode.Dfs = true | 395 » » » » » » Convey("walk", func() { |
| 370 » » » » » » So(req, WalkShouldReturn(c), &dm
.GraphData{ | 396 » » » » » » » So(req, fake.WalkShouldR
eturn(c, s), &dm.GraphData{ |
| 371 » » » » » » » Quests: map[string]*dm.Q
uest{ | 397 » » » » » » » » Quests: map[stri
ng]*dm.Quest{ |
| 372 » » » » » » » » w: {Attempts: ma
p[uint32]*dm.Attempt{1: {}}}, | 398 » » » » » » » » » w: {Atte
mpts: map[uint32]*dm.Attempt{1: {}}}, |
| 373 » » » » » » » » x: {Attempts: ma
p[uint32]*dm.Attempt{1: {}, 2: {}}}, | 399 » » » » » » » » » x: {Atte
mpts: map[uint32]*dm.Attempt{1: {}, 2: {}}}, |
| 374 » » » » » » » » z: {Attempts: ma
p[uint32]*dm.Attempt{1: {}}}, | 400 » » » » » » » » » z: {Atte
mpts: map[uint32]*dm.Attempt{1: {}}}, |
| 375 » » » » » » » }, | 401 » » » » » » » » }, |
| 402 » » » » » » » }) |
| 376 }) | 403 }) |
| 404 |
| 405 Convey("walk (dfs)", func() { |
| 406 req.Mode.Dfs = true |
| 407 So(req, fake.WalkShouldR
eturn(c, s), &dm.GraphData{ |
| 408 Quests: map[stri
ng]*dm.Quest{ |
| 409 w: {Atte
mpts: map[uint32]*dm.Attempt{1: {}}}, |
| 410 x: {Atte
mpts: map[uint32]*dm.Attempt{1: {}, 2: {}}}, |
| 411 z: {Atte
mpts: map[uint32]*dm.Attempt{1: {}}}, |
| 412 }, |
| 413 }) |
| 414 }) |
| 415 |
| 377 }) | 416 }) |
| 378 | 417 |
| 379 Convey("attemptlist", func() { | 418 Convey("attemptlist", func() { |
| 380 req.Limit.MaxDepth = 1 | 419 req.Limit.MaxDepth = 1 |
| 381 req.Include.ObjectIds = true | 420 req.Include.ObjectIds = true |
| 382 req.Query = dm.AttemptListQueryL
(map[string][]uint32{x: nil}) | 421 req.Query = dm.AttemptListQueryL
(map[string][]uint32{x: nil}) |
| 383 » » » » » » So(req, WalkShouldReturn(c), &dm
.GraphData{ | 422 » » » » » » So(req, fake.WalkShouldReturn(c,
s), &dm.GraphData{ |
| 384 Quests: map[string]*dm.Q
uest{ | 423 Quests: map[string]*dm.Q
uest{ |
| 385 x: { | 424 x: { |
| 386 Id: dm.N
ewQuestID(x), | 425 Id: dm.N
ewQuestID(x), |
| 387 Attempts
: map[uint32]*dm.Attempt{ | 426 Attempts
: map[uint32]*dm.Attempt{ |
| 388
1: {Id: dm.NewAttemptID(x, 1)}, | 427
1: {Id: dm.NewAttemptID(x, 1)}, |
| 389
2: {Id: dm.NewAttemptID(x, 2)}, | 428
2: {Id: dm.NewAttemptID(x, 2)}, |
| 390 }, | 429 }, |
| 391 }, | 430 }, |
| 392 }, | 431 }, |
| 393 }) | 432 }) |
| 394 }) | 433 }) |
| 395 | 434 |
| 396 }) | 435 }) |
| 397 | 436 |
| 398 Convey("early stop", func() { | 437 Convey("early stop", func() { |
| 399 req.Limit.MaxDepth = 100 | 438 req.Limit.MaxDepth = 100 |
| 400 req.Limit.MaxTime = google_pb.NewDuratio
n(time.Nanosecond) | 439 req.Limit.MaxTime = google_pb.NewDuratio
n(time.Nanosecond) |
| 401 tc := clock.Get(c).(testclock.TestClock) | 440 tc := clock.Get(c).(testclock.TestClock) |
| 402 tc.SetTimerCallback(func(d time.Duration
, t clock.Timer) { | 441 tc.SetTimerCallback(func(d time.Duration
, t clock.Timer) { |
| 403 tc.Add(d + time.Second) | 442 tc.Add(d + time.Second) |
| 404 }) | 443 }) |
| 405 » » » » » ret, err := newDecoratedDeps().WalkGraph
(c, req) | 444 » » » » » ret, err := s.WalkGraph(c, req) |
| 406 So(err, ShouldBeNil) | 445 So(err, ShouldBeNil) |
| 407 So(ret.HadMore, ShouldBeTrue) | 446 So(ret.HadMore, ShouldBeTrue) |
| 408 }) | 447 }) |
| 409 | 448 |
| 410 }) | 449 }) |
| 411 }) | 450 }) |
| 412 }) | 451 }) |
| 413 } | 452 } |
| OLD | NEW |