Work on mock server.
diff --git a/README.md b/README.md
index 134b6bd..86cfed4 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
 # Istio Apigee Adapter
 
 This workspace holds an apigee adapter for Istio.
+
+## Installation
+
+In order to use this, right now, you need a build of Istio
\ No newline at end of file
diff --git a/WORKSPACE b/WORKSPACE
index c29e9ff..a7ddb8c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -45,6 +45,13 @@
     importpath = "github.com/golang/protobuf",
 )
 
+new_git_repository(
+    name = "com_github_googleapis_googleapis",
+    build_file = "bazel/BUILD.googleapis",
+    commit = "13ac2436c5e3d568bd0e938f6ed58b77a48aba15",
+    remote = "https://github.com/googleapis/googleapis.git",
+)
+
 new_go_repository(
     name = "com_github_hashicorp_go_multierror",
     commit = "ed905158d87462226a13fe39ddf685ea65f1c11f",
@@ -57,9 +64,8 @@
     importpath = "github.com/hashicorp/errwrap",
 )
 
-new_git_repository(
-    name = "com_github_googleapis_googleapis",
-    build_file = "bazel/BUILD.googleapis",
-    commit = "13ac2436c5e3d568bd0e938f6ed58b77a48aba15",
-    remote = "https://github.com/googleapis/googleapis.git",
-)
\ No newline at end of file
+new_go_repository(
+    name = "com_github_julienschmidt_httprouter",
+    commit = "975b5c4c7c21c0e3d2764200bf2aa8e34657ae6e",
+    importpath = "github.com/julienschmidt/httprouter"
+)
diff --git a/common/BUILD b/common/BUILD
new file mode 100644
index 0000000..5c09cc7
--- /dev/null
+++ b/common/BUILD
@@ -0,0 +1,12 @@
+package(default_visibility = ["//visibility:public"])
+
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+    name = "go_default_library",
+    srcs = [
+        "types.go",
+    ],
+    deps = [
+    ],
+)
diff --git a/common/types.go b/common/types.go
new file mode 100644
index 0000000..da90279
--- /dev/null
+++ b/common/types.go
@@ -0,0 +1,25 @@
+package common
+
+type Attribute struct {
+	Name string `json:"name"`
+	Value string `json:"value"`
+}
+
+type APIProduct struct {
+	APIResources []string `json:"apiResources"`
+	ApprovalType string `json:"approvalType"`
+	Attributes []Attribute `json:"attributes"`
+	CreatedAt int64 `json:"createdAt"`
+	CreatedBy string `json:"createdBy"`
+	Description string `json:"description"`
+	DisplayName string `json:"displayName"`
+	Environments []string `json:"environments"`
+	LastModifiedAt int64 `json:"lastModifiedAt"`
+	LastModifiedBy string `json:"lastModifiedBy"`
+	Name string `json:"name"`
+	Proxies []string `json:"proxies"`
+	Quota string `json:"quota"`
+	QuotaInterval string `json:"quotaInterval"`
+	QuotaTimeUnit string `json:"quotaTimeUnit"`
+	Scopes []string `json:"scopes"`
+}
diff --git a/mock/BUILD b/mock/BUILD
new file mode 100644
index 0000000..84be835
--- /dev/null
+++ b/mock/BUILD
@@ -0,0 +1,24 @@
+package(default_visibility = ["//visibility:public"])
+
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+    name = "go_default_library",
+    srcs = [
+        "keys.go",
+        "mockserver.go",
+    ],
+    deps = [
+        "//common:go_default_library",
+        "@com_github_julienschmidt_httprouter//:go_default_library",
+    ],
+)
+
+go_test(
+    name = "small_tests",
+    size = "small",
+    srcs = [
+        "mockserver_test.go",
+    ],
+    library = ":go_default_library",
+)
diff --git a/mock/keys.go b/mock/keys.go
new file mode 100644
index 0000000..d5170cf
--- /dev/null
+++ b/mock/keys.go
@@ -0,0 +1,55 @@
+package mock
+
+import (
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"time"
+	"encoding/pem"
+	"math/big"
+)
+
+var mockKeyPEM, mockCertPEM []byte
+
+func makeKeys() {
+	key, err := rsa.GenerateKey(rand.Reader, 2048)
+	if err != nil {
+		panic(err.Error())
+	}
+
+	mockKeyPEM = pem.EncodeToMemory(&pem.Block{
+		Type: "RSA PRIVATE KEY",
+		Bytes: x509.MarshalPKCS1PrivateKey(key),
+	})
+
+	templ := makeCertTemplate()
+
+	certBytes, err := x509.CreateCertificate(rand.Reader, templ, templ, key.Public(), key)
+	if err != nil {
+		panic(err.Error())
+	}
+
+	mockCertPEM = pem.EncodeToMemory(&pem.Block{
+		Type: "CERTIFICATE",
+		Bytes: certBytes,
+	})
+}
+
+func makeCertTemplate() *x509.Certificate {
+	now := time.Now()
+
+	return &x509.Certificate{
+		SerialNumber: big.NewInt(1),
+		Subject: pkix.Name{
+			Country: []string{"US"},
+			Organization: []string{"Google"},
+			OrganizationalUnit: []string{"Cloud"},
+			Locality: []string{"Mountain View"},
+			Province: []string{"CA"},
+			CommonName: "mockserver",
+		},
+		NotBefore: now,
+		NotAfter: now.Add(time.Hour),
+	}
+}
\ No newline at end of file
diff --git a/mock/mockserver.go b/mock/mockserver.go
new file mode 100644
index 0000000..1d4392d
--- /dev/null
+++ b/mock/mockserver.go
@@ -0,0 +1,88 @@
+package mock
+
+import (
+	"fmt"
+	"net"
+	"net/http"
+	"sync"
+	"encoding/json"
+	"time"
+	"github.com/julienschmidt/httprouter"
+	"github.com/apid/istioApigeeAdapter/common"
+)
+
+var mockInit = &sync.Once{}
+
+type MockServer struct {
+	listener net.Listener
+}
+
+func StartMockServer(port int) (*MockServer, error) {
+	mockInit.Do(makeKeys)
+
+	l, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
+	if err != nil {
+		return nil, err
+	}
+
+	ms := &MockServer{
+		listener: l,
+	}
+
+  router := httprouter.New()
+	router.GET("/publicKey", ms.getPublicKey)
+	router.GET("/products", ms.getProducts)
+
+	go func() {
+		http.Serve(l, router)
+	}()
+
+	return ms, nil
+}
+
+func (m *MockServer) Address() string {
+	return m.listener.Addr().String()
+}
+
+func (m *MockServer) Stop() {
+	m.listener.Close()
+}
+
+func (m *MockServer) getPublicKey(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+	w.Header().Set("content-type", "text/plain")
+	w.Write(mockCertPEM)
+}
+
+func (m *MockServer) getProducts(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+	now := time.Now()
+	p := []common.APIProduct{
+		{
+			Name: "First",
+			DisplayName: "First Product",
+			Description: "First test product",
+			CreatedAt: now.UnixNano(),
+			CreatedBy: "foo@bar.com",
+			LastModifiedAt: now.UnixNano(),
+			LastModifiedBy: "foo@bar.com",
+
+			APIResources: []string{"/**"},
+			ApprovalType: "auto",
+			Attributes: []common.Attribute{
+				{
+					Name: "access",
+					Value: "public",
+				},
+			},
+			Environments: []string{"test", "prod"},
+			Proxies: []string{"ProxyOne"},
+			Quota: "10",
+			QuotaInterval: "1",
+			QuotaTimeUnit: "minute",
+		},
+	}
+
+	w.Header().Set("content-type", "application/json")
+
+	enc := json.NewEncoder(w)
+	enc.Encode(p)
+}
\ No newline at end of file
diff --git a/mock/mockserver_test.go b/mock/mockserver_test.go
new file mode 100644
index 0000000..8f8fd23
--- /dev/null
+++ b/mock/mockserver_test.go
@@ -0,0 +1,88 @@
+package mock
+
+import (
+	"fmt"
+	"net/http"
+	"os"
+	"testing"
+	"encoding/pem"
+	"encoding/json"
+	"io/ioutil"
+	"crypto/x509"
+	"github.com/apid/istioApigeeAdapter/common"
+)
+
+var testMockServer *MockServer
+
+func TestMain(m *testing.M) {
+	var err error
+	testMockServer, err = StartMockServer(0)
+	if err != nil {
+		panic(err.Error())
+	}
+
+	result := m.Run()
+	testMockServer.Stop()
+	os.Exit(result)
+}
+
+func TestServerSanity(t *testing.T) {
+	if mockKeyPEM == nil {
+		t.Fatal("Expected mock key to be generated")
+	}
+	if mockCertPEM == nil {
+		t.Fatal("Expected mock cert to be generated")
+	}
+}
+
+func TestPublicKey(t *testing.T) {
+	resp, err := http.Get(fmt.Sprintf("http://%s/publicKey", testMockServer.Address()))
+	if err != nil {
+		t.Fatalf("Network error: %s", err)
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != 200 {
+		t.Fatalf("Got HTTP status code %d", resp.StatusCode)
+	}
+
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		t.Fatalf("Error reading body: %s", err)
+	}
+	pb, _ := pem.Decode(body)
+	if pb == nil {
+		t.Fatalf("Failed decoding public key body \"%s\"", string(body))
+	}
+	if pb.Type != "CERTIFICATE" {
+		t.Fatalf("Got back invalid PEM type %s", pb.Type)
+	}
+
+	cert, err := x509.ParseCertificate(pb.Bytes)
+	if err != nil {
+		t.Fatalf("Error decoding certificate: %s", err)
+	}
+	if cert.Subject.CommonName != "mockserver" {
+		t.Fatalf("Common name does not match \"mockserver\": \"%s\"", cert.Subject.CommonName)
+	}
+}
+
+func TestProducts(t *testing.T) {
+	resp, err := http.Get(fmt.Sprintf("http://%s/products", testMockServer.Address()))
+	if err != nil {
+		t.Fatalf("Network error: %s", err)
+	}
+	defer resp.Body.Close()
+	if resp.StatusCode != 200 {
+		t.Fatalf("Got HTTP status code %d", resp.StatusCode)
+	}
+	if resp.Header.Get("content-type") != "application/json" {
+		t.Fatalf("Invalid content typs %s", resp.Header.Get("content-type"))
+	}
+
+	dec := json.NewDecoder(resp.Body)
+	var products []common.APIProduct
+	err = dec.Decode(&products)
+	if err != nil {
+		t.Fatalf("Error decoding response json: %s", err)
+	}
+}
\ No newline at end of file