1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
package testutil
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"reflect"
"regexp"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/jarcoal/httpmock"
"golang.org/x/oauth2"
)
var validTestAPIKey = "NOTANAPIKEY"
func MockRequestURL(path string) *regexp.Regexp {
return regexp.MustCompile(fmt.Sprintf("/[a-zA-Z0-9]+/%s", strings.TrimPrefix(path, "/")))
}
func MockRequestBodyValidate(t *testing.T, expected any, response any) httpmock.Responder {
t.Helper()
return func(request *http.Request) (*http.Response, error) {
eType := reflect.TypeOf(expected)
result := reflect.New(eType)
i := result.Interface()
data, err := io.ReadAll(request.Body)
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(data, &i); err != nil {
t.Fatal(err)
}
// Deref the pointer if necessary
if result.Kind() == reflect.Pointer {
result = result.Elem()
}
resultValue := result.Interface()
if !reflect.DeepEqual(expected, resultValue) {
t.Fatalf("request body does not match request options: %s", cmp.Diff(expected, resultValue))
}
return httpmock.NewJsonResponse(http.StatusOK, response)
}
}
func MockRequestBodyValidateNoBody(t *testing.T, response any) httpmock.Responder {
t.Helper()
return func(request *http.Request) (*http.Response, error) {
if request.Body != nil {
t.Fatal("got request body when no request body was expected")
}
return httpmock.NewJsonResponse(http.StatusOK, response)
}
}
// CreateMockClient is generic because importing the linodego package will result
// in a cyclic dependency. This pattern isn't ideal but works for now.
func CreateMockClient[T any](t *testing.T, createFunc func(*http.Client) T) *T {
t.Helper()
tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: validTestAPIKey})
client := &http.Client{
Transport: &oauth2.Transport{
Source: tokenSource,
},
}
httpmock.ActivateNonDefault(client)
t.Cleanup(func() {
httpmock.DeactivateAndReset()
})
result := createFunc(client)
return &result
}
type Logger interface {
Errorf(format string, v ...interface{})
Warnf(format string, v ...interface{})
Debugf(format string, v ...interface{})
}
func CreateLogger() *TestLogger {
l := &TestLogger{L: log.New(os.Stderr, "", log.Ldate|log.Lmicroseconds)}
return l
}
var _ Logger = (*TestLogger)(nil)
type TestLogger struct {
L *log.Logger
}
func (l *TestLogger) Errorf(format string, v ...interface{}) {
l.outputf("ERROR RESTY "+format, v...)
}
func (l *TestLogger) Warnf(format string, v ...interface{}) {
l.outputf("WARN RESTY "+format, v...)
}
func (l *TestLogger) Debugf(format string, v ...interface{}) {
l.outputf("DEBUG RESTY "+format, v...)
}
func (l *TestLogger) outputf(format string, v ...interface{}) {
if len(v) == 0 {
l.L.Print(format)
return
}
l.L.Printf(format, v...)
}
|