github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/azure/internal/azuretesting/senders.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package azuretesting 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "net/http" 10 "regexp" 11 "sync" 12 13 "github.com/Azure/go-autorest/autorest" 14 "github.com/Azure/go-autorest/autorest/mocks" 15 "github.com/juju/loggo" 16 ) 17 18 var logger = loggo.GetLogger("juju.provider.azure.internal.azuretesting") 19 20 // MockSender is a wrapper around autorest/mocks.Sender, extending it with 21 // request path checking to ease testing. 22 type MockSender struct { 23 *mocks.Sender 24 25 // PathPattern, if non-empty, is assumed to be a regular expression 26 // that must match the request path. 27 PathPattern string 28 } 29 30 func (s *MockSender) Do(req *http.Request) (*http.Response, error) { 31 if s.PathPattern != "" { 32 matched, err := regexp.MatchString(s.PathPattern, req.URL.Path) 33 if err != nil { 34 return nil, err 35 } 36 if !matched { 37 return nil, fmt.Errorf( 38 "request path %q did not match pattern %q", 39 req.URL.Path, s.PathPattern, 40 ) 41 } 42 } 43 return s.Sender.Do(req) 44 } 45 46 // NewSenderWithValue returns a *mocks.Sender that marshals the provided object 47 // to JSON and sets it as the content. This function will panic if marshalling 48 // fails. 49 func NewSenderWithValue(v interface{}) *MockSender { 50 content, err := json.Marshal(v) 51 if err != nil { 52 panic(err) 53 } 54 sender := &MockSender{Sender: mocks.NewSender()} 55 sender.AppendResponse(mocks.NewResponseWithContent(string(content))) 56 return sender 57 } 58 59 // Senders is a Sender that includes a collection of Senders, which 60 // will be called in sequence. 61 type Senders []autorest.Sender 62 63 func (s *Senders) Do(req *http.Request) (*http.Response, error) { 64 logger.Debugf("Senders.Do(%s)", req.URL) 65 if len(*s) == 0 { 66 response := mocks.NewResponseWithStatus("", http.StatusInternalServerError) 67 return response, fmt.Errorf("no sender for %q", req.URL) 68 } 69 sender := (*s)[0] 70 *s = (*s)[1:] 71 return sender.Do(req) 72 } 73 74 // SerialSender is a Sender that permits only one active Do call 75 // at a time. 76 type SerialSender struct { 77 mu sync.Mutex 78 s autorest.Sender 79 } 80 81 func (s *SerialSender) Do(req *http.Request) (*http.Response, error) { 82 s.mu.Lock() 83 defer s.mu.Unlock() 84 return s.s.Do(req) 85 } 86 87 func NewSerialSender(s autorest.Sender) *SerialSender { 88 return &SerialSender{s: s} 89 }