github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/testing/fakeapi.go (about)

     1  package testing
     2  
     3  import (
     4  	"crypto/tls"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"net/url"
     8  	"reflect"
     9  
    10  	"github.com/bmizerany/pat"
    11  	"github.com/juju/utils"
    12  	"golang.org/x/net/websocket"
    13  
    14  	"github.com/juju/juju/apiserver/observer/fakeobserver"
    15  	"github.com/juju/juju/rpc"
    16  	"github.com/juju/juju/rpc/jsoncodec"
    17  	"github.com/juju/juju/rpc/rpcreflect"
    18  	"github.com/juju/juju/testing"
    19  )
    20  
    21  // Server represents a fake API server. It must be closed
    22  // after use.
    23  type Server struct {
    24  	// Addrs holds the address used for the
    25  	// server, suitable for including in api.Info.Addrs
    26  	Addrs []string
    27  
    28  	*httptest.Server
    29  	newRoot func(modelUUID string) interface{}
    30  }
    31  
    32  // NewAPIServer serves RPC methods on a localhost HTTP server.
    33  // When a connection is made to the API, the newRoot function
    34  // is called with the requested model UUID and the returned
    35  // value defines the API (see the juju/rpc package).
    36  //
    37  // Note that the root value accepts any facade version number - it
    38  // is not currently possible to use this to serve several different
    39  // facade versions.
    40  //
    41  // The server uses testing.ServerCert and testing.ServerKey
    42  // to host the server.
    43  //
    44  // The returned server must be closed after use.
    45  func NewAPIServer(newRoot func(modelUUID string) interface{}) *Server {
    46  	tlsCert, err := tls.X509KeyPair([]byte(testing.ServerCert), []byte(testing.ServerKey))
    47  	if err != nil {
    48  		panic("bad key pair")
    49  	}
    50  
    51  	srv := &Server{
    52  		newRoot: newRoot,
    53  	}
    54  	pmux := pat.New()
    55  	pmux.Get("/model/:modeluuid/api", http.HandlerFunc(srv.serveAPI))
    56  
    57  	srv.Server = httptest.NewUnstartedServer(pmux)
    58  
    59  	tlsConfig := utils.SecureTLSConfig()
    60  	tlsConfig.Certificates = []tls.Certificate{tlsCert}
    61  	srv.Server.TLS = tlsConfig
    62  
    63  	srv.StartTLS()
    64  	u, _ := url.Parse(srv.URL)
    65  	srv.Addrs = []string{u.Host}
    66  	return srv
    67  }
    68  
    69  func (srv *Server) serveAPI(w http.ResponseWriter, req *http.Request) {
    70  	wsServer := websocket.Server{
    71  		Handler: func(conn *websocket.Conn) {
    72  			srv.serveConn(conn, req.URL.Query().Get(":modeluuid"))
    73  		},
    74  	}
    75  	wsServer.ServeHTTP(w, req)
    76  }
    77  
    78  func (srv *Server) serveConn(wsConn *websocket.Conn, modelUUID string) {
    79  	codec := jsoncodec.NewWebsocket(wsConn)
    80  	conn := rpc.NewConn(codec, &fakeobserver.Instance{})
    81  
    82  	root := allVersions{
    83  		rpcreflect.ValueOf(reflect.ValueOf(srv.newRoot(modelUUID))),
    84  	}
    85  	conn.ServeRoot(root, nil)
    86  	conn.Start()
    87  	<-conn.Dead()
    88  	conn.Close()
    89  }
    90  
    91  // allVersions serves the same methods as would be served
    92  // by rpc.Conn.Serve except that the facade version is ignored.
    93  type allVersions struct {
    94  	rpcreflect.Value
    95  }
    96  
    97  func (av allVersions) FindMethod(rootMethodName string, version int, objMethodName string) (rpcreflect.MethodCaller, error) {
    98  	return av.Value.FindMethod(rootMethodName, 0, objMethodName)
    99  }