text: package argotunnel
  
  import (
  	"fmt"
  	"testing"
  
  	logtest "github.com/sirupsen/logrus/hooks/test"
  	"github.com/stretchr/testify/assert"
  	"github.com/stretchr/testify/mock"
  	"k8s.io/api/core/v1"
  	"k8s.io/api/extensions/v1beta1"
  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  	"k8s.io/apimachinery/pkg/util/intstr"
  	"k8s.io/client-go/tools/cache"
  )
  
  func TestHandleResource(t *testing.T) {
  	t.Parallel()
  	for name, test := range map[string]struct {
  		tr   *syncTranslator
  		kind string
  		key  string
  		out  error
  	}{
  		"kind-unexpected": {
  			tr:   newMockedSyncTranslator(),
  			kind: "unit",
  			key:  "unit/unit",
  			out:  fmt.Errorf("unexpected kind (%q) in key (%q)", "unit", "unit/unit"),
  		},
  		"kind-endpoint-idx-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(struct{}{}, false, fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					ingress: &mockSharedIndexInformer{},
  					secret:  &mockSharedIndexInformer{},
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "endpoint",
  			key:  "unit/svc-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  		"kind-ingress-idx-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: &mockSharedIndexInformer{},
  					ingress: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/ing-a").Return(struct{}{}, false, fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					secret:  &mockSharedIndexInformer{},
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "ingress",
  			key:  "unit/ing-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  		"kind-secret-idx-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: &mockSharedIndexInformer{},
  					ingress:  &mockSharedIndexInformer{},
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(struct{}{}, false, fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "secret",
  			key:  "unit/sec-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  		"kind-service-idx-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: &mockSharedIndexInformer{},
  					ingress:  &mockSharedIndexInformer{},
  					secret:   &mockSharedIndexInformer{},
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(struct{}{}, false, fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  				},
  			},
  			kind: "service",
  			key:  "unit/svc-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  	} {
  		logger, hook := logtest.NewNullLogger()
  		test.tr.log = logger
  		out := test.tr.handleResource(test.kind, test.key)
  		assert.Equalf(t, test.out, out, "test '%s' error mismatch", name)
  		hook.Reset()
  		assert.Nil(t, hook.LastEntry())
  	}
  }
  
  func TestHandleByKind(t *testing.T) {
  	t.Parallel()
  	for name, test := range map[string]struct {
  		tr   *syncTranslator
  		kind string
  		key  string
  		out  error
  	}{
  		"kind-unexpected": {
  			tr:   newMockedSyncTranslator(),
  			kind: "unit",
  			key:  "unit/unit",
  			out:  fmt.Errorf("unexpected kind (%q)", "unit"),
  		},
  		"kind-secret-idx-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: &mockSharedIndexInformer{},
  					ingress:  &mockSharedIndexInformer{},
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(struct{}{}, false, fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "secret",
  			key:  "unit/sec-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  		"kind-secret-idx-update-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: &mockSharedIndexInformer{},
  					ingress: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("ByIndex", "secret", "unit/sec-a").Return(make([]interface{}, 0), fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(struct{}{}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "secret",
  			key:  "unit/sec-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  		"kind-secret-idx-delete-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: &mockSharedIndexInformer{},
  					ingress: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("IndexKeys", "secret", "unit/sec-a").Return(make([]string, 0), fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(struct{}{}, false, nil)
  							return idx
  						}())
  						return i
  					}(),
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "secret",
  			key:  "unit/sec-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  	} {
  		logger, hook := logtest.NewNullLogger()
  		test.tr.log = logger
  		out := test.tr.handleByKind(test.kind, test.key)
  		assert.Equalf(t, test.out, out, "test '%s' error mismatch", name)
  		hook.Reset()
  		assert.Nil(t, hook.LastEntry())
  	}
  }
  
  func TestHandleEndpoint(t *testing.T) {
  	t.Parallel()
  	for name, test := range map[string]struct {
  		tr   *syncTranslator
  		kind string
  		key  string
  		out  error
  	}{
  		"kind-endpoint-idx-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(struct{}{}, false, fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					ingress: &mockSharedIndexInformer{},
  					secret:  &mockSharedIndexInformer{},
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "endpoint",
  			key:  "unit/svc-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  		"kind-endpoint-idx-update-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(struct{}{}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  					ingress: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("ByIndex", "service", "unit/svc-a").Return(make([]interface{}, 0), fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					secret:  &mockSharedIndexInformer{},
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "endpoint",
  			key:  "unit/svc-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  		"kind-secret-idx-delete-err": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(struct{}{}, false, nil)
  							return idx
  						}())
  						return i
  					}(),
  					ingress: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("IndexKeys", "service", "unit/svc-a").Return(make([]string, 0), fmt.Errorf("short-circuit"))
  							return idx
  						}())
  						return i
  					}(),
  					secret:  &mockSharedIndexInformer{},
  					service: &mockSharedIndexInformer{},
  				},
  			},
  			kind: "secret",
  			key:  "unit/svc-a",
  			out:  fmt.Errorf("short-circuit"),
  		},
  	} {
  		logger, hook := logtest.NewNullLogger()
  		test.tr.log = logger
  		out := test.tr.handleEndpoint(test.kind, test.key)
  		assert.Equalf(t, test.out, out, "test '%s' error mismatch", name)
  		hook.Reset()
  		assert.Nil(t, hook.LastEntry())
  	}
  }
  
  func TestGetRouteFromIngress(t *testing.T) {
  	t.Parallel()
  	for name, test := range map[string]struct {
  		tr  *syncTranslator
  		ing *v1beta1.Ingress
  		out *tunnelRoute
  	}{
  		"ing-nil": {
  			tr:  newMockedSyncTranslator(),
  			ing: nil,
  			out: nil,
  		},
  		"ing-empty": {
  			tr: newMockedSyncTranslator(),
  			ing: &v1beta1.Ingress{
  				ObjectMeta: metav1.ObjectMeta{
  					Name:      "unit",
  					Namespace: "unit",
  				},
  				TypeMeta: metav1.TypeMeta{
  					Kind:       "Ingress",
  					APIVersion: "v1beta1",
  				},
  				Spec: v1beta1.IngressSpec{
  					TLS:   []v1beta1.IngressTLS{},
  					Rules: []v1beta1.IngressRule{},
  				},
  			},
  			out: &tunnelRoute{
  				name:      "unit",
  				namespace: "unit",
  				links:     tunnelRouteLinkMap{},
  			},
  		},
  		"ing-add-rule": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Endpoints{
  								Subsets: []v1.EndpointSubset{
  									{
  										Addresses: []v1.EndpointAddress{
  											{
  												IP:       "1.1.1.1",
  												Hostname: "unit.com",
  											},
  										},
  									},
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  					ingress: &mockSharedIndexInformer{},
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(&v1.Secret{
  								Data: map[string][]byte{
  									"cert.pem": genCertforHost("a.unit.com"),
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Service{
  								Spec: v1.ServiceSpec{
  									Ports: []v1.ServicePort{
  										{
  											Name:       "http",
  											Port:       8080,
  											TargetPort: intstr.FromInt(9090),
  											Protocol:   v1.ProtocolTCP,
  										},
  									},
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: func() tunnelRouter {
  					r := &mockTunnelRouter{}
  					return r
  				}(),
  			},
  			ing: &v1beta1.Ingress{
  				ObjectMeta: metav1.ObjectMeta{
  					Name:      "unit",
  					Namespace: "unit",
  				},
  				TypeMeta: metav1.TypeMeta{
  					Kind:       "Ingress",
  					APIVersion: "v1beta1",
  				},
  				Spec: v1beta1.IngressSpec{
  					TLS: []v1beta1.IngressTLS{
  						{
  							Hosts: []string{
  								"a.unit.com",
  							},
  							SecretName: "sec-a",
  						},
  					},
  					Rules: []v1beta1.IngressRule{
  						{
  							Host: "a.unit.com",
  							IngressRuleValue: v1beta1.IngressRuleValue{
  								HTTP: &v1beta1.HTTPIngressRuleValue{
  									Paths: []v1beta1.HTTPIngressPath{
  										{
  											Backend: v1beta1.IngressBackend{
  												ServiceName: "svc-a",
  												ServicePort: intstr.FromString("http"),
  											},
  										},
  									},
  								},
  							},
  						},
  					},
  				},
  			},
  			out: &tunnelRoute{
  				name:      "unit",
  				namespace: "unit",
  				links: tunnelRouteLinkMap{
  					tunnelRule{
  						host: "a.unit.com",
  						port: 8080,
  						service: resource{
  							namespace: "unit",
  							name:      "svc-a",
  						},
  						secret: resource{
  							namespace: "unit",
  							name:      "sec-a",
  						},
  					}: nil,
  				},
  			},
  		},
  	} {
  		logger, hook := logtest.NewNullLogger()
  		test.tr.log = logger
  		out := func() (r *tunnelRoute) {
  			if r = test.tr.getRouteFromIngress(test.ing); r != nil {
  				l := tunnelRouteLinkMap{}
  				for k := range r.links {
  					l[k] = nil
  				}
  				r.links = l
  			}
  			return
  		}()
  		assert.Equalf(t, test.out, out, "test '%s' route mismatch", name)
  		hook.Reset()
  		assert.Nil(t, hook.LastEntry())
  	}
  }
  
  func TestGetVerifiedCert(t *testing.T) {
  	t.Parallel()
  	for name, test := range map[string]struct {
  		tr     *syncTranslator
  		secret resource
  		host   string
  		cert   []byte
  		exists bool
  		err    error
  	}{
  		"secret-does-not-exist": {
  			tr: &syncTranslator{
  				informers: informerset{
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(&v1.Secret{}, false, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			secret: resource{
  				namespace: "unit",
  				name:      "sec-a",
  			},
  			host:   "a.unit.com",
  			cert:   nil,
  			exists: false,
  			err:    fmt.Errorf("secret 'unit/sec-a' does not exist"),
  		},
  		"secret-lookup-error": {
  			tr: &syncTranslator{
  				informers: informerset{
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(&v1.Secret{}, false, fmt.Errorf("lookup-error"))
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			secret: resource{
  				namespace: "unit",
  				name:      "sec-a",
  			},
  			host:   "a.unit.com",
  			cert:   nil,
  			exists: false,
  			err:    fmt.Errorf("lookup-error"),
  		},
  		"secret-no-cert": {
  			tr: &syncTranslator{
  				informers: informerset{
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(&v1.Secret{
  								Data: map[string][]byte{},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			secret: resource{
  				namespace: "unit",
  				name:      "sec-a",
  			},
  			host:   "a.unit.com",
  			cert:   nil,
  			exists: false,
  			err:    fmt.Errorf("secret 'unit/sec-a' missing 'cert.pem'"),
  		},
  		"secret-okay": {
  			tr: &syncTranslator{
  				informers: informerset{
  					secret: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/sec-a").Return(&v1.Secret{
  								Data: map[string][]byte{
  									"cert.pem": genCertforHost("a.unit.com"),
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			secret: resource{
  				namespace: "unit",
  				name:      "sec-a",
  			},
  			host:   "a.unit.com",
  			cert:   nil,
  			exists: true,
  			err:    nil,
  		},
  	} {
  		cert, exists, err := test.tr.getVerifiedCert(test.secret.namespace, test.secret.name, test.host)
  		assert.Equalf(t, test.exists, exists, "test '%s' exists mismatch", name)
  		assert.Equalf(t, test.err, err, "test '%s' error mismatch", name)
  		if exists {
  			assert.NotEmptyf(t, cert, "test '%s' cert not empty", name)
  		} else {
  			assert.Emptyf(t, cert, "test '%s' cert empty", name)
  		}
  	}
  }
  
  func TestGetVerifiedPort(t *testing.T) {
  	t.Parallel()
  	for name, test := range map[string]struct {
  		tr      *syncTranslator
  		service resource
  		port    intstr.IntOrString
  		out     int32
  		exists  bool
  		err     error
  	}{
  		"service-does-not-exist": {
  			tr: &syncTranslator{
  				informers: informerset{
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Service{}, false, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			service: resource{
  				namespace: "unit",
  				name:      "svc-a",
  			},
  			port:   intstr.FromInt(8080),
  			out:    0,
  			exists: false,
  			err:    fmt.Errorf("service 'unit/svc-a' does not exist"),
  		},
  		"service-lookup-error": {
  			tr: &syncTranslator{
  				informers: informerset{
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Service{}, false, fmt.Errorf("lookup-error"))
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			service: resource{
  				namespace: "unit",
  				name:      "svc-a",
  			},
  			port:   intstr.FromInt(8080),
  			out:    0,
  			exists: false,
  			err:    fmt.Errorf("lookup-error"),
  		},
  		"service-missing-port": {
  			tr: &syncTranslator{
  				informers: informerset{
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Service{
  								Spec: v1.ServiceSpec{
  									Ports: []v1.ServicePort{
  										{
  											Name:     "port-a",
  											Port:     8080,
  											Protocol: v1.ProtocolTCP,
  										},
  									},
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			service: resource{
  				namespace: "unit",
  				name:      "svc-a",
  			},
  			port:   intstr.FromString("port-b"),
  			out:    0,
  			exists: false,
  			err:    fmt.Errorf("service 'unit/svc-a' missing port 'port-b'"),
  		},
  		"endpoints-do-not-exist": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Endpoints{}, false, nil)
  							return idx
  						}())
  						return i
  					}(),
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Service{
  								Spec: v1.ServiceSpec{
  									Ports: []v1.ServicePort{
  										{
  											Name:     "port-a",
  											Port:     8080,
  											Protocol: v1.ProtocolTCP,
  										},
  									},
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			service: resource{
  				namespace: "unit",
  				name:      "svc-a",
  			},
  			port:   intstr.FromInt(8080),
  			out:    0,
  			exists: false,
  			err:    fmt.Errorf("endpoints 'unit/svc-a' do not exist"),
  		},
  		"endpoints-lookup-error": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Endpoints{}, false, fmt.Errorf("lookup-error"))
  							return idx
  						}())
  						return i
  					}(),
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Service{
  								Spec: v1.ServiceSpec{
  									Ports: []v1.ServicePort{
  										{
  											Name:     "port-a",
  											Port:     8080,
  											Protocol: v1.ProtocolTCP,
  										},
  									},
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			service: resource{
  				namespace: "unit",
  				name:      "svc-a",
  			},
  			port:   intstr.FromInt(8080),
  			out:    0,
  			exists: false,
  			err:    fmt.Errorf("lookup-error"),
  		},
  		"endpoints-missing-subsets": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Endpoints{
  								Subsets: []v1.EndpointSubset{},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Service{
  								Spec: v1.ServiceSpec{
  									Ports: []v1.ServicePort{
  										{
  											Name:       "port-a",
  											Port:       8080,
  											TargetPort: intstr.FromInt(8080),
  											Protocol:   v1.ProtocolTCP,
  										},
  									},
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			service: resource{
  				namespace: "unit",
  				name:      "svc-a",
  			},
  			port:   intstr.FromInt(8080),
  			out:    0,
  			exists: false,
  			err:    fmt.Errorf("endpoints 'unit/svc-a' missing subsets for port '8080'"),
  		},
  		"service-endpoints-okay": {
  			tr: &syncTranslator{
  				informers: informerset{
  					endpoint: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Endpoints{
  								Subsets: []v1.EndpointSubset{
  									{
  										Addresses: []v1.EndpointAddress{
  											{
  												IP:       "1.1.1.1",
  												Hostname: "unit.com",
  											},
  										},
  									},
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  					service: func() cache.SharedIndexInformer {
  						i := &mockSharedIndexInformer{}
  						i.On("GetIndexer").Return(func() cache.Indexer {
  							idx := &mockIndexer{}
  							idx.On("GetByKey", "unit/svc-a").Return(&v1.Service{
  								Spec: v1.ServiceSpec{
  									Ports: []v1.ServicePort{
  										{
  											Name:       "port-a",
  											Port:       8080,
  											TargetPort: intstr.FromInt(9090),
  											Protocol:   v1.ProtocolTCP,
  										},
  									},
  								},
  							}, true, nil)
  							return idx
  						}())
  						return i
  					}(),
  				},
  				router: &mockTunnelRouter{},
  			},
  			service: resource{
  				namespace: "unit",
  				name:      "svc-a",
  			},
  			port:   intstr.FromInt(8080),
  			out:    8080,
  			exists: true,
  			err:    nil,
  		},
  	} {
  		out, exists, err := test.tr.getVerifiedPort(test.service.namespace, test.service.name, test.port)
  		assert.Equalf(t, test.out, out, "test '%s' port mismatch", name)
  		assert.Equalf(t, test.exists, exists, "test '%s' exists mismatch", name)
  		assert.Equalf(t, test.err, err, "test '%s' error mismatch", name)
  	}
  }
  
  func newMockedSyncTranslator() *syncTranslator {
  	return &syncTranslator{
  		informers: informerset{
  			endpoint: func() cache.SharedIndexInformer {
  				i := &mockSharedIndexInformer{}
  				return i
  			}(),
  			ingress: func() cache.SharedIndexInformer {
  				i := &mockSharedIndexInformer{}
  				return i
  			}(),
  			secret: func() cache.SharedIndexInformer {
  				i := &mockSharedIndexInformer{}
  				return i
  			}(),
  			service: func() cache.SharedIndexInformer {
  				i := &mockSharedIndexInformer{}
  				return i
  			}(),
  		},
  		router: func() tunnelRouter {
  			r := &mockTunnelRouter{}
  			return r
  		}(),
  	}
  }
  
  type mockTranslator struct {
  	mock.Mock
  }
  
  func (t *mockTranslator) handleResource(kind, key string) error {
  	args := t.Called(kind, key)
  	return args.Error(0)
  }
  func (t *mockTranslator) waitForCacheSync(stopCh <-chan struct{}) bool {
  	args := t.Called(stopCh)
  	return args.Get(0).(bool)
  }
  func (t *mockTranslator) run(stopCh <-chan struct{}) error {
  	args := t.Called(stopCh)
  	return args.Error(0)
  }
  