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 (
"fmt"
"io"
"net/url"
"os/exec"
"time"
@ -14,6 +13,7 @@ import (
// APIServer knows how to run a kubernetes apiserver. Set it up with the path to a precompiled binary.
type APIServer struct {
AddressManager AddressManager
PathFinder BinPathFinder
ProcessStarter simpleSessionStarter
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.
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.
@ -60,28 +63,31 @@ func (s *APIServer) Start() error {
if s.PathFinder == nil {
s.PathFinder = DefaultBinPathFinder
}
if s.AddressManager == nil {
s.AddressManager = &DefaultAddressManager{}
}
if err := s.Config.Validate(); err != nil {
return err
}
err := s.Etcd.Start()
port, addr, err := s.AddressManager.Initialize("localhost")
if err != nil {
return err
}
s.stdOut = gbytes.NewBuffer()
s.stdErr = gbytes.NewBuffer()
certDir, err := s.CertDirManager.Create()
if err != nil {
return err
}
clientURL, err := url.Parse(s.Config.APIServerURL)
err = s.Etcd.Start()
if err != nil {
return err
}
s.stdOut = gbytes.NewBuffer()
s.stdErr = gbytes.NewBuffer()
args := []string{
"--authorization-mode=Node,RBAC",
"--runtime-config=admissionregistration.k8s.io/v1alpha1",
@ -92,11 +98,11 @@ func (s *APIServer) Start() error {
"--storage-backend=etcd3",
fmt.Sprintf("--etcd-servers=%s", s.Etcd.URL()),
fmt.Sprintf("--cert-dir=%s", certDir),
fmt.Sprintf("--insecure-port=%s", clientURL.Port()),
fmt.Sprintf("--insecure-bind-address=%s", clientURL.Hostname()),
fmt.Sprintf("--insecure-port=%d", port),
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)
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
type APIServerConfig struct {
APIServerURL string `valid:"required,url"`
APIServerURL string `valid:"url"`
}
// Validate checks that the config contains only valid URLs

View File

@ -16,12 +16,6 @@ var _ = Describe("APIServerConfig", func() {
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() {
conf := &APIServerConfig{
APIServerURL: "something not URLish",

View File

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

View File

@ -3,10 +3,90 @@ package test_test
import (
. "k8s.io/kubectl/pkg/framework/test"
"fmt"
"net"
. "github.com/onsi/ginkgo"
. "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() {
It("returns a free port and an address to bind to", func() {
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)