Chromium Code Reviews

Side by Side Diff: go/src/infra/gae/libs/wrapper/brokenfeatures.go

Issue 1230303003: Revert "Refactor current GAE abstraction library to be free of the SDK*" (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package gae 5 package wrapper
6 6
7 import ( 7 import (
8 "errors" 8 "errors"
9 "fmt" 9 "fmt"
10 "runtime" 10 "runtime"
11 "strings" 11 "strings"
12 "sync" 12 "sync"
13 "unicode" 13 "unicode"
14 "unicode/utf8" 14 "unicode/utf8"
15 ) 15 )
(...skipping 11 matching lines...)
27 // would return the error. 27 // would return the error.
28 // 28 //
29 // You may also pass nil as the error for BreakFeatures, and the fake will 29 // You may also pass nil as the error for BreakFeatures, and the fake will
30 // provide some suitable (but generic) error for those features (like a 30 // provide some suitable (but generic) error for those features (like a
31 // BAD_REQUEST or something like that). 31 // BAD_REQUEST or something like that).
32 type FeatureBreaker interface { 32 type FeatureBreaker interface {
33 BreakFeatures(err error, feature ...string) 33 BreakFeatures(err error, feature ...string)
34 UnbreakFeatures(feature ...string) 34 UnbreakFeatures(feature ...string)
35 } 35 }
36 36
37 // ErrBrokenFeaturesBroken is returned from RunIfNotBroken when BrokenFeatures 37 // ErrBrokenFeaturesBroken is returned from IsBroken when BrokenFeatures itself
38 // itself isn't working correctly. 38 // isn't working correctly.
39 var ErrBrokenFeaturesBroken = errors.New("brokenFeatures: Unable to retrieve cal ler information") 39 var ErrBrokenFeaturesBroken = errors.New("brokenFeatures: Unable to retrieve cal ler information")
40 40
41 // BrokenFeatures implements the FeatureBreaker interface, and is suitable for 41 // BrokenFeatures implements the FeatureBreaker interface, and is suitable for
42 // embedding within a fake service. 42 // embedding within a fake service.
43 type BrokenFeatures struct { 43 type BrokenFeatures struct {
44 lock sync.Mutex 44 lock sync.Mutex
45 45
46 broken map[string]error 46 broken map[string]error
47 47
48 // DefaultError is the default error to return when you call 48 // DefaultError is the default error to return when you call
(...skipping 25 matching lines...)
74 // features back to their original functionality. 74 // features back to their original functionality.
75 func (b *BrokenFeatures) UnbreakFeatures(feature ...string) { 75 func (b *BrokenFeatures) UnbreakFeatures(feature ...string) {
76 b.lock.Lock() 76 b.lock.Lock()
77 defer b.lock.Unlock() 77 defer b.lock.Unlock()
78 78
79 for _, f := range feature { 79 for _, f := range feature {
80 delete(b.broken, f) 80 delete(b.broken, f)
81 } 81 }
82 } 82 }
83 83
84 // RunIfNotBroken is to be called internally by the fake service on every 84 // IsBroken is to be called internally by the fake service on every
85 // publically-facing method. If it returns an error, the fake should return the 85 // publically-facing method. If it returns an error, the fake should return
86 // error. 86 // the error.
87 // 87 //
88 // Example: 88 // Example:
89 // type MyService struct { BrokenFeatures } 89 // type MyService struct { BrokenFeatures }
90 // func (ms *MyService) Thingy() error { 90 // func (ms *MyService) Thingy() error {
91 // if err := ms.RunIfNotBroken(); err != nil { 91 // if err := ms.IsBroken(); err != nil {
92 // return err 92 // return err
93 // } 93 // }
94 // ... 94 // ...
95 // } 95 // }
96 // 96 //
97 // You can now do ms.SetBrokenFeatures("Thingy"), and Thingy will return an 97 // You can now do ms.SetBrokenFeatures("Thingy"), and Thingy will return an
98 // error. 98 // error.
99 // 99 //
100 // Note that RunIfNotBroken will keep walking the stack until it finds the 100 // Note that IsBroken will keep walking the stack until it finds the first
101 // first publically-exported method, which will allow you to put the 101 // publically-exported method, which will allow you to put the IsBroken call
102 // RunIfNotBroken call in an internal helper method of your service 102 // in an internal helper method of your service implementation.
103 // implementation.
104 // 103 //
105 // Additionaly, RunIfNotBroken allows a very primitive form of overriding; it 104 // Additionaly, IsBroken allows a very primitive form of overriding; it walks
106 // walks the stack until it finds the first method which is not called 105 // the stack until it finds the first method which is not called "IsBroken".
107 // "RunIfNotBroken". This allows the embedding struct to call into 106 // This allows the embedding struct to call into BrokenFeatures.IsBroken from
108 // BrokenFeatures.RunIfNotBroken from another RunIfNotBroken function, and 107 // another IsBroken function, and still have it behave correctly.
109 // still have it behave correctly. 108 func (b *BrokenFeatures) IsBroken() error {
110 func (b *BrokenFeatures) RunIfNotBroken(f func() error) error {
111 if b.noBrokenFeatures() { 109 if b.noBrokenFeatures() {
112 » » return f() 110 » » return nil
113 } 111 }
114 112
115 var name string 113 var name string
116 for off := 1; ; off++ { // offset of 1 skips ourselves by default 114 for off := 1; ; off++ { // offset of 1 skips ourselves by default
117 // TODO(riannucci): Profile this to see if it's having an advers e 115 // TODO(riannucci): Profile this to see if it's having an advers e
118 » » // performance impact on tests. 116 » » // performance impact ont tests.
119 fn, _, _, ok := runtime.Caller(off) 117 fn, _, _, ok := runtime.Caller(off)
120 if !ok { 118 if !ok {
121 return ErrBrokenFeaturesBroken 119 return ErrBrokenFeaturesBroken
122 } 120 }
123 toks := strings.Split(runtime.FuncForPC(fn).Name(), ".") 121 toks := strings.Split(runtime.FuncForPC(fn).Name(), ".")
124 name = toks[len(toks)-1] 122 name = toks[len(toks)-1]
125 firstRune, _ := utf8.DecodeRuneInString(name) 123 firstRune, _ := utf8.DecodeRuneInString(name)
126 if !unicode.IsUpper(firstRune) { 124 if !unicode.IsUpper(firstRune) {
127 // unexported method, keep walking till we find the firs t exported 125 // unexported method, keep walking till we find the firs t exported
128 // method. Do !IsUpper, since exported is defined by IsU pper and not 126 // method. Do !IsUpper, since exported is defined by IsU pper and not
129 // !IsLower, and afaik, in unicode-land they're not dire ct opposites. 127 // !IsLower, and afaik, in unicode-land they're not dire ct opposites.
130 continue 128 continue
131 } 129 }
132 » » if name == "RunIfNotBroken" { 130 » » if name == "IsBroken" {
133 » » » // Allow users to override RunIfNotBroken, keep walking until we see 131 » » » // Allow users to override IsBroken, keep walking until we see a function
134 » » » // a function which is named differently than RunIfNotBr oken. 132 » » » // which is named differently than IsBroken.
135 continue 133 continue
136 } 134 }
137 break 135 break
138 } 136 }
139 137
140 b.lock.Lock() 138 b.lock.Lock()
141 err, ok := b.broken[name]
142 defer b.lock.Unlock() 139 defer b.lock.Unlock()
143 140 » if err, ok := b.broken[name]; ok {
144 » if ok {
145 if err != nil { 141 if err != nil {
146 return err 142 return err
147 } 143 }
148 if b.DefaultError != nil { 144 if b.DefaultError != nil {
149 return b.DefaultError 145 return b.DefaultError
150 } 146 }
151 return fmt.Errorf("feature %q is broken", name) 147 return fmt.Errorf("feature %q is broken", name)
152 } 148 }
153 149
154 » return f() 150 » return nil
155 } 151 }
156 152
157 func (b *BrokenFeatures) noBrokenFeatures() bool { 153 func (b *BrokenFeatures) noBrokenFeatures() bool {
158 b.lock.Lock() 154 b.lock.Lock()
159 defer b.lock.Unlock() 155 defer b.lock.Unlock()
160 return len(b.broken) == 0 156 return len(b.broken) == 0
161 } 157 }
OLDNEW
« no previous file with comments | « go/src/infra/gae/libs/meta/eg_test.go ('k') | go/src/infra/gae/libs/wrapper/brokenfeatures_test.go » ('j') | no next file with comments »

Powered by Google App Engine