Make APIServer manage its own port allocations

This means we will no longer need to pass a free port into the APIServer
constructor.
This commit is contained in:
Hannes Hörl 2017-12-12 15:46:53 +00:00 committed by Gareth Smith
parent d62ff04228
commit 657963b319
7 changed files with 501 additions and 93 deletions

View File

@ -3,7 +3,6 @@ package test
import ( import (
"fmt" "fmt"
"io" "io"
"net/url"
"os/exec" "os/exec"
"time" "time"
@ -14,6 +13,7 @@ import (
// APIServer knows how to run a kubernetes apiserver. Set it up with the path to a precompiled binary. // APIServer knows how to run a kubernetes apiserver. Set it up with the path to a precompiled binary.
type APIServer struct { type APIServer struct {
AddressManager AddressManager
PathFinder BinPathFinder PathFinder BinPathFinder
ProcessStarter simpleSessionStarter ProcessStarter simpleSessionStarter
CertDirManager certDirManager CertDirManager certDirManager
@ -52,7 +52,10 @@ func NewAPIServer(config *APIServerConfig) (*APIServer, error) {
// URL returns the URL APIServer is listening on. Clients can use this to connect to APIServer. // URL returns the URL APIServer is listening on. Clients can use this to connect to APIServer.
func (s *APIServer) URL() string { func (s *APIServer) URL() string {
return s.Config.APIServerURL // TODO handle errors
port, _ := s.AddressManager.Port()
host, _ := s.AddressManager.Host()
return fmt.Sprintf("http://%s:%d", host, port)
} }
// Start starts the apiserver, waits for it to come up, and returns an error, if occoured. // Start starts the apiserver, waits for it to come up, and returns an error, if occoured.
@ -60,28 +63,31 @@ func (s *APIServer) Start() error {
if s.PathFinder == nil { if s.PathFinder == nil {
s.PathFinder = DefaultBinPathFinder s.PathFinder = DefaultBinPathFinder
} }
if s.AddressManager == nil {
s.AddressManager = &DefaultAddressManager{}
}
if err := s.Config.Validate(); err != nil { if err := s.Config.Validate(); err != nil {
return err return err
} }
err := s.Etcd.Start() port, addr, err := s.AddressManager.Initialize("localhost")
if err != nil { if err != nil {
return err return err
} }
s.stdOut = gbytes.NewBuffer()
s.stdErr = gbytes.NewBuffer()
certDir, err := s.CertDirManager.Create() certDir, err := s.CertDirManager.Create()
if err != nil { if err != nil {
return err return err
} }
clientURL, err := url.Parse(s.Config.APIServerURL) err = s.Etcd.Start()
if err != nil { if err != nil {
return err return err
} }
s.stdOut = gbytes.NewBuffer()
s.stdErr = gbytes.NewBuffer()
args := []string{ args := []string{
"--authorization-mode=Node,RBAC", "--authorization-mode=Node,RBAC",
"--runtime-config=admissionregistration.k8s.io/v1alpha1", "--runtime-config=admissionregistration.k8s.io/v1alpha1",
@ -92,11 +98,11 @@ func (s *APIServer) Start() error {
"--storage-backend=etcd3", "--storage-backend=etcd3",
fmt.Sprintf("--etcd-servers=%s", s.Etcd.URL()), fmt.Sprintf("--etcd-servers=%s", s.Etcd.URL()),
fmt.Sprintf("--cert-dir=%s", certDir), fmt.Sprintf("--cert-dir=%s", certDir),
fmt.Sprintf("--insecure-port=%s", clientURL.Port()), fmt.Sprintf("--insecure-port=%d", port),
fmt.Sprintf("--insecure-bind-address=%s", clientURL.Hostname()), fmt.Sprintf("--insecure-bind-address=%s", addr),
} }
detectedStart := s.stdErr.Detect(fmt.Sprintf("Serving insecurely on %s", clientURL.Host)) detectedStart := s.stdErr.Detect(fmt.Sprintf("Serving insecurely on %s:%d", addr, port))
timedOut := time.After(20 * time.Second) timedOut := time.After(20 * time.Second)
command := exec.Command(s.PathFinder("kube-apiserver"), args...) command := exec.Command(s.PathFinder("kube-apiserver"), args...)

View File

@ -4,7 +4,7 @@ import "github.com/asaskevich/govalidator"
// APIServerConfig is a struct holding data to configure the API Server process // APIServerConfig is a struct holding data to configure the API Server process
type APIServerConfig struct { type APIServerConfig struct {
APIServerURL string `valid:"required,url"` APIServerURL string `valid:"url"`
} }
// Validate checks that the config contains only valid URLs // Validate checks that the config contains only valid URLs

View File

@ -16,12 +16,6 @@ var _ = Describe("APIServerConfig", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
It("errors on empty config", func() {
conf := &APIServerConfig{}
err := conf.Validate()
Expect(err).To(MatchError(ContainSubstring("APIServerURL: non zero value required")))
})
It("errors on malformed URLs", func() { It("errors on malformed URLs", func() {
conf := &APIServerConfig{ conf := &APIServerConfig{
APIServerURL: "something not URLish", APIServerURL: "something not URLish",

View File

@ -23,6 +23,7 @@ var _ = Describe("Apiserver", func() {
apiServerConfig *APIServerConfig apiServerConfig *APIServerConfig
fakeEtcdProcess *testfakes.FakeFixtureProcess fakeEtcdProcess *testfakes.FakeFixtureProcess
fakePathFinder *testfakes.FakeBinPathFinder fakePathFinder *testfakes.FakeBinPathFinder
fakeAddressManager *testfakes.FakeAddressManager
) )
BeforeEach(func() { BeforeEach(func() {
@ -30,11 +31,13 @@ var _ = Describe("Apiserver", func() {
fakeCertDirManager = &testfakes.FakeCertDirManager{} fakeCertDirManager = &testfakes.FakeCertDirManager{}
fakeEtcdProcess = &testfakes.FakeFixtureProcess{} fakeEtcdProcess = &testfakes.FakeFixtureProcess{}
fakePathFinder = &testfakes.FakeBinPathFinder{} fakePathFinder = &testfakes.FakeBinPathFinder{}
fakeAddressManager = &testfakes.FakeAddressManager{}
apiServerConfig = &APIServerConfig{ apiServerConfig = &APIServerConfig{
APIServerURL: "http://this.is.the.API.server:8080", APIServerURL: "",
} }
apiServer = &APIServer{ apiServer = &APIServer{
AddressManager: fakeAddressManager,
PathFinder: fakePathFinder.Spy, PathFinder: fakePathFinder.Spy,
CertDirManager: fakeCertDirManager, CertDirManager: fakeCertDirManager,
Config: apiServerConfig, Config: apiServerConfig,
@ -42,104 +45,150 @@ var _ = Describe("Apiserver", func() {
} }
}) })
It("can be queried for the URL it listens on", func() { Describe("starting and stopping the server", func() {
Expect(apiServer.URL()).To(Equal("http://this.is.the.API.server:8080")) Context("when given a path to a binary that runs for a long time", func() {
}) It("can start and stop that binary", func() {
sessionBuffer := gbytes.NewBuffer()
fmt.Fprint(sessionBuffer, "Everything is fine")
fakeSession.BufferReturns(sessionBuffer)
Context("when given a path to a binary that runs for a long time", func() { fakeSession.ExitCodeReturnsOnCall(0, -1)
It("can start and stop that binary", func() { fakeSession.ExitCodeReturnsOnCall(1, 143)
sessionBuffer := gbytes.NewBuffer()
fmt.Fprint(sessionBuffer, "Everything is fine")
fakeSession.BufferReturns(sessionBuffer)
fakeSession.ExitCodeReturnsOnCall(0, -1) fakePathFinder.Returns("/some/path/to/apiserver")
fakeSession.ExitCodeReturnsOnCall(1, 143) fakeAddressManager.InitializeReturns(1234, "this.is.the.API.server", nil)
fakePathFinder.Returns("/some/path/to/apiserver") apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
Expect(command.Args).To(ContainElement("--insecure-port=1234"))
Expect(command.Args).To(ContainElement("--insecure-bind-address=this.is.the.API.server"))
Expect(command.Path).To(Equal("/some/path/to/apiserver"))
fmt.Fprint(err, "Serving insecurely on this.is.the.API.server:1234")
return fakeSession, nil
}
apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) { By("Starting the API Server")
Expect(command.Path).To(Equal("/some/path/to/apiserver")) err := apiServer.Start()
fmt.Fprint(err, "Serving insecurely on this.is.the.API.server:8080") Expect(err).NotTo(HaveOccurred())
return fakeSession, nil
}
By("Starting the API Server") By("...in turn starting Etcd")
err := apiServer.Start() Expect(fakeEtcdProcess.StartCallCount()).To(Equal(1),
Expect(err).NotTo(HaveOccurred()) "the Etcd process should be started exactly once")
By("starting Etcd") By("...in turn calling the PathFinder")
Expect(fakeEtcdProcess.StartCallCount()).To(Equal(1), Expect(fakePathFinder.CallCount()).To(Equal(1))
"the Etcd process should be started exactly once") Expect(fakePathFinder.ArgsForCall(0)).To(Equal("kube-apiserver"))
By("...in turn calls the PathFinder") By("...in turn calling the PortFinder")
Expect(fakePathFinder.CallCount()).To(Equal(1)) Expect(fakeAddressManager.InitializeCallCount()).To(Equal(1))
Expect(fakePathFinder.ArgsForCall(0)).To(Equal("kube-apiserver")) Expect(fakeAddressManager.InitializeArgsForCall(0)).To(Equal("localhost"))
Eventually(apiServer).Should(gbytes.Say("Everything is fine")) Eventually(apiServer).Should(gbytes.Say("Everything is fine"))
Expect(fakeSession.ExitCodeCallCount()).To(Equal(0)) Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
Expect(apiServer).NotTo(gexec.Exit()) Expect(apiServer).NotTo(gexec.Exit())
Expect(fakeSession.ExitCodeCallCount()).To(Equal(1)) Expect(fakeSession.ExitCodeCallCount()).To(Equal(1))
Expect(fakeCertDirManager.CreateCallCount()).To(Equal(1)) Expect(fakeCertDirManager.CreateCallCount()).To(Equal(1))
By("Stopping the API Server") By("Stopping the API Server")
apiServer.Stop() apiServer.Stop()
Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1)) Expect(fakeEtcdProcess.StopCallCount()).To(Equal(1))
Expect(apiServer).To(gexec.Exit(143)) Expect(apiServer).To(gexec.Exit(143))
Expect(fakeSession.TerminateCallCount()).To(Equal(1)) Expect(fakeSession.TerminateCallCount()).To(Equal(1))
Expect(fakeSession.WaitCallCount()).To(Equal(1)) Expect(fakeSession.WaitCallCount()).To(Equal(1))
Expect(fakeSession.ExitCodeCallCount()).To(Equal(2)) Expect(fakeSession.ExitCodeCallCount()).To(Equal(2))
Expect(fakeCertDirManager.DestroyCallCount()).To(Equal(1)) Expect(fakeCertDirManager.DestroyCallCount()).To(Equal(1))
})
}) })
})
Context("when starting etcd fails", func() { Context("when starting etcd fails", func() {
It("propagates the error, and does not start the process", func() { It("propagates the error, and does not start the process", func() {
fakeEtcdProcess.StartReturnsOnCall(0, fmt.Errorf("starting etcd failed")) fakeEtcdProcess.StartReturnsOnCall(0, fmt.Errorf("starting etcd failed"))
apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) { apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
Expect(true).To(BeFalse(), Expect(true).To(BeFalse(),
"the api server process starter shouldn't be called if starting etcd fails") "the api server process starter shouldn't be called if starting etcd fails")
return nil, nil return nil, nil
} }
err := apiServer.Start() err := apiServer.Start()
Expect(err).To(MatchError(ContainSubstring("starting etcd failed"))) Expect(err).To(MatchError(ContainSubstring("starting etcd failed")))
})
}) })
})
Context("when the certificate directory cannot be created", func() { Context("when the certificate directory cannot be created", func() {
It("propagates the error, and does not start the process", func() { It("propagates the error, and does not start any process", func() {
fakeCertDirManager.CreateReturnsOnCall(0, "", fmt.Errorf("Error on cert directory creation.")) fakeCertDirManager.CreateReturnsOnCall(0, "", fmt.Errorf("Error on cert directory creation."))
apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) { apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
Expect(true).To(BeFalse(), Expect(true).To(BeFalse(),
"the api server process starter shouldn't be called if creating the cert dir fails") "the api server process starter shouldn't be called if creating the cert dir fails")
return nil, nil return nil, nil
} }
err := apiServer.Start() err := apiServer.Start()
Expect(err).To(MatchError(ContainSubstring("Error on cert directory creation."))) Expect(err).To(MatchError(ContainSubstring("Error on cert directory creation.")))
Expect(fakeEtcdProcess.StartCallCount()).To(Equal(0))
})
}) })
})
Context("when the starter returns an error", func() { Context("when the address manager fails to get a new address", func() {
It("propagates the error", func() { It("propagates the error and does not start any process", func() {
apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) { fakeAddressManager.InitializeReturns(0, "", fmt.Errorf("some error finding a free port"))
return nil, fmt.Errorf("Some error in the apiserver starter.")
}
err := apiServer.Start() apiServer.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
Expect(err).To(MatchError(ContainSubstring("Some error in the apiserver starter."))) Expect(true).To(BeFalse(),
"the api server process starter shouldn't be called if getting a free port fails")
return nil, nil
}
Expect(apiServer.Start()).To(MatchError(ContainSubstring("some error finding a free port")))
Expect(fakeEtcdProcess.StartCallCount()).To(Equal(0))
})
}) })
Context("when the starter returns an error", func() {
It("propagates the error", func() {
apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
return nil, fmt.Errorf("Some error in the apiserver starter.")
}
err := apiServer.Start()
Expect(err).To(MatchError(ContainSubstring("Some error in the apiserver starter.")))
})
})
Context("when we try to stop a server that hasn't been started", func() {
It("is a noop and does not call exit on the session", func() {
apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) {
return fakeSession, nil
}
apiServer.Stop()
Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
})
})
}) })
Context("when we try to stop a server that hasn't been started", func() { Describe("querying the server for its URL", func() {
It("is a noop and does not call exit on the session", func() { It("can be queried for the URL it listens on", func() {
apiServer.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) { fakeAddressManager.HostReturns("the.host.for.api.server", nil)
return fakeSession, nil fakeAddressManager.PortReturns(5678, nil)
} Expect(apiServer.URL()).To(Equal("http://the.host.for.api.server:5678"))
apiServer.Stop() })
Expect(fakeSession.ExitCodeCallCount()).To(Equal(0))
Context("when we query for the URL before starting the server", func() {
Context("and so the addressmanager fails to give us a port", func() {
It("propagates the failure", func() {
//TODO
})
})
Context("and so the addressmanager fails to give us a host", func() {
It("propagates the failure", func() {
//TODO
})
})
}) })
}) })
}) })

View File

@ -5,11 +5,70 @@ import (
"net" "net"
) )
// AddressManager knows how to generate and remember a single address on some
// local interface for a service to listen on.
type AddressManager interface {
Initialize(host string) (port int, resolvedAddress string, err error)
Host() (string, error)
Port() (int, error)
}
//go:generate counterfeiter . AddressManager
// DefaultAddressManager implements an AddressManager. It allocates a new address
// (interface & port) a process can bind and keeps track of that.
type DefaultAddressManager struct {
port int
host string
}
// Initialize returns a address a process can listen on. Given a hostname it returns an address,
// a tuple consisting of a free port and the hostname resolved to its IP.
func (d *DefaultAddressManager) Initialize(host string) (port int, resolvedHost string, err error) {
if d.port != 0 {
return 0, "", fmt.Errorf("this DefaultAddressManager is already initialized")
}
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:0", host))
if err != nil {
return
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return
}
d.port = l.Addr().(*net.TCPAddr).Port
defer func() {
err = l.Close()
}()
d.host = addr.IP.String()
return d.port, d.host, nil
}
// Port returns the port that this DefaultAddressManager is managing. Port returns an
// error if this DefaultAddressManager has not yet been initialized.
func (d *DefaultAddressManager) Port() (int, error) {
if d.port == 0 {
return 0, fmt.Errorf("this DefaultAdressManager has is not initialized yet")
}
return d.port, nil
}
// Host returns the host that this DefaultAddressManager is managing. Host returns an
// error if this DefaultAddressManager has not yet been initialized.
func (d *DefaultAddressManager) Host() (string, error) {
if d.host == "" {
return "", fmt.Errorf("this DefaultAdressManager has is not initialized yet")
}
return d.host, nil
}
// PortFinder is the signature of a function returning a free port and a resolved // PortFinder is the signature of a function returning a free port and a resolved
// address to listen/bind on, and an erro in case there were some problems finding // address to listen/bind on, and an erro in case there were some problems finding
// a free pair of address & port // a free pair of address & port
type PortFinder func(host string) (port int, resolvedAddress string, err error) type PortFinder func(host string) (port int, resolvedAddress string, err error)
//go:generate counterfeiter . PortFinder
// DefaultPortFinder is the default implementation of PortFinder: It resolves that // DefaultPortFinder is the default implementation of PortFinder: It resolves that
// hostname or IP handed in and asks the kernel for a random port. To make that a bit // hostname or IP handed in and asks the kernel for a random port. To make that a bit
// safer, it also tries to bind to that port to make sure it is not in use. If all goes // safer, it also tries to bind to that port to make sure it is not in use. If all goes

View File

@ -3,10 +3,90 @@ package test_test
import ( import (
. "k8s.io/kubectl/pkg/framework/test" . "k8s.io/kubectl/pkg/framework/test"
"fmt"
"net"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
var _ = Describe("DefaultAddressManager", func() {
var defaultAddressManager *DefaultAddressManager
BeforeEach(func() {
defaultAddressManager = &DefaultAddressManager{}
})
Describe("Initialize", func() {
It("returns a free port and an address to bind to", func() {
port, host, err := defaultAddressManager.Initialize("localhost")
Expect(err).NotTo(HaveOccurred())
Expect(host).To(Equal("127.0.0.1"))
Expect(port).NotTo(Equal(0))
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
Expect(err).NotTo(HaveOccurred())
l, err := net.ListenTCP("tcp", addr)
defer func() {
Expect(l.Close()).To(Succeed())
}()
Expect(err).NotTo(HaveOccurred())
})
Context("when given an invalid hostname", func() {
It("propagates the error", func() {
_, _, err := defaultAddressManager.Initialize("this is not a hostname")
Expect(err).To(MatchError(ContainSubstring("no such host")))
})
})
Context("when given a hostname that we don't have permission to listen on", func() {
It("propagates the error", func() {
_, _, err := defaultAddressManager.Initialize("example.com")
Expect(err).To(MatchError(ContainSubstring("bind: can't assign requested address")))
})
})
Context("initialized multiple times", func() {
It("fails", func() {
_, _, err := defaultAddressManager.Initialize("localhost")
Expect(err).NotTo(HaveOccurred())
_, _, err = defaultAddressManager.Initialize("localhost")
Expect(err).To(MatchError(ContainSubstring("already initialized")))
})
})
})
Describe("Port", func() {
It("returns an error if Initialize has not been called yet", func() {
_, err := defaultAddressManager.Port()
Expect(err).To(MatchError(ContainSubstring("not initialized yet")))
})
It("returns the same port as previously allocated by Initialize", func() {
expectedPort, _, err := defaultAddressManager.Initialize("localhost")
Expect(err).NotTo(HaveOccurred())
actualPort, err := defaultAddressManager.Port()
Expect(err).NotTo(HaveOccurred())
Expect(actualPort).To(Equal(expectedPort))
})
})
Describe("Host", func() {
It("returns an error if Initialize has not been called yet", func() {
_, err := defaultAddressManager.Host()
Expect(err).To(MatchError(ContainSubstring("not initialized yet")))
})
It("returns the same port as previously allocated by Initialize", func() {
_, expectedHost, err := defaultAddressManager.Initialize("localhost")
Expect(err).NotTo(HaveOccurred())
actualHost, err := defaultAddressManager.Host()
Expect(err).NotTo(HaveOccurred())
Expect(actualHost).To(Equal(expectedHost))
})
})
})
var _ = Describe("DefaultPortFinder", func() { var _ = Describe("DefaultPortFinder", func() {
It("returns a free port and an address to bind to", func() { It("returns a free port and an address to bind to", func() {
port, addr, err := DefaultPortFinder("127.0.0.1") port, addr, err := DefaultPortFinder("127.0.0.1")

View File

@ -0,0 +1,220 @@
// Code generated by counterfeiter. DO NOT EDIT.
package testfakes
import (
"sync"
"k8s.io/kubectl/pkg/framework/test"
)
type FakeAddressManager struct {
InitializeStub func(host string) (port int, resolvedAddress string, err error)
initializeMutex sync.RWMutex
initializeArgsForCall []struct {
host string
}
initializeReturns struct {
result1 int
result2 string
result3 error
}
initializeReturnsOnCall map[int]struct {
result1 int
result2 string
result3 error
}
HostStub func() (string, error)
hostMutex sync.RWMutex
hostArgsForCall []struct{}
hostReturns struct {
result1 string
result2 error
}
hostReturnsOnCall map[int]struct {
result1 string
result2 error
}
PortStub func() (int, error)
portMutex sync.RWMutex
portArgsForCall []struct{}
portReturns struct {
result1 int
result2 error
}
portReturnsOnCall map[int]struct {
result1 int
result2 error
}
invocations map[string][][]interface{}
invocationsMutex sync.RWMutex
}
func (fake *FakeAddressManager) Initialize(host string) (port int, resolvedAddress string, err error) {
fake.initializeMutex.Lock()
ret, specificReturn := fake.initializeReturnsOnCall[len(fake.initializeArgsForCall)]
fake.initializeArgsForCall = append(fake.initializeArgsForCall, struct {
host string
}{host})
fake.recordInvocation("Initialize", []interface{}{host})
fake.initializeMutex.Unlock()
if fake.InitializeStub != nil {
return fake.InitializeStub(host)
}
if specificReturn {
return ret.result1, ret.result2, ret.result3
}
return fake.initializeReturns.result1, fake.initializeReturns.result2, fake.initializeReturns.result3
}
func (fake *FakeAddressManager) InitializeCallCount() int {
fake.initializeMutex.RLock()
defer fake.initializeMutex.RUnlock()
return len(fake.initializeArgsForCall)
}
func (fake *FakeAddressManager) InitializeArgsForCall(i int) string {
fake.initializeMutex.RLock()
defer fake.initializeMutex.RUnlock()
return fake.initializeArgsForCall[i].host
}
func (fake *FakeAddressManager) InitializeReturns(result1 int, result2 string, result3 error) {
fake.InitializeStub = nil
fake.initializeReturns = struct {
result1 int
result2 string
result3 error
}{result1, result2, result3}
}
func (fake *FakeAddressManager) InitializeReturnsOnCall(i int, result1 int, result2 string, result3 error) {
fake.InitializeStub = nil
if fake.initializeReturnsOnCall == nil {
fake.initializeReturnsOnCall = make(map[int]struct {
result1 int
result2 string
result3 error
})
}
fake.initializeReturnsOnCall[i] = struct {
result1 int
result2 string
result3 error
}{result1, result2, result3}
}
func (fake *FakeAddressManager) Host() (string, error) {
fake.hostMutex.Lock()
ret, specificReturn := fake.hostReturnsOnCall[len(fake.hostArgsForCall)]
fake.hostArgsForCall = append(fake.hostArgsForCall, struct{}{})
fake.recordInvocation("Host", []interface{}{})
fake.hostMutex.Unlock()
if fake.HostStub != nil {
return fake.HostStub()
}
if specificReturn {
return ret.result1, ret.result2
}
return fake.hostReturns.result1, fake.hostReturns.result2
}
func (fake *FakeAddressManager) HostCallCount() int {
fake.hostMutex.RLock()
defer fake.hostMutex.RUnlock()
return len(fake.hostArgsForCall)
}
func (fake *FakeAddressManager) HostReturns(result1 string, result2 error) {
fake.HostStub = nil
fake.hostReturns = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *FakeAddressManager) HostReturnsOnCall(i int, result1 string, result2 error) {
fake.HostStub = nil
if fake.hostReturnsOnCall == nil {
fake.hostReturnsOnCall = make(map[int]struct {
result1 string
result2 error
})
}
fake.hostReturnsOnCall[i] = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *FakeAddressManager) Port() (int, error) {
fake.portMutex.Lock()
ret, specificReturn := fake.portReturnsOnCall[len(fake.portArgsForCall)]
fake.portArgsForCall = append(fake.portArgsForCall, struct{}{})
fake.recordInvocation("Port", []interface{}{})
fake.portMutex.Unlock()
if fake.PortStub != nil {
return fake.PortStub()
}
if specificReturn {
return ret.result1, ret.result2
}
return fake.portReturns.result1, fake.portReturns.result2
}
func (fake *FakeAddressManager) PortCallCount() int {
fake.portMutex.RLock()
defer fake.portMutex.RUnlock()
return len(fake.portArgsForCall)
}
func (fake *FakeAddressManager) PortReturns(result1 int, result2 error) {
fake.PortStub = nil
fake.portReturns = struct {
result1 int
result2 error
}{result1, result2}
}
func (fake *FakeAddressManager) PortReturnsOnCall(i int, result1 int, result2 error) {
fake.PortStub = nil
if fake.portReturnsOnCall == nil {
fake.portReturnsOnCall = make(map[int]struct {
result1 int
result2 error
})
}
fake.portReturnsOnCall[i] = struct {
result1 int
result2 error
}{result1, result2}
}
func (fake *FakeAddressManager) Invocations() map[string][][]interface{} {
fake.invocationsMutex.RLock()
defer fake.invocationsMutex.RUnlock()
fake.initializeMutex.RLock()
defer fake.initializeMutex.RUnlock()
fake.hostMutex.RLock()
defer fake.hostMutex.RUnlock()
fake.portMutex.RLock()
defer fake.portMutex.RUnlock()
copiedInvocations := map[string][][]interface{}{}
for key, value := range fake.invocations {
copiedInvocations[key] = value
}
return copiedInvocations
}
func (fake *FakeAddressManager) recordInvocation(key string, args []interface{}) {
fake.invocationsMutex.Lock()
defer fake.invocationsMutex.Unlock()
if fake.invocations == nil {
fake.invocations = map[string][][]interface{}{}
}
if fake.invocations[key] == nil {
fake.invocations[key] = [][]interface{}{}
}
fake.invocations[key] = append(fake.invocations[key], args)
}
var _ test.AddressManager = new(FakeAddressManager)