Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Added some proxy unit tests
  • Loading branch information
eko committed Jul 21, 2019
1 parent fff4eb4 commit 1a4e376
Show file tree
Hide file tree
Showing 16 changed files with 233 additions and 62 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
@@ -1,3 +1,5 @@
sudo: required

language: go
matrix:
include:
Expand All @@ -17,6 +19,7 @@ install:
- go get -t -v ./...

script:
- ifconfig lo:0 127.0.0.2 netmask 255.0.0.0 up
- go test -v ./...
- if [ "${LATEST}" = "true" ]; then gox -ldflags "-s -w -X main.Version=$TRAVIS_TAG" -os="linux darwin" -arch="386 amd64" -osarch="linux/arm" -output="monday-{{.OS}}-{{.Arch}}" -verbose ./...; fi

Expand Down
9 changes: 5 additions & 4 deletions Makefile
Expand Up @@ -10,10 +10,11 @@ generate-mocks: ## Generate mocks for tests
@echo "> generating mocks..."

# Monday
mockery -name=ProxyInterface -dir=pkg/proxy/ -output internal/tests/mocks
mockery -name=RunnerInterface -dir=pkg/runner/ -output internal/tests/mocks
mockery -name=ForwarderInterface -dir=pkg/forwarder/ -output internal/tests/mocks
mockery -name=WatcherInterface -dir=pkg/watcher/ -output internal/tests/mocks
mockery -name=HostfileInterface -dir=pkg/hostfile/ -output internal/tests/mocks/hostfile
mockery -name=ProxyInterface -dir=pkg/proxy/ -output internal/tests/mocks/proxy
mockery -name=RunnerInterface -dir=pkg/runner/ -output internal/tests/mocks/runner
mockery -name=ForwarderInterface -dir=pkg/forwarder/ -output internal/tests/mocks/forwarder
mockery -name=WatcherInterface -dir=pkg/watcher/ -output internal/tests/mocks/watcher

# Kubernetes AppsV1
mockery -name=Interface -dir=vendor/k8s.io/client-go/kubernetes/ -output internal/tests/mocks/kubernetes/client
Expand Down
9 changes: 8 additions & 1 deletion cmd/main.go
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/eko/monday/internal/config"
"github.com/eko/monday/pkg/forwarder"
"github.com/eko/monday/pkg/hostfile"
"github.com/eko/monday/pkg/proxy"
"github.com/eko/monday/pkg/runner"
"github.com/eko/monday/pkg/watcher"
Expand Down Expand Up @@ -79,8 +80,14 @@ func run(conf *config.Config, choice string) {
panic(err)
}

// Initializes hosts file manager
hostfile, err := hostfile.NewClient()
if err != nil {
panic(err)
}

// Initializes proxy
proxyComponent = proxy.NewProxy()
proxyComponent = proxy.NewProxy(hostfile)

