Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

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

Issue 1151473003: Better attempt at an appengine wrapper. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: better typecheck Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 package wrapper
6
7 import (
8 "errors"
9 "runtime"
10 "strings"
11 "sync"
12 "unicode"
13 "unicode/utf8"
14 )
15
16 // FeatureBreaker allows a fake implementation to set and unset broken features.
17 // A feature is the Name of some method on the fake. So if you had:
18 // var fake interface{ FeatureBreaker, MCSingleReadWriter } = ...
19 //
20 // you could do:
21 // fake.BreakFeatures(memcache.ErrServerError, "Add", "Set")
22 //
23 // and then
24 // fake.Add(...) and fake.Set(...)
25 //
26 // would return the error.
27 //
28 // You may also pass nil as the error for BreakFeatures, and the fake will
29 // provide some suitable (but generic) error for those features (like a
30 // BAD_REQUEST or something like that).
31 type FeatureBreaker interface {
32 BreakFeatures(err error, feature ...string)
33 UnbreakFeatures(feature ...string)
34 }
35
36 // ErrBrokenFeaturesBroken is returned from IsBroken when BrokenFeatures itself
37 // isn't working correctly.
38 var ErrBrokenFeaturesBroken = errors.New("brokenFeatures: Unable to retrieve cal ler information")
39
40 // BrokenFeatures implements the FeatureBreaker interface, and is suitable for
41 // embedding within a fake service.
42 type BrokenFeatures struct {
43 lock sync.Mutex
44
45 broken map[string]error
46 dfltErr error
47 }
48
49 // NewBrokenFeatures creates an embeddable *BrokenFeatures which is set to
50 // return err for a given broken feature.
51 func NewBrokenFeatures(err error) *BrokenFeatures {
M-A Ruel 2015/05/27 00:27:11 I still think this function is unneeded.
iannucci 2015/05/27 02:40:56 Removed, made dfltErr exported
52 return &BrokenFeatures{broken: map[string]error{}, dfltErr: err}
53 }
54
55 // initLocked makes sure the map is allocated, in case the user decided to
56 // do &BrokenFeatures{} themselves.
57 func (b *BrokenFeatures) initLocked() {
58 if b.broken == nil {
59 b.broken = map[string]error{}
60 }
61 }
62
63 // BreakFeatures allows you to specify an MCSingleReadWriter function name
64 // to cause it to return memcache.ErrServerError. e.g.
65 //
66 // m.SetBrokenFeatures("Add")
67 //
68 // would return memcache.ErrServerError. You can reverse this by calling
69 // UnbreakFeatures("Add").
70 func (b *BrokenFeatures) BreakFeatures(err error, feature ...string) {
71 b.lock.Lock()
72 defer b.lock.Unlock()
73 b.initLocked()
M-A Ruel 2015/05/27 00:27:11 Inline initLocked here since it's now the only cal
iannucci 2015/05/27 02:40:56 done
74
75 for _, f := range feature {
76 b.broken[f] = err
77 }
78 }
79
80 // UnbreakFeatures is the inverse of BreakFeatures, and will return the named
81 // features back to their original functionality.
82 func (b *BrokenFeatures) UnbreakFeatures(feature ...string) {
83 b.lock.Lock()
84 defer b.lock.Unlock()
85 b.initLocked()
M-A Ruel 2015/05/27 00:27:11 It's not needed, delete(nil, ...) works, e.g. http
iannucci 2015/05/27 02:40:57 cool, done
86
87 for _, f := range feature {
88 delete(b.broken, f)
89 }
90 }
91
92 // IsBroken is to be called internally by the fake service on every
93 // publically-facing method. If it returns an error, the fake should return
94 // the error.
95 //
96 // Example:
97 // type MyService struct { *BrokenFeatures }
98 // func (ms *MyService) Thingy() error {
99 // if err := ms.IsBroken(); err != nil {
100 // return err
101 // }
102 // ...
103 // }
104 //
105 // You can now do ms.SetBrokenFeatures("Thingy"), and Thingy will return an
106 // error.
107 //
108 // Note that IsBroken will keep walking the stack until it finds the first
109 // publically-exported method, which will allow you to put the IsBroken call
110 // in an internal helper method of your service implementation.
111 //
112 // Additionaly, IsBroken allows a very primitive form of overriding; it walks
113 // the stack until it finds the first method which is not called "IsBroken".
114 // This allows the embedding struct to call into BrokenFeatures.IsBroken from
115 // another IsBroken function, and still have it behave correctly.
116 func (b *BrokenFeatures) IsBroken() error {
117 b.lock.Lock()
118 defer b.lock.Unlock()
119 b.initLocked()
M-A Ruel 2015/05/27 00:27:11 it's not needed here.
iannucci 2015/05/27 02:40:56 done
120
121 if len(b.broken) == 0 {
122 return nil
123 }
124 off := 1 // offset of 1 skips ourselves by default
125
126 for {
M-A Ruel 2015/05/27 00:27:11 for off := 1; ; off++ {
iannucci 2015/05/27 02:40:57 done
127 // TODO(riannucci): Profile this to see if it's having an advers e
128 // performance impact ont tests.
129 fn, _, _, ok := runtime.Caller(off)
130 if !ok {
131 return ErrBrokenFeaturesBroken
132 }
133 toks := strings.Split(runtime.FuncForPC(fn).Name(), ".")
134 name := toks[len(toks)-1]
135 firstRune, _ := utf8.DecodeRuneInString(name)
136 if !unicode.IsUpper(firstRune) {
137 // unexported method, keep walking till we find the firs t exported
138 // method. Do !IsUpper, since exported is defined by IsU pper and not
139 // !IsLower, and afaik, in unicode-land they're not dire ct opposites.
140 off++
M-A Ruel 2015/05/27 00:27:11 remove
iannucci 2015/05/27 02:40:56 done
141 continue
142 }
143 if name == "IsBroken" {
144 // Allow users to override IsBroken, keep walking until we see a function
145 // which is named differently than IsBroken.
146 off++
M-A Ruel 2015/05/27 00:27:11 remove
iannucci 2015/05/27 02:40:57 done
147 continue
148 }
149 if err, ok := b.broken[name]; ok {
150 if err != nil {
151 return err
152 }
153 return b.dfltErr
154 }
155 break
156 }
157
158 return nil
159 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698