Merge lp:~chipaca/snappy/tasks into lp:~snappy-dev/snappy/snappy-moved-to-github

Proposed by John Lenton on 2015-09-11
Status: Merged
Approved by: John Lenton on 2015-09-14
Approved revision: 666
Merged at revision: 679
Proposed branch: lp:~chipaca/snappy/tasks
Merge into: lp:~snappy-dev/snappy/snappy-moved-to-github
Prerequisite: lp:~chipaca/snappy/icons
Diff against target: 288 lines (+269/-0)
4 files modified
daemon/task.go (+94/-0)
daemon/task_test.go (+81/-0)
daemon/uuid.go (+52/-0)
daemon/uuid_test.go (+42/-0)
To merge this branch: bzr merge lp:~chipaca/snappy/tasks
Reviewer Review Type Date Requested Status
Michael Vogt 2015-09-11 Approve on 2015-09-11
Review via email: mp+270813@code.launchpad.net

Commit Message

Tasks.

To post a comment you must log in.
Michael Vogt (mvo) wrote :

Good stuff!

review: Approve
John Lenton (chipaca) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'daemon/task.go'
2--- daemon/task.go 1970-01-01 00:00:00 +0000
3+++ daemon/task.go 2015-09-14 12:48:40 +0000
4@@ -0,0 +1,94 @@
5+// -*- Mode: Go; indent-tabs-mode: t -*-
6+
7+/*
8+ * Copyright (C) 2015 Canonical Ltd
9+ *
10+ * This program is free software: you can redistribute it and/or modify
11+ * it under the terms of the GNU General Public License version 3 as
12+ * published by the Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful,
15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ * GNU General Public License for more details.
18+ *
19+ * You should have received a copy of the GNU General Public License
20+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
21+ *
22+ */
23+
24+package daemon
25+
26+import (
27+ "github.com/gorilla/mux"
28+ "gopkg.in/tomb.v2"
29+)
30+
31+// A Task encapsulates an asynchronous operation.
32+type Task struct {
33+ id UUID
34+ tomb tomb.Tomb
35+ metadata interface{}
36+}
37+
38+// A task can be in one of three states
39+const (
40+ TaskRunning = "running"
41+ TaskSucceeded = "succeeded"
42+ TaskFailed = "failed"
43+)
44+
45+// Metadata is the outcome of this task. If the task is still running
46+// this will be nil.
47+func (t *Task) Metadata() interface{} {
48+ if t.tomb.Alive() {
49+ return nil
50+ }
51+
52+ return t.metadata
53+}
54+
55+// State of the task
56+func (t *Task) State() string {
57+ err := t.tomb.Err()
58+ switch err {
59+ case tomb.ErrStillAlive:
60+ return TaskRunning
61+ case nil:
62+ return TaskSucceeded
63+ default:
64+ return TaskFailed
65+ }
66+}
67+
68+// Location of the task, based on the given route.
69+//
70+// If the route can't build a URL for this task, returns the empty
71+// string.
72+func (t *Task) Location(route *mux.Route) string {
73+ url, err := route.URL("uuid", t.id.String())
74+ if err != nil {
75+ return ""
76+ }
77+
78+ return url.String()
79+}
80+
81+// RunTask creates a Task for the given function and runs it.
82+func RunTask(f func() interface{}) *Task {
83+ id := UUID4()
84+ t := &Task{id: id}
85+
86+ t.tomb.Go(func() error {
87+ out := f()
88+ t.metadata = out
89+
90+ if err, ok := out.(error); ok {
91+ return err
92+ }
93+
94+ return nil
95+ })
96+
97+ return t
98+}
99
100=== added file 'daemon/task_test.go'
101--- daemon/task_test.go 1970-01-01 00:00:00 +0000
102+++ daemon/task_test.go 2015-09-14 12:48:40 +0000
103@@ -0,0 +1,81 @@
104+// -*- Mode: Go; indent-tabs-mode: t -*-
105+
106+/*
107+ * Copyright (C) 2015 Canonical Ltd
108+ *
109+ * This program is free software: you can redistribute it and/or modify
110+ * it under the terms of the GNU General Public License version 3 as
111+ * published by the Free Software Foundation.
112+ *
113+ * This program is distributed in the hope that it will be useful,
114+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
115+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
116+ * GNU General Public License for more details.
117+ *
118+ * You should have received a copy of the GNU General Public License
119+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
120+ *
121+ */
122+
123+package daemon
124+
125+import (
126+ "errors"
127+ "time"
128+
129+ "github.com/gorilla/mux"
130+ "gopkg.in/check.v1"
131+)
132+
133+type taskSuite struct{}
134+
135+var _ = check.Suite(&taskSuite{})
136+
137+func (s *taskSuite) TestTask(c *check.C) {
138+ router := mux.NewRouter()
139+ route := router.Handle("/xyzzy/{uuid}", nil)
140+
141+ ch := make(chan struct{})
142+
143+ t := RunTask(func() interface{} {
144+ ch <- struct{}{}
145+ return 42
146+ })
147+
148+ c.Check(t.Metadata(), check.IsNil)
149+ c.Check(t.State(), check.Equals, TaskRunning)
150+ c.Check(t.Location(route), check.Equals, "/xyzzy/"+t.id.String())
151+
152+ <-ch
153+
154+ // let the other guy have a go, just in case
155+ time.Sleep(time.Millisecond)
156+
157+ c.Check(t.State(), check.Equals, TaskSucceeded)
158+ c.Check(t.Metadata(), check.Equals, 42)
159+}
160+
161+func (s *taskSuite) TestFails(c *check.C) {
162+ router := mux.NewRouter()
163+ route := router.Handle("/xyzzy/{uuid}", nil)
164+
165+ ch := make(chan struct{})
166+ err := errors.New("everything is broken")
167+
168+ t := RunTask(func() interface{} {
169+ ch <- struct{}{}
170+ return err
171+ })
172+
173+ c.Check(t.Metadata(), check.IsNil)
174+ c.Check(t.State(), check.Equals, TaskRunning)
175+ c.Check(t.Location(route), check.Equals, "/xyzzy/"+t.id.String())
176+
177+ <-ch
178+
179+ // let the other guy have a go, just in case
180+ time.Sleep(time.Millisecond)
181+
182+ c.Check(t.State(), check.Equals, TaskFailed)
183+ c.Check(t.Metadata(), check.Equals, err)
184+}
185
186=== added file 'daemon/uuid.go'
187--- daemon/uuid.go 1970-01-01 00:00:00 +0000
188+++ daemon/uuid.go 2015-09-14 12:48:40 +0000
189@@ -0,0 +1,52 @@
190+// -*- Mode: Go; indent-tabs-mode: t -*-
191+
192+/*
193+ * Copyright (C) 2015 Canonical Ltd
194+ *
195+ * This program is free software: you can redistribute it and/or modify
196+ * it under the terms of the GNU General Public License version 3 as
197+ * published by the Free Software Foundation.
198+ *
199+ * This program is distributed in the hope that it will be useful,
200+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
201+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
202+ * GNU General Public License for more details.
203+ *
204+ * You should have received a copy of the GNU General Public License
205+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
206+ *
207+ */
208+
209+package daemon
210+
211+import (
212+ "fmt"
213+ "math/rand"
214+ "time"
215+)
216+
217+// TODO: use an actual uuid package; these UUIDs actually have only
218+// 126 bits free (and less entropy than that). Good enough for our use
219+// case for now at least.
220+
221+// An UUID is a universally unique identifier
222+type UUID [2]uint64
223+
224+var source = rand.NewSource(time.Now().UTC().UnixNano())
225+
226+// UUID4 are random-based UUIDs
227+func UUID4() UUID {
228+ return UUID{uint64(source.Int63()), uint64(source.Int63())}
229+}
230+
231+func (u UUID) String() string {
232+ m := u[0]
233+ n := u[1]
234+
235+ return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
236+ n&0xffffffff,
237+ (n>>32)&0xffff,
238+ (n>>48)&0xffff,
239+ m&0xffff,
240+ m>>16)
241+}
242
243=== added file 'daemon/uuid_test.go'
244--- daemon/uuid_test.go 1970-01-01 00:00:00 +0000
245+++ daemon/uuid_test.go 2015-09-14 12:48:40 +0000
246@@ -0,0 +1,42 @@
247+// -*- Mode: Go; indent-tabs-mode: t -*-
248+
249+/*
250+ * Copyright (C) 2015 Canonical Ltd
251+ *
252+ * This program is free software: you can redistribute it and/or modify
253+ * it under the terms of the GNU General Public License version 3 as
254+ * published by the Free Software Foundation.
255+ *
256+ * This program is distributed in the hope that it will be useful,
257+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
258+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
259+ * GNU General Public License for more details.
260+ *
261+ * You should have received a copy of the GNU General Public License
262+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
263+ *
264+ */
265+
266+package daemon
267+
268+import (
269+ "gopkg.in/check.v1"
270+)
271+
272+type uuidSuite struct{}
273+
274+var _ = check.Suite(&uuidSuite{})
275+
276+func (s *uuidSuite) TestUUID(c *check.C) {
277+ uuids := make([]UUID, 200)
278+ for i := range uuids {
279+ uuids[i] = UUID4()
280+ }
281+
282+ for i := range uuids[:len(uuids)-2] {
283+ c.Check(uuids[i].String(), check.Matches, `^[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}`, check.Commentf("format of %d wrong: %s", i, uuids[i]))
284+ for j := range uuids[i+1:] {
285+ c.Check(uuids[i], check.Not(check.Equals), uuids[i+j+1], check.Commentf("%d == %d", i, i+j+1))
286+ }
287+ }
288+}

Subscribers

People subscribed via source and target branches