| 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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 // | 115 // |
| 117 // service.RawFactory - a function returning a RawInterface | 116 // service.RawFactory - a function returning a RawInterface |
| 118 // | 117 // |
| 119 // service.RawFilter - a function returning a new RawInterface based on | 118 // service.RawFilter - a function returning a new RawInterface based on |
| 120 // the previous filtered interface. Filters chain | 119 // the previous filtered interface. Filters chain |
| 121 // together to allow behavioral service features | 120 // together to allow behavioral service features |
| 122 // without needing to agument the underlying service | 121 // without needing to agument the underlying service |
| 123 // implementations directly. | 122 // implementations directly. |
| 124 // | 123 // |
| 125 // And common functions are: | 124 // And common functions are: |
| 126 // service.Get - Retrieve the current, filtered Interface | |
| 127 // implementation from the context. This is the most | |
| 128 // frequently used service function by far. | |
| 129 // | |
| 130 // service.GetRaw - Retrieve the current, filtered RawInterface | 125 // service.GetRaw - Retrieve the current, filtered RawInterface |
| 131 // implementation from the context. This is less | 126 // implementation from the context. This is less |
| 132 // frequently used, but can be useful if you want to | 127 // frequently used, but can be useful if you want to |
| 133 // avoid some of the overhead of the user-friendly | 128 // avoid some of the overhead of the user-friendly |
| 134 // Interface, which can do sometimes-unnecessary amou
nts | 129 // Interface, which can do sometimes-unnecessary amou
nts |
| 135 // of reflection or allocation. The RawInterface and | 130 // of reflection or allocation. The RawInterface and |
| 136 // Interface for a service are fully interchangable a
nd | 131 // Interface for a service are fully interchangable a
nd |
| 137 // usage of them can be freely mixed in an applicatio
n. | 132 // usage of them can be freely mixed in an applicatio
n. |
| 138 // | 133 // |
| 139 // service.AddRawFilters - adds one or more RawFilters to the context. | 134 // service.AddRawFilters - adds one or more RawFilters to the context. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 // CoolFunc(c) | 166 // CoolFunc(c) |
| 172 // } | 167 // } |
| 173 // | 168 // |
| 174 // // This is the 'testing' code | 169 // // This is the 'testing' code |
| 175 // func TestCoolFunc(t *testing.T) { | 170 // func TestCoolFunc(t *testing.T) { |
| 176 // c := memory.Use(context.Background()) | 171 // c := memory.Use(context.Background()) |
| 177 // CoolFunc(c) | 172 // CoolFunc(c) |
| 178 // } | 173 // } |
| 179 // | 174 // |
| 180 // func CoolFunc(c context.Context, ...) { | 175 // 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. | |
| 186 // SomeOtherFunction(c, ...) | 176 // SomeOtherFunction(c, ...) |
| 187 // | 177 // |
| 188 // // because you might need to: | 178 // // because you might need to: |
| 189 // ds.RunInTransaction(func (c context.Context) error { | 179 // ds.RunInTransaction(c, func (c context.Context) error { |
| 190 // SomeOtherFunction(c, ...) // c contains transactional versions of ever
ything | 180 // SomeOtherFunction(c, ...) // c contains transactional versions of ever
ything |
| 191 // }, nil) | 181 // }, nil) |
| 192 // } | 182 // } |
| 193 // | 183 // |
| 194 // Filters | 184 // Filters |
| 195 // | 185 // |
| 196 // Each service also supports "filters". Filters are proxy objects which have | 186 // 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 | 187 // 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 | 188 // the previous filter in the stack. Conceptually, a filtered version of, for |
| 199 // example, the Datastore, could look like: | 189 // example, the Datastore, could look like: |
| 200 // User code | 190 // User code |
| 201 // <count filter (counts how many times each API is called by the user)> | 191 // <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)> | 192 // <dscache filter (attempts to use memcache as a cache for datastore)> |
| 203 // <count filter (counts how many times each API is actually hit)> | 193 // <count filter (counts how many times each API is actually hit)> |
| 204 // memory datastore.RawInterface implementation | 194 // memory datastore.RawInterface implementation |
| 205 // | 195 // |
| 206 // So datastore.Get would return the full stack. In code, this would look | |
| 207 // like: | |
| 208 // func HTTPHandler(r *http.Request) { | |
| 209 // c := prod.UseRequest(r)
// production datastore | |
| 210 // c, rawCount := count.FilterRDS(c) // add count filter | |
| 211 // c = dscache.FilterRDS(c) // add dscache filter | |
| 212 // c, userCount := count.FilterRDS(c) // add another count filter | |
| 213 // } | |
| 214 // | |
| 215 // Filters may or may not have state, it's up to the filter itself. In the case | 196 // 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, | 197 // 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. | 198 // 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 | 199 // 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 | 200 // see how many calls to the actual real datastore went through, vs. how many |
| 220 // went to memcache, for example. | 201 // went to memcache, for example. |
| 221 // | 202 // |
| 222 // Note that Filters apply only to the service.RawInterface. All implementations | 203 // Note that Filters apply only to the service.RawInterface. All implementations |
| 223 // of service.Interface boil down to calls to service.RawInterface methods, but | 204 // 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 | 205 // it's possible that bad calls to the service.Interface methods could return |
| 225 // an error before ever reaching the filters or service implementation. | 206 // an error before ever reaching the filters or service implementation. |
| 226 package gae | 207 package gae |
| OLD | NEW |