Increase Unit Test Coverage for Templates

Increases the Coverage for nginx ingress template
functions. The majority of the added unit tests
are for checking the invalid type handling.
This commit is contained in:
Fernando Diaz 2019-01-29 00:21:08 -06:00
parent 63ea4fdb6a
commit 7b507095f4
2 changed files with 304 additions and 13 deletions

View file

@ -230,9 +230,6 @@ func buildLuaSharedDictionaries(s interface{}, disableLuaRestyWAF bool) string {
} }
} }
if len(out) == 0 {
return ""
}
return strings.Join(out, ";\n\r") + ";" return strings.Join(out, ";\n\r") + ";"
} }
@ -840,7 +837,7 @@ func buildOpentracing(input interface{}) string {
if cfg.ZipkinCollectorHost != "" { if cfg.ZipkinCollectorHost != "" {
buf.WriteString("opentracing_load_tracer /usr/local/lib/libzipkin_opentracing.so /etc/nginx/opentracing.json;") buf.WriteString("opentracing_load_tracer /usr/local/lib/libzipkin_opentracing.so /etc/nginx/opentracing.json;")
} else if cfg.JaegerCollectorHost != "" { } else if cfg.JaegerCollectorHost != "" {
buf.WriteString("opentracing_load_tracer /usr/local/lib/libjaegertracing_plugin.so /etc/nginx/opentracing.json;") buf.WriteString("opentracing_load_tracer /usr/local/lib/libjaegertracing_plugin.so /etc/nginx/opentracing.json;")
} }
buf.WriteString("\r\n") buf.WriteString("\r\n")

View file

@ -22,6 +22,7 @@ import (
"os" "os"
"path" "path"
"reflect" "reflect"
"sort"
"strings" "strings"
"testing" "testing"
@ -33,7 +34,9 @@ import (
"k8s.io/ingress-nginx/internal/file" "k8s.io/ingress-nginx/internal/file"
"k8s.io/ingress-nginx/internal/ingress" "k8s.io/ingress-nginx/internal/ingress"
"k8s.io/ingress-nginx/internal/ingress/annotations/authreq" "k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
"k8s.io/ingress-nginx/internal/ingress/annotations/influxdb"
"k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf" "k8s.io/ingress-nginx/internal/ingress/annotations/luarestywaf"
"k8s.io/ingress-nginx/internal/ingress/annotations/ratelimit"
"k8s.io/ingress-nginx/internal/ingress/annotations/rewrite" "k8s.io/ingress-nginx/internal/ingress/annotations/rewrite"
"k8s.io/ingress-nginx/internal/ingress/controller/config" "k8s.io/ingress-nginx/internal/ingress/controller/config"
) )
@ -163,6 +166,14 @@ proxy_pass http://upstream_balancer;`,
) )
func TestBuildLuaSharedDictionaries(t *testing.T) { func TestBuildLuaSharedDictionaries(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildLuaSharedDictionaries(invalidType, true)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
servers := []*ingress.Server{ servers := []*ingress.Server{
{ {
Hostname: "foo.bar", Hostname: "foo.bar",
@ -209,6 +220,14 @@ func TestFormatIP(t *testing.T) {
} }
func TestBuildLocation(t *testing.T) { func TestBuildLocation(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := "/"
actual := buildLocation(invalidType, true)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
for k, tc := range tmplFuncTestcases { for k, tc := range tmplFuncTestcases {
loc := &ingress.Location{ loc := &ingress.Location{
Path: tc.Path, Path: tc.Path,
@ -263,6 +282,14 @@ func TestBuildProxyPass(t *testing.T) {
} }
func TestBuildAuthLocation(t *testing.T) { func TestBuildAuthLocation(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildAuthLocation(invalidType)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
authURL := "foo.com/auth" authURL := "foo.com/auth"
loc := &ingress.Location{ loc := &ingress.Location{
@ -275,7 +302,7 @@ func TestBuildAuthLocation(t *testing.T) {
str := buildAuthLocation(loc) str := buildAuthLocation(loc)
encodedAuthURL := strings.Replace(base64.URLEncoding.EncodeToString([]byte(loc.Path)), "=", "", -1) encodedAuthURL := strings.Replace(base64.URLEncoding.EncodeToString([]byte(loc.Path)), "=", "", -1)
expected := fmt.Sprintf("/_external-auth-%v", encodedAuthURL) expected = fmt.Sprintf("/_external-auth-%v", encodedAuthURL)
if str != expected { if str != expected {
t.Errorf("Expected \n'%v'\nbut returned \n'%v'", expected, str) t.Errorf("Expected \n'%v'\nbut returned \n'%v'", expected, str)
@ -283,11 +310,19 @@ func TestBuildAuthLocation(t *testing.T) {
} }
func TestBuildAuthResponseHeaders(t *testing.T) { func TestBuildAuthResponseHeaders(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := []string{}
actual := buildAuthResponseHeaders(invalidType)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
loc := &ingress.Location{ loc := &ingress.Location{
ExternalAuth: authreq.Config{ResponseHeaders: []string{"h1", "H-With-Caps-And-Dashes"}}, ExternalAuth: authreq.Config{ResponseHeaders: []string{"h1", "H-With-Caps-And-Dashes"}},
} }
headers := buildAuthResponseHeaders(loc) headers := buildAuthResponseHeaders(loc)
expected := []string{ expected = []string{
"auth_request_set $authHeader0 $upstream_http_h1;", "auth_request_set $authHeader0 $upstream_http_h1;",
"proxy_set_header 'h1' $authHeader0;", "proxy_set_header 'h1' $authHeader0;",
"auth_request_set $authHeader1 $upstream_http_h_with_caps_and_dashes;", "auth_request_set $authHeader1 $upstream_http_h_with_caps_and_dashes;",
@ -378,6 +413,14 @@ func BenchmarkTemplateWithData(b *testing.B) {
} }
func TestBuildDenyVariable(t *testing.T) { func TestBuildDenyVariable(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildDenyVariable(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
a := buildDenyVariable("host1.example.com_/.well-known/acme-challenge") a := buildDenyVariable("host1.example.com_/.well-known/acme-challenge")
b := buildDenyVariable("host1.example.com_/.well-known/acme-challenge") b := buildDenyVariable("host1.example.com_/.well-known/acme-challenge")
if !reflect.DeepEqual(a, b) { if !reflect.DeepEqual(a, b) {
@ -416,6 +459,14 @@ func TestBuildByteSize(t *testing.T) {
} }
func TestIsLocationAllowed(t *testing.T) { func TestIsLocationAllowed(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := false
actual := isLocationAllowed(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
loc := ingress.Location{ loc := ingress.Location{
Denied: nil, Denied: nil,
} }
@ -427,23 +478,47 @@ func TestIsLocationAllowed(t *testing.T) {
} }
func TestBuildForwardedFor(t *testing.T) { func TestBuildForwardedFor(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildForwardedFor(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
inputStr := "X-Forwarded-For" inputStr := "X-Forwarded-For"
outputStr := buildForwardedFor(inputStr) expected = "$http_x_forwarded_for"
actual = buildForwardedFor(inputStr)
validStr := "$http_x_forwarded_for" if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
if outputStr != validStr {
t.Errorf("Expected '%v' but returned '%v'", validStr, outputStr)
} }
} }
func TestBuildResolversForLua(t *testing.T) { func TestBuildResolversForLua(t *testing.T) {
ipOne := net.ParseIP("192.0.0.1") ipOne := net.ParseIP("192.0.0.1")
ipTwo := net.ParseIP("2001:db8:1234:0000:0000:0000:0000:0000") ipTwo := net.ParseIP("2001:db8:1234:0000:0000:0000:0000:0000")
ipList := []net.IP{ipOne, ipTwo} ipList := []net.IP{ipOne, ipTwo}
expected := "\"192.0.0.1\", \"2001:db8:1234::\"" invalidType := &ingress.Ingress{}
actual := buildResolversForLua(ipList, false) expected := ""
actual := buildResolversForLua(invalidType, false)
// Invalid Type for []net.IP
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
actual = buildResolversForLua(ipList, invalidType)
// Invalid Type for bool
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
expected = "\"192.0.0.1\", \"2001:db8:1234::\""
actual = buildResolversForLua(ipList, false)
if expected != actual { if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual) t.Errorf("Expected '%v' but returned '%v'", expected, actual)
@ -462,6 +537,22 @@ func TestBuildResolvers(t *testing.T) {
ipTwo := net.ParseIP("2001:db8:1234:0000:0000:0000:0000:0000") ipTwo := net.ParseIP("2001:db8:1234:0000:0000:0000:0000:0000")
ipList := []net.IP{ipOne, ipTwo} ipList := []net.IP{ipOne, ipTwo}
invalidType := &ingress.Ingress{}
expected := ""
actual := buildResolvers(invalidType, false)
// Invalid Type for []net.IP
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
actual = buildResolvers(ipList, invalidType)
// Invalid Type for bool
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
validResolver := "resolver 192.0.0.1 [2001:db8:1234::] valid=30s;" validResolver := "resolver 192.0.0.1 [2001:db8:1234::] valid=30s;"
resolver := buildResolvers(ipList, false) resolver := buildResolvers(ipList, false)
@ -478,6 +569,14 @@ func TestBuildResolvers(t *testing.T) {
} }
func TestBuildNextUpstream(t *testing.T) { func TestBuildNextUpstream(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildNextUpstream(invalidType, "")
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
cases := map[string]struct { cases := map[string]struct {
NextUpstream string NextUpstream string
NonIdempotent bool NonIdempotent bool
@ -516,6 +615,14 @@ func TestBuildNextUpstream(t *testing.T) {
} }
func TestBuildRateLimit(t *testing.T) { func TestBuildRateLimit(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := []string{}
actual := buildRateLimit(invalidType)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
loc := &ingress.Location{} loc := &ingress.Location{}
loc.RateLimit.Connections.Name = "con" loc.RateLimit.Connections.Name = "con"
@ -547,9 +654,45 @@ func TestBuildRateLimit(t *testing.T) {
t.Errorf("Expected '%v' but returned '%v'", validLimits, limits) t.Errorf("Expected '%v' but returned '%v'", validLimits, limits)
} }
} }
// Invalid limit
limits = buildRateLimit(&ingress.Ingress{})
if !reflect.DeepEqual(expected, limits) {
t.Errorf("Expected '%v' but returned '%v'", expected, limits)
}
}
// TODO: Needs more tests
func TestBuildRateLimitZones(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := []string{}
actual := buildRateLimitZones(invalidType)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
}
// TODO: Needs more tests
func TestFilterRateLimits(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := []ratelimit.Config{}
actual := filterRateLimits(invalidType)
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
} }
func TestBuildAuthSignURL(t *testing.T) { func TestBuildAuthSignURL(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildAuthSignURL(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
cases := map[string]struct { cases := map[string]struct {
Input, Output string Input, Output string
}{ }{
@ -566,6 +709,13 @@ func TestBuildAuthSignURL(t *testing.T) {
} }
func TestIsLocationInLocationList(t *testing.T) { func TestIsLocationInLocationList(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := false
actual := isLocationInLocationList(invalidType, "")
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
testCases := []struct { testCases := []struct {
location *ingress.Location location *ingress.Location
@ -589,6 +739,14 @@ func TestIsLocationInLocationList(t *testing.T) {
} }
func TestBuildUpstreamName(t *testing.T) { func TestBuildUpstreamName(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildUpstreamName(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
defaultBackend := "upstream-name" defaultBackend := "upstream-name"
defaultHost := "example.com" defaultHost := "example.com"
@ -744,3 +902,139 @@ func TestGetIngressInformation(t *testing.T) {
t.Errorf("Expected %v, but got %v", expected, info) t.Errorf("Expected %v, but got %v", expected, info)
} }
} }
func TestCollectCustomErrorsPerServer(t *testing.T) {
invalidType := &ingress.Ingress{}
customErrors := collectCustomErrorsPerServer(invalidType)
if customErrors != nil {
t.Errorf("Expected %v but returned %v", nil, customErrors)
}
server := &ingress.Server{
Locations: []*ingress.Location{
{CustomHTTPErrors: []int{404, 405}},
{CustomHTTPErrors: []int{404, 500}},
},
}
expected := []int{404, 405, 500}
uniqueCodes := collectCustomErrorsPerServer(server)
sort.Ints(uniqueCodes)
if !reflect.DeepEqual(expected, uniqueCodes) {
t.Errorf("Expected '%v' but got '%v'", expected, uniqueCodes)
}
}
func TestProxySetHeader(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := "proxy_set_header"
actual := proxySetHeader(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
grpcBackend := &ingress.Location{
BackendProtocol: "GRPC",
}
expected = "grpc_set_header"
actual = proxySetHeader(grpcBackend)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
}
func TestBuildInfluxDB(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildInfluxDB(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
cfg := influxdb.Config{
InfluxDBEnabled: true,
InfluxDBServerName: "ok.com",
InfluxDBHost: "host.com",
InfluxDBPort: "5252",
InfluxDBMeasurement: "ok",
}
expected = "influxdb server_name=ok.com host=host.com port=5252 measurement=ok enabled=true;"
actual = buildInfluxDB(cfg)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
}
func TestBuildOpenTracing(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := ""
actual := buildOpentracing(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
cfgJaeger := config.Configuration{
EnableOpentracing: true,
JaegerCollectorHost: "jaeger-host.com",
}
expected = "opentracing_load_tracer /usr/local/lib/libjaegertracing_plugin.so /etc/nginx/opentracing.json;\r\n"
actual = buildOpentracing(cfgJaeger)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
cfgZipkin := config.Configuration{
EnableOpentracing: true,
ZipkinCollectorHost: "zipkin-host.com",
}
expected = "opentracing_load_tracer /usr/local/lib/libzipkin_opentracing.so /etc/nginx/opentracing.json;\r\n"
actual = buildOpentracing(cfgZipkin)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
}
func TestEnforceRegexModifier(t *testing.T) {
invalidType := &ingress.Ingress{}
expected := false
actual := enforceRegexModifier(invalidType)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
locs := []*ingress.Location{
{
Rewrite: rewrite.Config{
Target: "/alright",
UseRegex: true,
},
Path: "/ok",
},
}
expected = true
actual = enforceRegexModifier(locs)
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
}
func TestStripLocationModifer(t *testing.T) {
expected := "ok.com"
actual := stripLocationModifer("~*ok.com")
if expected != actual {
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
}
}