go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/doc.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package gae provides a fakable wrapped interface for the appengine SDK's 16 // APIs. This means that it's possible to mock all of the supported appengine 17 // APIs for testing (or potentially implement a different backend for them). 18 // 19 // # Features 20 // 21 // gae currently provides interfaces for: 22 // - Datastore 23 // - Memcache 24 // - TaskQueue 25 // - Info (e.g. Namespace, AppID, etc.) 26 // 27 // Additional features include: 28 // - true service interfaces (not package-level functions) 29 // - methods don't need explicit context passed to them, increasing readability. 30 // - service filters allow for composition of functionality. For example: 31 // - transparent memcaching of datastore access 32 // - transparent transaction buffering 33 // - statistics-gathering shims 34 // - deterministic and probabalistic API failure simulation 35 // - transparent retries 36 // - truly parallel in-memory testing implementation. No more need for 37 // dev_appserver.py subprocesses :). 38 // - Separate service and user-facing interfaces 39 // - Allows easier filter and service implementation while retaining the 40 // benefits of a user-friendly interface. 41 // 42 // # Package Organization 43 // 44 // The gae library is organized into several subpackages: 45 // - service/* supported service definitions 46 // - impl/* implementations of the services 47 // - filter/* extra filter functionality for the services, agnostic to the 48 // underlying implementation. 49 // 50 // # Service Definitions 51 // 52 // A service defintion lives under the `service` subfolder, and defines the 53 // user-facing interface for a service. Each service has a few common types and 54 // functions. Common types are: 55 // 56 // service.Interface - the main user-friendly service interface. 57 // 58 // service.RawInterface - the internal service interface used by service 59 // and filter implementations. Note that some services 60 // like Info don't distinguish between the service 61 // interface and the user interface. This interface is 62 // typically a bit lower level than Interface and 63 // lacks convenience methods. 64 // 65 // service.Testable - any additional methods that a 'testing' 66 // implementation should provide. This can be accessed 67 // via the Testable method on RawInterface. If the 68 // current implementation is not testable, it will 69 // return nil. This is only meant to be accessed when 70 // testing. 71 // 72 // service.RawFactory - a function returning a RawInterface 73 // 74 // service.RawFilter - a function returning a new RawInterface based on 75 // the previous filtered interface. Filters chain 76 // together to allow behavioral service features 77 // without needing to agument the underlying service 78 // implementations directly. 79 // 80 // And common functions are: 81 // 82 // service.GetRaw - Retrieve the current, filtered RawInterface 83 // implementation from the context. This is less 84 // frequently used, but can be useful if you want to 85 // avoid some of the overhead of the user-friendly 86 // Interface, which can do sometimes-unnecessary amounts 87 // of reflection or allocation. The RawInterface and 88 // Interface for a service are fully interchangable and 89 // usage of them can be freely mixed in an application. 90 // 91 // service.AddRawFilters - adds one or more RawFilters to the context. 92 // 93 // service.SetRawFactory - adds a RawFactory to the context 94 // 95 // service.SetRaw - adds an implementation of RawInterface to the context 96 // (shorthand for SetRawFactory, useful for testing) 97 // 98 // # Implementations 99 // 100 // The impl subdirectory contains a couple different service implementations, 101 // depending on your needs. 102 // 103 // 'prod' is the production (e.g. real appengine-backed) implementation. It 104 // calls through to the original appengine SDK. 105 // 106 // 'memory' is a truly parallel in-memory testing implementation. It should 107 // be functionally the same as the production appengine services, implementing 108 // many of the real-world quirks of the actual services. It also implements 109 // the services' Testable interface, for those services which define those 110 // interfaces. 111 // 112 // 'dummy' provides a bunch of implementations of the various RawInterfaces. 113 // These implementations just panic with an appropriate message, depending on 114 // which API method was called. They're useful to embed in filter or service 115 // implementations as stubs while you're implementing the filter. 116 // 117 // # Filters 118 // 119 // Each service also supports "filters". Filters are proxy objects which have 120 // the same interface as the service they're filtering, and pass data through to 121 // the previous filter in the stack. Conceptually, a filtered version of, for 122 // example, the Datastore, could look like: 123 // 124 // User code 125 // <count filter (counts how many times each API is called by the user)> 126 // <dscache filter (attempts to use memcache as a cache for datastore)> 127 // <count filter (counts how many times each API is actually hit)> 128 // memory datastore.RawInterface implementation 129 // 130 // Filters may or may not have state, it's up to the filter itself. In the case 131 // of the count filter, it returns its state from the Filter<Service> method, 132 // and the state can be observed to see how many times each API was invoked. 133 // Since filters stack, we can compare counts from rawCount versus userCount to 134 // see how many calls to the actual real datastore went through, vs. how many 135 // went to memcache, for example. 136 // 137 // Note that Filters apply only to the service.RawInterface. All implementations 138 // of service.Interface boil down to calls to service.RawInterface methods, but 139 // it's possible that bad calls to the service.Interface methods could return 140 // an error before ever reaching the filters or service implementation. 141 package gae