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  }