blob: 010a6c92fb9177b3b9b17f4fd12559b10be01466 [file] [log] [blame]
// Copyright 2021 Google LLC
//
// 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 configfetcher
import (
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
// isValidMetadataRequest is a generic helper function to verify that the
// request matches the spec set by GCE metadata service and supports the
// behavior specified in the MetadataRetriever implementation.
func isValidMetadataRequest(r *http.Request) error {
// Check the request is a GET request.
if r.Method != "GET" {
return fmt.Errorf("got a %s request, want GET request",
r.Method)
}
// Check request contains the right headers.
if _, ok := r.Header[requestHeaderKey]; !ok {
return fmt.Errorf("missing %s header", requestHeaderKey)
}
return nil
}
// TestGetEntry tests that the getEntry function for the following things:
// - makes a GET request with the required headers
// - raises an error if the status code is not 200
// - returns the correct response from the server
// - returns the correct etag from the server
func TestGetEntry(t *testing.T) {
tests := []struct {
name string
entry string
expectResponse string
expectErr bool
expectEtag string
}{
{
"InstanceCustomMetaData",
instanceCustomDataDirectory,
`{
"key1": "value1",
"key2": "value2"
}`,
false,
"myEtag",
},
{
"ServerError",
instanceCustomDataDirectory,
"",
true,
"",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// Set up a test server.
handler := func(w http.ResponseWriter, r *http.Request) {
if test.expectErr {
w.WriteHeader(http.StatusInternalServerError)
return
}
if err := isValidMetadataRequest(r); err != nil {
t.Errorf("unexpected err: %v", err)
}
w.Header().Set("etag", test.expectEtag)
fmt.Fprint(w, test.expectResponse)
}
ts := httptest.NewServer(http.HandlerFunc(handler))
resp, etag, err := getEntry(test.entry, ts.URL)
if err != nil {
if !test.expectErr {
t.Errorf("got unexpected error %v", err)
}
} else {
if test.expectErr {
t.Errorf("got %s, want error", string(resp))
} else {
if string(resp) != test.expectResponse {
t.Errorf("got %s, want %s", string(resp), test.expectResponse)
}
if etag != test.expectEtag {
t.Errorf("got etag %s, want %s", etag, test.expectEtag)
}
}
}
})
}
}
// TestFetchMetadata tests that the retriever implementation correctly fetches
// the content of instance custom metadata directory.
func TestFetchMetadata(t *testing.T) {
// Dummy key-value pairs.
dummyMap := map[string]string{
"key1": "val1",
"key2": "val2",
"key3": "\t val3 \n ",
}
tests := []struct {
name string
lastEtag string
expectResponse string
expectEtag string
expectErr bool
}{
{
"InstanceCustomMetadataWait",
"lastEtag",
dummyMap["key1"],
"myEtag1",
false,
},
{
"InstanceCustomMetadataNoWait",
"",
dummyMap["key2"],
"myEtag2",
false,
},
{
"InstanceCustomMetadataWhitespaces",
"",
dummyMap["key3"],
"myEtag3",
false,
},
{
"InstanceCustomDataServerError",
"",
"",
"",
true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// Set up a test server.
handler := func(w http.ResponseWriter, r *http.Request) {
if test.expectErr {
w.WriteHeader(http.StatusInternalServerError)
return
}
if err := isValidMetadataRequest(r); err != nil {
t.Errorf("Test %s: %v", test.name, err)
}
// Make sure the request is for the directory.
if r.URL.Path != instanceCustomDataDirectory {
t.Errorf("got URL path %s, want %s",
r.URL.Path,
instanceCustomDataDirectory)
}
expectedQuery := "recursive=true"
if test.lastEtag != "" {
expectedQuery += "&wait_for_change=true&last_etag=" + test.lastEtag
}
if r.URL.RawQuery != expectedQuery {
t.Errorf("got HTTP request query %s, want %s",
r.URL.RawQuery,
expectedQuery)
}
w.Header().Set("etag", test.expectEtag)
fmt.Fprint(w, test.expectResponse)
}
ts := httptest.NewServer(http.HandlerFunc(handler))
resp, etag, err := FetchMetadata(test.lastEtag, ts.URL)
if err != nil {
if !test.expectErr {
t.Errorf("got unexpected error %v", err)
}
} else {
if test.expectErr {
t.Errorf("got %s, want error", resp)
} else {
if resp != strings.TrimSpace(test.expectResponse) {
t.Errorf("got %v, want %v", resp, test.expectResponse)
}
if etag != test.expectEtag {
t.Errorf("got etag %s, want %s", etag, test.expectEtag)
}
}
}
})
}
}