| 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 | 
|---|