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

Unified Diff: go/src/infra/gae/libs/wrapper/featurebreaker.go

Issue 1151473003: Better attempt at an appengine wrapper. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: pointer! Created 5 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: go/src/infra/gae/libs/wrapper/featurebreaker.go
diff --git a/go/src/infra/gae/libs/wrapper/featurebreaker.go b/go/src/infra/gae/libs/wrapper/featurebreaker.go
new file mode 100644
index 0000000000000000000000000000000000000000..aec58ba68ea7d5ad42c402299694efa541b6506a
--- /dev/null
+++ b/go/src/infra/gae/libs/wrapper/featurebreaker.go
@@ -0,0 +1,110 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package wrapper
+
+import (
+ "runtime"
+ "strings"
+ "sync"
+)
+
+// FeatureBreaker allows a fake implementation to set and unset broken features.
+// A feature is the Name of some method on the fake. So if you had:
+// var fake interface{ FeatureBreaker, MCSingleReadWriter } = ...
+//
+// you could do:
+// fake.SetBrokenFeatures("Add", "Set")
+//
+// and then
+// fake.Add(...) and fake.Set(...)
+//
+// would return an error (likely memcache.ErrServerError in this case), as if
+// the service were disconnected or broken.
+type FeatureBreaker interface {
+ SetBrokenFeatures(feature ...string)
+ UnsetBrokenFeatures(feature ...string)
M-A Ruel 2015/05/25 17:14:51 UnbreakFeatures() ?
iannucci 2015/05/26 18:25:06 And BreakFeatures? sgtm.
+}
+
+// BrokenFeatures implements the FeatureBreaker interface, and is suitable for
+// embedding within a fake service.
+type BrokenFeatures struct {
+ lock sync.Mutex
+
+ broken map[string]struct{}
M-A Ruel 2015/05/25 17:14:51 broken map[string]bool or much better: broken ma
iannucci 2015/05/26 18:25:06 I thought map[string]struct{} was better because s
+ err error
+}
+
+// NewBrokenFeatures creates an embeddable *BrokenFeatures which is set to
+// return err for a given broken feature.
+func NewBrokenFeatures(err error) *BrokenFeatures {
+ return &BrokenFeatures{broken: map[string]struct{}{}, err: err}
+}
+
+// SetBrokenFeatures allows you to specify an MCSingleReadWriter function name
+// to cause it to return memcache.ErrServerError. e.g.
+//
+// m.SetBrokenFeatures("Add")
+//
+// would return memcache.ErrServerError. You can reverse this by calling
+// UnsetBrokenFeatures("Add").
+func (b *BrokenFeatures) SetBrokenFeatures(feature ...string) {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+ for _, f := range feature {
M-A Ruel 2015/05/25 17:14:51 it'd be good to add a check: if b.broken == nil {
iannucci 2015/05/26 18:25:06 good point, added initLocked().
+ b.broken[f] = struct{}{}
M-A Ruel 2015/05/25 17:14:51 b.broken[f] = true is faster.
iannucci 2015/05/26 18:25:06 did the error map. Also, do you have benchmarks h
+ }
+}
+
+// UnsetBrokenFeatures is the inverse of SetBrokenFeatures.
+func (b *BrokenFeatures) UnsetBrokenFeatures(feature ...string) {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+ for _, f := range feature {
+ delete(b.broken, f)
+ }
+}
+
+// IsBroken is to be called internally by the fake service on every
+// publically-facing method. If it returns an error, the fake should return
+// the error.
+//
+// Example:
+// type MyService struct { *BrokenFeatures }
+// func (ms *MyService) Thingy() error {
+// if err := ms.IsBroken(); err != nil {
+// return err
+// }
+// ...
+// }
+//
+// You can now do ms.SetBrokenFeatures("Thingy"), and Thingy will return an
+// error.
+func (b *BrokenFeatures) IsBroken() error {
+ b.lock.Lock()
+ defer b.lock.Unlock()
+ if len(b.broken) == 0 {
+ return nil
+ }
+ off := 1
+
+ for {
+ fn, _, _, _ := runtime.Caller(off)
+ name := runtime.FuncForPC(fn).Name()
+ toks := strings.Split(name, ".")
M-A Ruel 2015/05/25 17:14:51 toks := strings.Split(runtime.FuncForPC(fn).Name()
iannucci 2015/05/26 18:25:06 ew gross, good catch.
+ name = toks[len(toks)-1]
+ if name == "IsBroken" {
+ // Allow users to override IsBroken
M-A Ruel 2015/05/25 17:14:51 This should be in docstring then.
iannucci 2015/05/26 18:25:06 done
+ // ITS MAGIC!!!!!
+ off++
+ continue
+ }
+ if _, ok := b.broken[name]; ok {
M-A Ruel 2015/05/25 17:14:51 I don't like that it's not checking the package. I
iannucci 2015/05/26 18:25:06 Discussed in chat, it's not exactly clear what to
+ return b.err
+ }
+ break
+ }
+
+ return nil
+}

Powered by Google App Engine
This is Rietveld 408576698