blob: e37ee26c6b733c0a09273456b7f0d8df013a7f6c [file] [log] [blame]
/*
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mock
import (
"bytes"
"compress/gzip"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"io/ioutil"
"net/http"
"os"
"testing"
"time"
"io"
"github.com/SermoDigital/jose/jws"
"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)
}
}
func TestAPIKeyWrongFormat(t *testing.T) {
req := common.VerifyAPIKeyRequest{}
requestBod, _ := json.Marshal(&req)
resp, err := http.DefaultClient.Post(
fmt.Sprintf("http://%s/verifyApiKey", testMockServer.Address()),
"text/plain",
bytes.NewBuffer(requestBod))
if err != nil {
t.Fatalf("Network error: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 404 {
t.Fatalf("Got HTTP status code %d -- expected 404", resp.StatusCode)
}
}
func TestAPIKeyNotJSON(t *testing.T) {
resp, err := http.DefaultClient.Post(
fmt.Sprintf("http://%s/verifyApiKey", testMockServer.Address()),
"application/json",
bytes.NewBuffer([]byte("Hello!")))
if err != nil {
t.Fatalf("Network error: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 500 {
t.Fatalf("Got HTTP status code %d -- expected 500", resp.StatusCode)
}
}
func TestAPIKeyNoKey(t *testing.T) {
req := common.VerifyAPIKeyRequest{}
requestBod, _ := json.Marshal(&req)
resp, err := http.DefaultClient.Post(
fmt.Sprintf("http://%s/verifyApiKey", testMockServer.Address()),
"application/json",
bytes.NewBuffer(requestBod))
if err != nil {
t.Fatalf("Network error: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 404 {
t.Fatalf("Got HTTP status code %d -- expected 404", resp.StatusCode)
}
}
func TestAPIKeyBadKey(t *testing.T) {
req := common.VerifyAPIKeyRequest{
Key: "foobar",
}
requestBod, _ := json.Marshal(&req)
resp, err := http.DefaultClient.Post(
fmt.Sprintf("http://%s/verifyApiKey", testMockServer.Address()),
"application/json",
bytes.NewBuffer(requestBod))
if err != nil {
t.Fatalf("Network error: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 404 {
t.Fatalf("Got HTTP status code %d -- expected 404", resp.StatusCode)
}
}
func TestAPIKeySuccess(t *testing.T) {
req := common.VerifyAPIKeyRequest{
Key: ValidAPIKey1,
}
requestBod, _ := json.Marshal(&req)
resp, err := http.DefaultClient.Post(
fmt.Sprintf("http://%s/verifyApiKey", testMockServer.Address()),
"application/json",
bytes.NewBuffer(requestBod))
if err != nil {
t.Fatalf("Network error: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Fatalf("Got HTTP status code %d -- expected 200", resp.StatusCode)
}
var respBody common.VerifyAPIKeyResponse
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&respBody)
if err != nil {
t.Fatalf("Error reading JSON response: %s", err)
}
_, err = jws.ParseJWT([]byte(respBody.Token))
if err != nil {
t.Fatalf("Error parsing JWT: %s", err)
}
}
func TestAxPublishBadJSON(t *testing.T) {
resp, err := sendAnalytics([]byte("NOTJSON"), "application/json",
ValidPublishKey, ValidPublishSecret, false)
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 500 {
t.Fatalf("Got status code %d and expected 500", resp.StatusCode)
}
}
func TestAxPublishNotJSON(t *testing.T) {
resp, err := sendAnalytics([]byte("{}"), "text/plain",
ValidPublishKey, ValidPublishSecret, false)
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Fatalf("Got status code %d and expected 200", resp.StatusCode)
}
var respBody common.AnalyticsResponse
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&respBody)
if err != nil {
t.Fatalf("Error reading JSON response: %s", err)
}
if respBody.Accepted != 0 {
t.Fatalf("%d records were accepted", respBody.Accepted)
}
if respBody.Rejected != 1 {
t.Fatalf("%d records were rejected", respBody.Rejected)
}
}
func TestAxPublishEmpty(t *testing.T) {
resp, err := sendAnalytics([]byte("{}"), "application/json",
ValidPublishKey, ValidPublishSecret, false)
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Fatalf("Got status code %d and expected 200", resp.StatusCode)
}
var respBody common.AnalyticsResponse
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&respBody)
if err != nil {
t.Fatalf("Error reading JSON response: %s", err)
}
if respBody.Accepted != 0 {
t.Fatalf("%d records were accepted", respBody.Accepted)
}
if respBody.Rejected != 0 {
t.Fatalf("%d records were rejected", respBody.Rejected)
}
}
func TestAxPublishWrongUser(t *testing.T) {
resp, err := sendAnalytics([]byte("{}"), "application/json",
"NOTVALID", ValidPublishSecret, false)
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 401 {
t.Fatalf("Got status code %d and expected 401", resp.StatusCode)
}
}
func TestAxPublishWrongPW(t *testing.T) {
resp, err := sendAnalytics([]byte("{}"), "application/json",
ValidPublishKey, "NOPE", false)
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 401 {
t.Fatalf("Got status code %d and expected 401", resp.StatusCode)
}
}
func TestAxPublishNoAuth(t *testing.T) {
resp, err := http.Post(
fmt.Sprintf("http://%s/edgemicro/axpublisher/organization/foo/environment/test", testMockServer.Address()),
"application/json", bytes.NewReader([]byte("{}")))
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 401 {
t.Fatalf("Got status code %d and expected 401", resp.StatusCode)
}
}
func TestAxPublishCompressed(t *testing.T) {
requestBod, err := json.Marshal(makeRequest(10))
if err != nil {
t.Fatalf("Error making JSON: %s", err)
}
resp, err := sendAnalytics(requestBod, "application/json",
ValidPublishKey, ValidPublishSecret, true)
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Fatalf("Got status code %d", resp.StatusCode)
}
var respBody common.AnalyticsResponse
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&respBody)
if err != nil {
t.Fatalf("Error reading JSON response: %s", err)
}
if respBody.Accepted != 10 {
t.Fatalf("Only %d record accepted", respBody.Accepted)
}
if respBody.Rejected != 0 {
t.Fatalf("%d records were rejected", respBody.Rejected)
}
}
func sendAnalytics(body []byte, contentType, user, pw string, compress bool) (*http.Response, error) {
var bod io.Reader
if compress {
bb := &bytes.Buffer{}
zw := gzip.NewWriter(bb)
zw.Write(body)
zw.Close()
bod = bb
} else {
bod = bytes.NewBuffer(body)
}
req, err := http.NewRequest(
"POST",
fmt.Sprintf("http://%s/edgemicro/axpublisher/organization/foo/environment/test", testMockServer.Address()),
bod)
if err != nil {
return nil, err
}
req.Header.Set("content-type", contentType)
if compress {
req.Header.Set("content-encoding", "gzip")
}
req.SetBasicAuth(user, pw)
return http.DefaultClient.Do(req)
}
func TestRegionCheck(t *testing.T) {
req, err := http.NewRequest(
"GET",
fmt.Sprintf("http://%s/edgemicro/region/organization/foo/environment/test", testMockServer.Address()),
nil)
if err != nil {
t.Fatal("Can't make request")
}
req.SetBasicAuth(ValidPublishKey, ValidPublishSecret)
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Fatalf("Got status code %d", resp.StatusCode)
}
var rr common.RegionResponse
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&rr)
if err != nil {
t.Fatalf("Error reading JSON response: %s", err)
}
if rr.Host != testMockServer.Address() {
t.Fatalf("Invalid host response %s", rr.Host)
}
}
func TestRegionCheckNoAuth(t *testing.T) {
req, err := http.NewRequest(
"GET",
fmt.Sprintf("http://%s/edgemicro/region/organization/foo/environment/test", testMockServer.Address()),
nil)
if err != nil {
t.Fatal("Can't make request")
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("Network error sending request: %s", err)
}
defer resp.Body.Close()
if resp.StatusCode != 401 {
t.Fatalf("Got status code %d", resp.StatusCode)
}
}
func makeRequest(numRecords int) *common.AnalyticsRequest {
var recs []common.AnalyticsRecord
for i := 0; i < numRecords; i++ {
now := time.Now().UnixNano() / 1000000
nr := common.AnalyticsRecord{
ClientReceivedStartTimestamp: now,
ClientReceivedEndTimestamp: now + 1,
ClientSentStartTimestamp: now + 10,
ClientSentEndTimestamp: now + 11,
RecordType: "APIAnalytics",
APIProxy: "helloworld",
RequestURI: "http://hello/world",
RequestPath: "/world",
RequestVerb: "GET",
ClientIP: "192.168.201.100",
UserAgent: "Testing",
APIProxyRevision: 1,
ResponseStatusCode: 200,
}
recs = append(recs, nr)
}
return &common.AnalyticsRequest{
Records: recs,
}
}