// Initializes runner
runnerComponent = runner.NewRunner(proxyComponent, project)
Expand Down
File renamed without changes.
38 changes: 38 additions & 0 deletions internal/tests/mocks/hostfile/HostfileInterface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion pkg/forwarder/forwarder_test.go
Expand Up @@ -5,7 +5,7 @@ import (
"testing"

"github.com/eko/monday/internal/config"
"github.com/eko/monday/internal/tests/mocks"
mocks "github.com/eko/monday/internal/tests/mocks/proxy"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
Expand Down
46 changes: 46 additions & 0 deletions pkg/hostfile/client.go
@@ -0,0 +1,46 @@
package hostfile

import "github.com/txn2/txeh"

type HostfileInterface interface {
AddHost(ip, hostname string) error
RemoveHost(hostname string) error
}

// Hostfile represents the host file manager client
type Hostfile struct {
hosts *txeh.Hosts
}

// NewClient returns a new Hostfile manager client
func NewClient() (*Hostfile, error) {
hosts, err := txeh.NewHostsDefault()
if err != nil {
panic(err)
}

return &Hostfile{
hosts: hosts,
}, err
}

// AddHost adds a new host / ip entry into the hosts file
func (h *Hostfile) AddHost(ip, hostname string) error {
h.hosts.Reload()
h.hosts.AddHost(ip, hostname)
err := h.hosts.Save()
if err != nil {
return err
}

return nil
}

// RemoveHost removes a given hostname from the hosts file
func (h *Hostfile) RemoveHost(hostname string) error {
h.hosts.Reload()
h.hosts.RemoveHost(hostname)
h.hosts.Save()

return nil
}
42 changes: 0 additions & 42 deletions pkg/hostfile/hostfile.go

This file was deleted.

15 changes: 12 additions & 3 deletions pkg/proxy/proxy.go
Expand Up @@ -11,6 +11,8 @@ import (
)

const (
// ProxyPortStart is the first port that will be allocated by the proxy component.
// Others will be incremented by 1 each time
ProxyPortStart = "9400"
)

Expand All @@ -20,8 +22,10 @@ type ProxyInterface interface {
AddProxyForward(name string, proxyForward *ProxyForward)
}

// Proxy represents the proxy component instance
type Proxy struct {
ProxyForwards map[string][]*ProxyForward
hostfile hostfile.HostfileInterface
listeners map[string]net.Listener
listening bool
addProxyForwardMux sync.Mutex
Expand All @@ -31,9 +35,11 @@ type Proxy struct {
ipLastByte int
}

func NewProxy() *Proxy {
// NewProxy initializes a new proxy component instance
func NewProxy(hostfile hostfile.HostfileInterface) *Proxy {
return &Proxy{
ProxyForwards: make(map[string][]*ProxyForward, 0),
hostfile: hostfile,
listeners: make(map[string]net.Listener),
listening: true,
latestPort: ProxyPortStart,
Expand Down Expand Up @@ -125,13 +131,16 @@ func (p *Proxy) AddProxyForward(name string, proxyForward *ProxyForward) {
p.addProxyForwardMux.Lock()
defer p.addProxyForwardMux.Unlock()

p.generateIP(proxyForward)
err := p.generateIP(proxyForward)
if err != nil {
fmt.Printf("❌ An error has occured while generating IP address for '%s': %v\n", proxyForward.Name, err)
}

if proxyForward.ProxyPort == "" {
p.generateProxyPort(proxyForward)
}

err := hostfile.AddHost(proxyForward.LocalIP, proxyForward.GetHostname())
err = p.hostfile.AddHost(proxyForward.LocalIP, proxyForward.GetHostname())
if err != nil {
fmt.Printf("❌ An error has occured while trying to write host file for application '%s' (ip: %s): %v\n", proxyForward.Name, proxyForward.LocalIP, err)
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/proxy/proxy_forward.go
Expand Up @@ -12,6 +12,7 @@ type ProxyForward struct {
ProxyPort string
}

// NewProxyForward returns a new proxy port-forward instance
func NewProxyForward(name, hostname, proxyHostname, localPort, forwardPort string) *ProxyForward {
proxyForward := &ProxyForward{
Name: name,
Expand All @@ -30,18 +31,23 @@ func NewProxyForward(name, hostname, proxyHostname, localPort, forwardPort strin
return proxyForward
}

// SetLocalIP sets local attributed IP to this forward
func (p *ProxyForward) SetLocalIP(ip string) {
p.LocalIP = ip
}

// SetProxyPort sets proxy attributed port to this forward
func (p *ProxyForward) SetProxyPort(port string) {
p.ProxyPort = port
}

// GetProxifiedPorts returns the couple of proxified ports (proxy attributed port:forward port)
func (p *ProxyForward) GetProxifiedPorts() string {
return fmt.Sprintf("%s:%s", p.ProxyPort, p.ForwardPort)
}

// GetHostname returns the hostname (if defined) of this proxy forward, elsewhere uses the
// service name
func (p *ProxyForward) GetHostname() string {
if p.Hostname != "" {
return p.Hostname
Expand Down
104 changes: 103 additions & 1 deletion pkg/proxy/proxy_test.go
Expand Up @@ -3,16 +3,118 @@ package proxy
import (
"testing"

mocks "github.com/eko/monday/internal/tests/mocks/hostfile"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

func TestNewProxy(t *testing.T) {
// Given

hostfileMock := &mocks.HostfileInterface{}

// When
proxy := NewProxy()
proxy := NewProxy(hostfileMock)

// Then
assert.IsType(t, new(Proxy), proxy)

assert.Len(t, proxy.ProxyForwards, 0)
assert.Len(t, proxy.attributedIPs, 0)
assert.Equal(t, proxy.latestPort, "9400")
assert.Equal(t, proxy.ipLastByte, 1)
}

func TestAddProxyForward(t *testing.T) {
// Given
pf := NewProxyForward("test", "hostname.svc.local", "", "8080", "8080")

hostfileMock := &mocks.HostfileInterface{}
hostfileMock.On("AddHost", mock.AnythingOfType("string"), "hostname.svc.local").Return(nil)

proxy := NewProxy(hostfileMock)

// When
proxy.AddProxyForward("test", pf)

// Then
assert.Len(t, proxy.ProxyForwards, 1)
assert.Len(t, proxy.attributedIPs, 1)
assert.Equal(t, proxy.latestPort, "9401")
assert.Equal(t, proxy.ipLastByte, 2)
}

func TestAddProxyForwardWhenMultiple(t *testing.T) {
// Given
testCases := []struct {
name string
hostname string
localPort string
forwardPort string
}{
{name: "test", hostname: "hostname.svc.local", localPort: "8080", forwardPort: "8081"},
{name: "test-2", hostname: "hostname2.svc.local", localPort: "8080", forwardPort: "8081"},
{name: "test-2", hostname: "hostname3.svc.local", localPort: "8081", forwardPort: "8082"},
}

hostfileMock := &mocks.HostfileInterface{}
hostfileMock.ExpectedCalls = []*mock.Call{
&mock.Call{
Method: "AddHost",
Arguments: mock.Arguments{
mock.AnythingOfType("string"), "hostname.svc.local",
},
ReturnArguments: mock.Arguments{nil},
},
&mock.Call{
Method: "AddHost",
Arguments: mock.Arguments{
mock.AnythingOfType("string"), "hostname2.svc.local",
},
ReturnArguments: mock.Arguments{nil},
},
&mock.Call{
Method: "AddHost",
Arguments: mock.Arguments{
mock.AnythingOfType("string"), "hostname3.svc.local",
},
ReturnArguments: mock.Arguments{nil},
},
}

proxy := NewProxy(hostfileMock)

// When
for _, testCase := range testCases {
pf := NewProxyForward(testCase.name, testCase.hostname, "", testCase.localPort, testCase.forwardPort)
proxy.AddProxyForward(testCase.name, pf)
}

// Then
assert.Len(t, proxy.ProxyForwards, 2)
assert.Len(t, proxy.attributedIPs, 2)
assert.Equal(t, proxy.latestPort, "9403")
assert.Equal(t, proxy.ipLastByte, 3)
}

func TestListen(t *testing.T) {
// Given
pf := NewProxyForward("test", "hostname.svc.local", "", "8080", "8080")

hostfileMock := &mocks.HostfileInterface{}
hostfileMock.On("AddHost", mock.AnythingOfType("string"), "hostname.svc.local").Return(nil)

proxy := NewProxy(hostfileMock)
proxy.AddProxyForward("test", pf)

// When
err := proxy.Listen()

// Then
assert.Nil(t, err)

assert.Len(t, proxy.ProxyForwards, 1)
assert.Len(t, proxy.attributedIPs, 1)
assert.Equal(t, proxy.latestPort, "9401")
assert.Equal(t, proxy.ipLastByte, 2)
}

0 comments on commit 1a4e376

Please sign in to comment.