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 gae provides a fakable wrapped interface for the appengine SDK's | 5 // Package gae provides a fakable wrapped interface for the appengine SDK's |
6 // APIs. This means that it's possible to mock all of the supported appengine | 6 // APIs. This means that it's possible to mock all of the supported appengine |
7 // APIs for testing (or potentially implement a different backend for them). | 7 // APIs for testing (or potentially implement a different backend for them). |
8 // | 8 // |
9 // Features | 9 // Features |
10 // | 10 // |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 // innerHandler(c, w) | 56 // innerHandler(c, w) |
57 // } | 57 // } |
58 // | 58 // |
59 // type CoolStruct struct { | 59 // type CoolStruct struct { |
60 // ID `gae:"$id"` | 60 // ID `gae:"$id"` |
61 // | 61 // |
62 // Value string | 62 // Value string |
63 // } | 63 // } |
64 // | 64 // |
65 // func innerHandler(c context.Context, w http.ResponseWriter) { | 65 // func innerHandler(c context.Context, w http.ResponseWriter) { |
66 // rds := datastore.Get(c) | |
67 // obj := &CoolStruct{Value: "hello"} | 66 // obj := &CoolStruct{Value: "hello"} |
68 // if err := rds.Put(obj); err != nil { | 67 // if err := rds.Put(c, obj); err != nil { |
69 // http.Error(w, err.String(), http.StatusInternalServerError) | 68 // http.Error(w, err.String(), http.StatusInternalServerError) |
70 // } | 69 // } |
71 // fmt.Fprintf(w, "I wrote: %s", ds.KeyForObj(obj)) | 70 // fmt.Fprintf(w, "I wrote: %s", ds.KeyForObj(obj)) |
72 // } | 71 // } |
73 // | 72 // |
74 // And in your test do: | 73 // And in your test do: |
75 // | 74 // |
76 // import ( | 75 // import ( |
77 // "testing" | 76 // "testing" |
78 // "fmt" | 77 // "fmt" |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 // CoolFunc(c) | 170 // CoolFunc(c) |
172 // } | 171 // } |
173 // | 172 // |
174 // // This is the 'testing' code | 173 // // This is the 'testing' code |
175 // func TestCoolFunc(t *testing.T) { | 174 // func TestCoolFunc(t *testing.T) { |
176 // c := memory.Use(context.Background()) | 175 // c := memory.Use(context.Background()) |
177 // CoolFunc(c) | 176 // CoolFunc(c) |
178 // } | 177 // } |
179 // | 178 // |
180 // func CoolFunc(c context.Context, ...) { | 179 // func CoolFunc(c context.Context, ...) { |
181 // ds := datastore.Get(c) // returns a datastore.Interface object | |
182 // mc := memcache.Get(c) // returns a memcache.Interface object | |
183 // // use them here | |
184 // | |
185 // // don't pass ds/mc/etc. directly, pass the context instead. | 180 // // don't pass ds/mc/etc. directly, pass the context instead. |
iannucci
2016/09/16 01:01:13
this comment no longer makes sense
dnj
2016/09/16 05:44:42
Done.
| |
186 // SomeOtherFunction(c, ...) | 181 // SomeOtherFunction(c, ...) |
187 // | 182 // |
188 // // because you might need to: | 183 // // because you might need to: |
189 // ds.RunInTransaction(func (c context.Context) error { | 184 // ds.RunInTransaction(c, func (c context.Context) error { |
190 // SomeOtherFunction(c, ...) // c contains transactional versions of ever ything | 185 // SomeOtherFunction(c, ...) // c contains transactional versions of ever ything |
191 // }, nil) | 186 // }, nil) |
192 // } | 187 // } |
193 // | 188 // |
194 // Filters | 189 // Filters |
195 // | 190 // |
196 // Each service also supports "filters". Filters are proxy objects which have | 191 // Each service also supports "filters". Filters are proxy objects which have |
197 // the same interface as the service they're filtering, and pass data through to | 192 // the same interface as the service they're filtering, and pass data through to |
198 // the previous filter in the stack. Conceptually, a filtered version of, for | 193 // the previous filter in the stack. Conceptually, a filtered version of, for |
199 // example, the Datastore, could look like: | 194 // example, the Datastore, could look like: |
200 // User code | 195 // User code |
201 // <count filter (counts how many times each API is called by the user)> | 196 // <count filter (counts how many times each API is called by the user)> |
202 // <dscache filter (attempts to use memcache as a cache for datastore)> | 197 // <dscache filter (attempts to use memcache as a cache for datastore)> |
203 // <count filter (counts how many times each API is actually hit)> | 198 // <count filter (counts how many times each API is actually hit)> |
204 // memory datastore.RawInterface implementation | 199 // memory datastore.RawInterface implementation |
205 // | 200 // |
206 // So datastore.Get would return the full stack. In code, this would look | 201 // So datastore.Raw would return the full stack. In code, this would look |
iannucci
2016/09/16 01:01:13
Nor does this one
dnj
2016/09/16 05:44:42
Done.
| |
207 // like: | 202 // like: |
208 // func HTTPHandler(r *http.Request) { | 203 // func HTTPHandler(r *http.Request) { |
209 // c := prod.UseRequest(r)» » » » » » » // production datastore | 204 // c := prod.UseRequest(r) // production datastore |
210 // c, rawCount := count.FilterRDS(c) // add count filter | 205 // c, rawCount := count.FilterRDS(c) // add count filter |
211 // c = dscache.FilterRDS(c) // add dscache filter | 206 // c = dscache.FilterRDS(c) // add dscache filter |
212 // c, userCount := count.FilterRDS(c) // add another count filter | 207 // c, userCount := count.FilterRDS(c) // add another count filter |
213 // } | 208 // } |
214 // | 209 // |
215 // Filters may or may not have state, it's up to the filter itself. In the case | 210 // Filters may or may not have state, it's up to the filter itself. In the case |
216 // of the count filter, it returns its state from the Filter<Service> method, | 211 // of the count filter, it returns its state from the Filter<Service> method, |
217 // and the state can be observed to see how many times each API was invoked. | 212 // and the state can be observed to see how many times each API was invoked. |
218 // Since filters stack, we can compare counts from rawCount versus userCount to | 213 // Since filters stack, we can compare counts from rawCount versus userCount to |
219 // see how many calls to the actual real datastore went through, vs. how many | 214 // see how many calls to the actual real datastore went through, vs. how many |
220 // went to memcache, for example. | 215 // went to memcache, for example. |
221 // | 216 // |
222 // Note that Filters apply only to the service.RawInterface. All implementations | 217 // Note that Filters apply only to the service.RawInterface. All implementations |
223 // of service.Interface boil down to calls to service.RawInterface methods, but | 218 // of service.Interface boil down to calls to service.RawInterface methods, but |
224 // it's possible that bad calls to the service.Interface methods could return | 219 // it's possible that bad calls to the service.Interface methods could return |
225 // an error before ever reaching the filters or service implementation. | 220 // an error before ever reaching the filters or service implementation. |
226 package gae | 221 package gae |
OLD | NEW |