mirror of
https://github.com/openfaas/faas.git
synced 2025-06-21 14:23:25 +00:00
Refactoring: variable names, adding tests and http constants
Signed-off-by: Alex Ellis <alexellis2@gmail.com>
This commit is contained in:
@ -21,6 +21,13 @@ import (
|
||||
// DefaultMaxReplicas is the amount of replicas a service will auto-scale up to.
|
||||
const DefaultMaxReplicas = 20
|
||||
|
||||
// MinScaleLabel label indicating min scale for a function
|
||||
const MinScaleLabel = "com.openfaas.scale.min"
|
||||
|
||||
// MaxScaleLabel label indicating max scale for a function
|
||||
const MaxScaleLabel = "com.openfaas.scale.max"
|
||||
|
||||
// ServiceQuery provides interface for replica querying/setting
|
||||
type ServiceQuery interface {
|
||||
GetReplicas(service string) (currentReplicas uint64, maxReplicas uint64, minReplicas uint64, err error)
|
||||
SetReplicas(service string, count uint64) error
|
||||
@ -33,7 +40,7 @@ func NewSwarmServiceQuery(c *client.Client) ServiceQuery {
|
||||
}
|
||||
}
|
||||
|
||||
// SwarmServiceQuery Docker Swarm implementation
|
||||
// SwarmServiceQuery implementation for Docker Swarm
|
||||
type SwarmServiceQuery struct {
|
||||
c *client.Client
|
||||
}
|
||||
@ -42,21 +49,21 @@ type SwarmServiceQuery struct {
|
||||
func (s SwarmServiceQuery) GetReplicas(serviceName string) (uint64, uint64, uint64, error) {
|
||||
var err error
|
||||
var currentReplicas uint64
|
||||
|
||||
maxReplicas := uint64(DefaultMaxReplicas)
|
||||
minReplicas := uint64(1)
|
||||
|
||||
opts := types.ServiceInspectOptions{
|
||||
InsertDefaults: true,
|
||||
}
|
||||
|
||||
service, _, err := s.c.ServiceInspectWithRaw(context.Background(), serviceName, opts)
|
||||
|
||||
if err == nil {
|
||||
currentReplicas = *service.Spec.Mode.Replicated.Replicas
|
||||
log.Println("service.Spec.Annotations.Labels ", service.Spec.Annotations.Labels)
|
||||
log.Println("service.Spec.TaskTemplate.ContainerSpec.Labels ", service.Spec.TaskTemplate.ContainerSpec.Labels)
|
||||
log.Println("service.Spec.Labels ", service.Spec.Labels)
|
||||
|
||||
minScale := service.Spec.Annotations.Labels["com.openfaas.scale.min"]
|
||||
maxScale := service.Spec.Annotations.Labels["com.openfaas.scale.max"]
|
||||
minScale := service.Spec.Annotations.Labels[MinScaleLabel]
|
||||
maxScale := service.Spec.Annotations.Labels[MaxScaleLabel]
|
||||
|
||||
if len(maxScale) > 0 {
|
||||
labelValue, err := strconv.Atoi(maxScale)
|
||||
@ -98,12 +105,14 @@ func (s SwarmServiceQuery) SetReplicas(serviceName string, count uint64) error {
|
||||
err = updateErr
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// MakeAlertHandler handles alerts from Prometheus Alertmanager
|
||||
func MakeAlertHandler(sq ServiceQuery) http.HandlerFunc {
|
||||
func MakeAlertHandler(service ServiceQuery) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.Println("Alert received.")
|
||||
|
||||
body, readErr := ioutil.ReadAll(r.Body)
|
||||
@ -127,7 +136,7 @@ func MakeAlertHandler(sq ServiceQuery) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
errors := handleAlerts(&req, sq)
|
||||
errors := handleAlerts(&req, service)
|
||||
if len(errors) > 0 {
|
||||
log.Println(errors)
|
||||
var errorOutput string
|
||||
@ -143,10 +152,10 @@ func MakeAlertHandler(sq ServiceQuery) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func handleAlerts(req *requests.PrometheusAlert, sq ServiceQuery) []error {
|
||||
func handleAlerts(req *requests.PrometheusAlert, service ServiceQuery) []error {
|
||||
var errors []error
|
||||
for _, alert := range req.Alerts {
|
||||
if err := scaleService(alert, sq); err != nil {
|
||||
if err := scaleService(alert, service); err != nil {
|
||||
log.Println(err)
|
||||
errors = append(errors, err)
|
||||
}
|
||||
@ -155,12 +164,12 @@ func handleAlerts(req *requests.PrometheusAlert, sq ServiceQuery) []error {
|
||||
return errors
|
||||
}
|
||||
|
||||
func scaleService(alert requests.PrometheusInnerAlert, sq ServiceQuery) error {
|
||||
func scaleService(alert requests.PrometheusInnerAlert, service ServiceQuery) error {
|
||||
var err error
|
||||
serviceName := alert.Labels.FunctionName
|
||||
|
||||
if len(serviceName) > 0 {
|
||||
currentReplicas, maxReplicas, minReplicas, getErr := sq.GetReplicas(serviceName)
|
||||
currentReplicas, maxReplicas, minReplicas, getErr := service.GetReplicas(serviceName)
|
||||
if getErr == nil {
|
||||
status := alert.Status
|
||||
|
||||
@ -171,7 +180,7 @@ func scaleService(alert requests.PrometheusInnerAlert, sq ServiceQuery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
updateErr := sq.SetReplicas(serviceName, newReplicas)
|
||||
updateErr := service.SetReplicas(serviceName, newReplicas)
|
||||
if updateErr != nil {
|
||||
err = updateErr
|
||||
}
|
||||
|
@ -2,12 +2,13 @@ package handlers
|
||||
|
||||
import "net/http"
|
||||
|
||||
type CorsHandler struct {
|
||||
// CORSHandler set custom CORS instructions for the store.
|
||||
type CORSHandler struct {
|
||||
Upstream *http.Handler
|
||||
AllowedHost string
|
||||
}
|
||||
|
||||
func (c CorsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
func (c CORSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// https://raw.githubusercontent.com/openfaas/store/master/store.json
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET")
|
||||
@ -16,8 +17,9 @@ func (c CorsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
(*c.Upstream).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// DecorateWithCORS decorate a handler with CORS-injecting middleware
|
||||
func DecorateWithCORS(upstream http.Handler, allowedHost string) http.Handler {
|
||||
return CorsHandler{
|
||||
return CORSHandler{
|
||||
Upstream: &upstream,
|
||||
AllowedHost: allowedHost,
|
||||
}
|
||||
|
@ -135,6 +135,7 @@ func buildEnv(envProcess string, envVars map[string]string) []string {
|
||||
if len(envProcess) > 0 {
|
||||
env = append(env, fmt.Sprintf("fprocess=%s", envProcess))
|
||||
}
|
||||
|
||||
for k, v := range envVars {
|
||||
env = append(env, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ func MakeForwardingProxyHandler(proxy *httputil.ReverseProxy, metrics *metrics.M
|
||||
proxy.ServeHTTP(writeAdapter, r)
|
||||
|
||||
seconds := time.Since(start).Seconds()
|
||||
log.Printf("< [%s] - %d took %f seconds\n", r.URL.String(), writeAdapter.GetHeaderCode(), seconds)
|
||||
log.Printf("< [%s] - %d took %f seconds\n", r.URL.String(),
|
||||
writeAdapter.GetHeaderCode(), seconds)
|
||||
|
||||
forward := "/function/"
|
||||
if startsWith(uri, forward) {
|
||||
@ -39,7 +40,9 @@ func MakeForwardingProxyHandler(proxy *httputil.ReverseProxy, metrics *metrics.M
|
||||
|
||||
code := strconv.Itoa(writeAdapter.GetHeaderCode())
|
||||
|
||||
metrics.GatewayFunctionInvocation.With(prometheus.Labels{"function_name": service, "code": code}).Inc()
|
||||
metrics.GatewayFunctionInvocation.
|
||||
With(prometheus.Labels{"function_name": service, "code": code}).
|
||||
Inc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const watchdogPort = 8080
|
||||
|
||||
// MakeProxy creates a proxy for HTTP web requests which can be routed to a function.
|
||||
func MakeProxy(metrics metrics.MetricOptions, wildcard bool, client *client.Client, logger *logrus.Logger) http.HandlerFunc {
|
||||
proxyClient := http.Client{
|
||||
@ -123,8 +125,6 @@ func invokeService(w http.ResponseWriter, r *http.Request, metrics metrics.Metri
|
||||
dnsrr = true
|
||||
}
|
||||
|
||||
watchdogPort := 8080
|
||||
|
||||
addr := service
|
||||
// Use DNS-RR via tasks.servicename if enabled as override, otherwise VIP.
|
||||
if dnsrr {
|
||||
@ -165,6 +165,7 @@ func invokeService(w http.ResponseWriter, r *http.Request, metrics metrics.Metri
|
||||
w.Header().Set("Content-Type", GetContentType(response.Header, r.Header, defaultHeader))
|
||||
|
||||
writeHead(service, metrics, response.StatusCode, w)
|
||||
|
||||
if response.Body != nil {
|
||||
io.Copy(w, response.Body)
|
||||
}
|
||||
@ -188,10 +189,10 @@ func GetContentType(request http.Header, proxyResponse http.Header, defaultValue
|
||||
}
|
||||
|
||||
func copyHeaders(destination *http.Header, source *http.Header) {
|
||||
for k, vv := range *source {
|
||||
vvClone := make([]string, len(vv))
|
||||
copy(vvClone, vv)
|
||||
(*destination)[k] = vvClone
|
||||
for k, v := range *source {
|
||||
vClone := make([]string, len(v))
|
||||
copy(vClone, v)
|
||||
(*destination)[k] = vClone
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,14 +208,20 @@ func writeHead(service string, metrics metrics.MetricOptions, code int, w http.R
|
||||
}
|
||||
|
||||
func trackInvocation(service string, metrics metrics.MetricOptions, code int) {
|
||||
metrics.GatewayFunctionInvocation.With(prometheus.Labels{"function_name": service, "code": strconv.Itoa(code)}).Inc()
|
||||
metrics.GatewayFunctionInvocation.With(
|
||||
prometheus.Labels{"function_name": service,
|
||||
"code": strconv.Itoa(code)}).Inc()
|
||||
}
|
||||
|
||||
func trackTime(then time.Time, metrics metrics.MetricOptions, name string) {
|
||||
since := time.Since(then)
|
||||
metrics.GatewayFunctionsHistogram.WithLabelValues(name).Observe(since.Seconds())
|
||||
metrics.GatewayFunctionsHistogram.
|
||||
WithLabelValues(name).
|
||||
Observe(since.Seconds())
|
||||
}
|
||||
|
||||
func trackTimeExact(duration time.Duration, metrics metrics.MetricOptions, name string) {
|
||||
metrics.GatewayFunctionsHistogram.WithLabelValues(name).Observe(float64(duration))
|
||||
metrics.GatewayFunctionsHistogram.
|
||||
WithLabelValues(name).
|
||||
Observe(float64(duration))
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ func MakeQueuedProxy(metrics metrics.MetricOptions, wildcard bool, logger *logru
|
||||
|
||||
callbackURL = urlVal
|
||||
}
|
||||
|
||||
req := &queue.Request{
|
||||
Function: name,
|
||||
Body: body,
|
||||
@ -54,13 +55,14 @@ func MakeQueuedProxy(metrics metrics.MetricOptions, wildcard bool, logger *logru
|
||||
}
|
||||
|
||||
err = canQueueRequests.Queue(req)
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
}
|
||||
|
@ -42,16 +42,11 @@ func MakeFunctionReader(metricsOptions metrics.MetricOptions, c client.ServiceAP
|
||||
for _, service := range services {
|
||||
|
||||
if len(service.Spec.TaskTemplate.ContainerSpec.Labels["function"]) > 0 {
|
||||
var envProcess string
|
||||
|
||||
for _, env := range service.Spec.TaskTemplate.ContainerSpec.Env {
|
||||
if strings.Contains(env, "fprocess=") {
|
||||
envProcess = env[len("fprocess="):]
|
||||
}
|
||||
}
|
||||
envProcess := getEnvProcess(service.Spec.TaskTemplate.ContainerSpec.Env)
|
||||
|
||||
// Required (copy by value)
|
||||
labels := service.Spec.Annotations.Labels
|
||||
|
||||
f := requests.Function{
|
||||
Name: service.Spec.Name,
|
||||
Image: service.Spec.TaskTemplate.ContainerSpec.Image,
|
||||
@ -67,7 +62,19 @@ func MakeFunctionReader(metricsOptions metrics.MetricOptions, c client.ServiceAP
|
||||
|
||||
functionBytes, _ := json.Marshal(functions)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(functionBytes)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func getEnvProcess(envVars []string) string {
|
||||
var value string
|
||||
for _, env := range envVars {
|
||||
if strings.Contains(env, "fprocess=") {
|
||||
value = env[len("fprocess="):]
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
@ -30,14 +30,16 @@ func NewPrometheusQuery(host string, port int, client *http.Client) PrometheusQu
|
||||
// Fetch queries aggregated stats
|
||||
func (q PrometheusQuery) Fetch(query string) (*VectorQueryResponse, error) {
|
||||
|
||||
req, reqErr := http.NewRequest("GET", fmt.Sprintf("http://%s:%d/api/v1/query/?query=%s", q.Host, q.Port, query), nil)
|
||||
req, reqErr := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d/api/v1/query/?query=%s", q.Host, q.Port, query), nil)
|
||||
if reqErr != nil {
|
||||
return nil, reqErr
|
||||
}
|
||||
|
||||
res, getErr := q.Client.Do(req)
|
||||
if getErr != nil {
|
||||
return nil, getErr
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
bytesOut, readErr := ioutil.ReadAll(res.Body)
|
||||
if readErr != nil {
|
||||
|
@ -15,8 +15,9 @@ import (
|
||||
|
||||
// AttachSwarmWatcher adds a go-route to monitor the amount of service replicas in the swarm
|
||||
// matching a 'function' label.
|
||||
func AttachSwarmWatcher(dockerClient *client.Client, metricsOptions MetricOptions, label string) {
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
func AttachSwarmWatcher(dockerClient *client.Client, metricsOptions MetricOptions, label string, interval time.Duration) {
|
||||
ticker := time.NewTicker(interval)
|
||||
|
||||
quit := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
@ -47,5 +48,4 @@ func AttachSwarmWatcher(dockerClient *client.Client, metricsOptions MetricOption
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
|
@ -55,15 +55,21 @@ func (s ExternalServiceQuery) GetReplicas(serviceName string) (uint64, uint64, u
|
||||
function := requests.Function{}
|
||||
|
||||
urlPath := fmt.Sprintf("%ssystem/function/%s", s.URL.String(), serviceName)
|
||||
req, _ := http.NewRequest("GET", urlPath, nil)
|
||||
res, err := s.ProxyClient.Do(req)
|
||||
if err != nil {
|
||||
log.Println(urlPath, err)
|
||||
}
|
||||
|
||||
if res.StatusCode == 200 {
|
||||
req, _ := http.NewRequest(http.MethodGet, urlPath, nil)
|
||||
|
||||
res, err := s.ProxyClient.Do(req)
|
||||
|
||||
if err != nil {
|
||||
|
||||
log.Println(urlPath, err)
|
||||
} else {
|
||||
|
||||
if res.Body != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
if res.StatusCode == http.StatusOK {
|
||||
bytesOut, _ := ioutil.ReadAll(res.Body)
|
||||
err = json.Unmarshal(bytesOut, &function)
|
||||
if err != nil {
|
||||
@ -77,8 +83,8 @@ func (s ExternalServiceQuery) GetReplicas(serviceName string) (uint64, uint64, u
|
||||
|
||||
if function.Labels != nil {
|
||||
labels := *function.Labels
|
||||
minScale := labels["com.openfaas.scale.min"]
|
||||
maxScale := labels["com.openfaas.scale.max"]
|
||||
minScale := labels[handlers.MinScaleLabel]
|
||||
maxScale := labels[handlers.MaxScaleLabel]
|
||||
|
||||
if len(minScale) > 0 {
|
||||
labelValue, err := strconv.Atoi(minScale)
|
||||
@ -123,7 +129,7 @@ func (s ExternalServiceQuery) SetReplicas(serviceName string, count uint64) erro
|
||||
}
|
||||
|
||||
urlPath := fmt.Sprintf("%ssystem/scale-function/%s", s.URL.String(), serviceName)
|
||||
req, _ := http.NewRequest("POST", urlPath, bytes.NewReader(requestBody))
|
||||
req, _ := http.NewRequest(http.MethodPost, urlPath, bytes.NewReader(requestBody))
|
||||
defer req.Body.Close()
|
||||
res, err := s.ProxyClient.Do(req)
|
||||
|
||||
|
@ -71,6 +71,7 @@ func main() {
|
||||
metrics.RegisterMetrics(metricsOptions)
|
||||
|
||||
var faasHandlers handlerSet
|
||||
servicePollInterval := time.Second * 5
|
||||
|
||||
if config.UseExternalProvider() {
|
||||
|
||||
@ -86,7 +87,7 @@ func main() {
|
||||
alertHandler := plugin.NewExternalServiceQuery(*config.FunctionsProviderURL)
|
||||
faasHandlers.Alert = internalHandlers.MakeAlertHandler(alertHandler)
|
||||
|
||||
metrics.AttachExternalWatcher(*config.FunctionsProviderURL, metricsOptions, "func", time.Second*5)
|
||||
metrics.AttachExternalWatcher(*config.FunctionsProviderURL, metricsOptions, "func", servicePollInterval)
|
||||
|
||||
} else {
|
||||
|
||||
@ -106,7 +107,7 @@ func main() {
|
||||
|
||||
// This could exist in a separate process - records the replicas of each swarm service.
|
||||
functionLabel := "function"
|
||||
metrics.AttachSwarmWatcher(dockerClient, metricsOptions, functionLabel)
|
||||
metrics.AttachSwarmWatcher(dockerClient, metricsOptions, functionLabel, servicePollInterval)
|
||||
}
|
||||
|
||||
if config.UseNATS() {
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
|
||||
func TestScale1to5(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
newReplicas := handlers.CalculateReplicas("firing", 1, 20, minReplicas)
|
||||
newReplicas := handlers.CalculateReplicas("firing", 1, handlers.DefaultMaxReplicas, minReplicas)
|
||||
if newReplicas != 5 {
|
||||
t.Log("Expected increment in blocks of 5 from 1 to 5")
|
||||
t.Fail()
|
||||
@ -20,7 +20,7 @@ func TestScale1to5(t *testing.T) {
|
||||
|
||||
func TestScale5to10(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
newReplicas := handlers.CalculateReplicas("firing", 5, 20, minReplicas)
|
||||
newReplicas := handlers.CalculateReplicas("firing", 5, handlers.DefaultMaxReplicas, minReplicas)
|
||||
if newReplicas != 10 {
|
||||
t.Log("Expected increment in blocks of 5 from 5 to 10")
|
||||
t.Fail()
|
||||
@ -29,7 +29,7 @@ func TestScale5to10(t *testing.T) {
|
||||
|
||||
func TestScaleCeilingOf20Replicas_Noaction(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
newReplicas := handlers.CalculateReplicas("firing", 20, 20, minReplicas)
|
||||
newReplicas := handlers.CalculateReplicas("firing", 20, handlers.DefaultMaxReplicas, minReplicas)
|
||||
if newReplicas != 20 {
|
||||
t.Log("Expected ceiling of 20 replicas")
|
||||
t.Fail()
|
||||
@ -38,7 +38,7 @@ func TestScaleCeilingOf20Replicas_Noaction(t *testing.T) {
|
||||
|
||||
func TestScaleCeilingOf20Replicas(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
newReplicas := handlers.CalculateReplicas("firing", 19, 20, minReplicas)
|
||||
newReplicas := handlers.CalculateReplicas("firing", 19, handlers.DefaultMaxReplicas, minReplicas)
|
||||
if newReplicas != 20 {
|
||||
t.Log("Expected ceiling of 20 replicas")
|
||||
t.Fail()
|
||||
@ -47,7 +47,7 @@ func TestScaleCeilingOf20Replicas(t *testing.T) {
|
||||
|
||||
func TestBackingOff10to1(t *testing.T) {
|
||||
minReplicas := uint64(1)
|
||||
newReplicas := handlers.CalculateReplicas("resolved", 10, 20, minReplicas)
|
||||
newReplicas := handlers.CalculateReplicas("resolved", 10, handlers.DefaultMaxReplicas, minReplicas)
|
||||
if newReplicas != 1 {
|
||||
t.Log("Expected backing off to 1 replica")
|
||||
t.Fail()
|
||||
|
36
gateway/tests/cors_test.go
Normal file
36
gateway/tests/cors_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/openfaas/faas/gateway/handlers"
|
||||
)
|
||||
|
||||
type customHandler struct {
|
||||
}
|
||||
|
||||
func (h customHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func Test_HeadersAdded(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
handler := customHandler{}
|
||||
host := "store.openfaas.com"
|
||||
|
||||
decorated := handlers.DecorateWithCORS(handler, host)
|
||||
request, _ := http.NewRequest(http.MethodGet, "/", nil)
|
||||
decorated.ServeHTTP(rr, request)
|
||||
|
||||
actual := rr.Header().Get("Access-Control-Allow-Origin")
|
||||
if actual != host {
|
||||
t.Errorf("Access-Control-Allow-Origin: want: %s got: %s", host, actual)
|
||||
}
|
||||
|
||||
actualMethods := rr.Header().Get("Access-Control-Allow-Methods")
|
||||
if actualMethods != "GET" {
|
||||
t.Errorf("Access-Control-Allow-Methods: want: %s got: %s", "GET", actualMethods)
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,6 @@ func Test_GetContentType_UsesRequest_WhenResponseEmpty(t *testing.T) {
|
||||
if contentType != request.Get("Content-Type") {
|
||||
t.Errorf("Got: %s, want: %s", contentType, request.Get("Content-Type"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_GetContentType_UsesDefaultWhenRequestResponseEmpty(t *testing.T) {
|
||||
@ -42,5 +41,4 @@ func Test_GetContentType_UsesDefaultWhenRequestResponseEmpty(t *testing.T) {
|
||||
if contentType != "default" {
|
||||
t.Errorf("Got: %s, want: %s", contentType, "default")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -167,6 +167,7 @@ func TestReaderSuccessReturnsCorrectBodyWithOneFunction(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
marshalled, _ := json.Marshal(functions)
|
||||
expected := string(marshalled)
|
||||
if w.Body.String() != expected {
|
||||
|
@ -15,14 +15,14 @@ import (
|
||||
|
||||
func TestBuildEncodedAuthConfig(t *testing.T) {
|
||||
// custom repository with valid data
|
||||
assertValidEncodedAuthConfig(t, "user", "password", "my.repository.com/user/imagename", "my.repository.com")
|
||||
assertValidEncodedAuthConfig(t, "user", "weird:password:", "my.repository.com/user/imagename", "my.repository.com")
|
||||
assertValidEncodedAuthConfig(t, "userWithNoPassword", "", "my.repository.com/user/imagename", "my.repository.com")
|
||||
assertValidEncodedAuthConfig(t, "", "", "my.repository.com/user/imagename", "my.repository.com")
|
||||
testValidEncodedAuthConfig(t, "user", "password", "my.repository.com/user/imagename", "my.repository.com")
|
||||
testValidEncodedAuthConfig(t, "user", "weird:password:", "my.repository.com/user/imagename", "my.repository.com")
|
||||
testValidEncodedAuthConfig(t, "userWithNoPassword", "", "my.repository.com/user/imagename", "my.repository.com")
|
||||
testValidEncodedAuthConfig(t, "", "", "my.repository.com/user/imagename", "my.repository.com")
|
||||
|
||||
// docker hub default repository
|
||||
assertValidEncodedAuthConfig(t, "user", "password", "user/imagename", "docker.io")
|
||||
assertValidEncodedAuthConfig(t, "", "", "user/imagename", "docker.io")
|
||||
testValidEncodedAuthConfig(t, "user", "password", "user/imagename", "docker.io")
|
||||
testValidEncodedAuthConfig(t, "", "", "user/imagename", "docker.io")
|
||||
|
||||
// invalid base64 basic auth
|
||||
assertEncodedAuthError(t, "invalidBasicAuth", "my.repository.com/user/imagename")
|
||||
@ -32,7 +32,7 @@ func TestBuildEncodedAuthConfig(t *testing.T) {
|
||||
assertEncodedAuthError(t, b64BasicAuth("user", "password"), "invalid name")
|
||||
}
|
||||
|
||||
func assertValidEncodedAuthConfig(t *testing.T, user, password, imageName, expectedRegistryHost string) {
|
||||
func testValidEncodedAuthConfig(t *testing.T, user, password, imageName, expectedRegistryHost string) {
|
||||
encodedAuthConfig, err := handlers.BuildEncodedAuthConfig(b64BasicAuth(user, password), imageName)
|
||||
if err != nil {
|
||||
t.Log("Unexpected error while building auth config with correct values")
|
||||
@ -50,10 +50,12 @@ func assertValidEncodedAuthConfig(t *testing.T, user, password, imageName, expec
|
||||
t.Log("Auth config username mismatch", user, authConfig.Username)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if password != authConfig.Password {
|
||||
t.Log("Auth config password mismatch", password, authConfig.Password)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if expectedRegistryHost != authConfig.ServerAddress {
|
||||
t.Log("Auth config registry server address mismatch", expectedRegistryHost, authConfig.ServerAddress)
|
||||
t.Fail()
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"github.com/openfaas/faas/gateway/handlers"
|
||||
)
|
||||
|
||||
// Test_ParseMemory exploratory testing to document how to convert
|
||||
// from Docker limits notation to bytes value.
|
||||
func Test_ParseMemory(t *testing.T) {
|
||||
value := "512 m"
|
||||
|
||||
|
@ -4,11 +4,9 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/openfaas/faas/gateway/requests"
|
||||
)
|
||||
@ -19,21 +17,27 @@ func TestUnmarshallAlert(t *testing.T) {
|
||||
|
||||
var alert requests.PrometheusAlert
|
||||
err := json.Unmarshal(file, &alert)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if (len(alert.Status)) == 0 {
|
||||
t.Fatal("No status read")
|
||||
}
|
||||
|
||||
if (len(alert.Receiver)) == 0 {
|
||||
t.Fatal("No status read")
|
||||
}
|
||||
|
||||
if (len(alert.Alerts)) == 0 {
|
||||
t.Fatal("No alerts read")
|
||||
}
|
||||
|
||||
if (len(alert.Alerts[0].Labels.AlertName)) == 0 {
|
||||
t.Fatal("No alerts name")
|
||||
}
|
||||
|
||||
if (len(alert.Alerts[0].Labels.FunctionName)) == 0 {
|
||||
t.Fatal("No function name read")
|
||||
}
|
||||
|
@ -4,22 +4,24 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// WriteAdapter adapts a ResponseWriter
|
||||
type WriteAdapter struct {
|
||||
Writer http.ResponseWriter
|
||||
HttpResult *HttpResult
|
||||
HTTPResult *HTTPResult
|
||||
}
|
||||
type HttpResult struct {
|
||||
HeaderCode int
|
||||
|
||||
// HTTPResult captures data from forwarded HTTP call
|
||||
type HTTPResult struct {
|
||||
HeaderCode int // HeaderCode is the result of WriteHeader(int)
|
||||
}
|
||||
|
||||
//NewWriteAdapter create a new NewWriteAdapter
|
||||
func NewWriteAdapter(w http.ResponseWriter) WriteAdapter {
|
||||
return WriteAdapter{Writer: w, HttpResult: &HttpResult{}}
|
||||
return WriteAdapter{Writer: w, HTTPResult: &HTTPResult{}}
|
||||
}
|
||||
|
||||
//Header adapts Header
|
||||
@ -27,19 +29,20 @@ func (w WriteAdapter) Header() http.Header {
|
||||
return w.Writer.Header()
|
||||
}
|
||||
|
||||
// Write adapts Write
|
||||
// Write adapts Write for a straight pass-through
|
||||
func (w WriteAdapter) Write(data []byte) (int, error) {
|
||||
return w.Writer.Write(data)
|
||||
}
|
||||
|
||||
// WriteHeader adapts WriteHeader
|
||||
func (w WriteAdapter) WriteHeader(i int) {
|
||||
w.Writer.WriteHeader(i)
|
||||
w.HttpResult.HeaderCode = i
|
||||
fmt.Println("GetHeaderCode before", w.HttpResult.HeaderCode)
|
||||
func (w WriteAdapter) WriteHeader(statusCode int) {
|
||||
w.Writer.WriteHeader(statusCode)
|
||||
w.HTTPResult.HeaderCode = statusCode
|
||||
|
||||
log.Printf("GetHeaderCode %d", w.HTTPResult.HeaderCode)
|
||||
}
|
||||
|
||||
// GetHeaderCode result from WriteHeader
|
||||
func (w *WriteAdapter) GetHeaderCode() int {
|
||||
return w.HttpResult.HeaderCode
|
||||
return w.HTTPResult.HeaderCode
|
||||
}
|
||||
|
Reference in New Issue
Block a user