Merge pull request #4813 from tstromberg/cluster_test

Make cluster_test and utils_test run in isolation
pull/4825/head
Thomas Strömberg 2019-07-19 16:48:26 -07:00 committed by GitHub
commit 784717c007
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 178 additions and 108 deletions

View File

@ -20,7 +20,6 @@ import (
"reflect"
"testing"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/host"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
@ -71,7 +70,7 @@ func newShellCfg(shell, prefix, suffix, delim string) *ShellConfig {
func TestShellCfgSet(t *testing.T) {
var tests = []struct {
description string
api libmachine.API
api *tests.MockAPI
shell string
noProxyVar string
noProxyValue string
@ -236,7 +235,7 @@ func TestShellCfgSet(t *testing.T) {
defaultShellDetector = &FakeShellDetector{test.shell}
defaultNoProxyGetter = &FakeNoProxyGetter{test.noProxyVar, test.noProxyValue}
noProxy = test.noProxyFlag
test.api.T = t
shellCfg, err := shellCfgSet(test.api)
if !reflect.DeepEqual(shellCfg, test.expectedShellCfg) {
t.Errorf("Shell cfgs differ: expected %+v, \n\n got %+v", test.expectedShellCfg, shellCfg)

View File

@ -75,12 +75,10 @@ func init() {
// CacheISO downloads and caches ISO.
func CacheISO(config cfg.MachineConfig) error {
if config.VMDriver != constants.DriverNone {
if err := config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO); err != nil {
return err
}
}
if localDriver(config.VMDriver) {
return nil
}
return config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO)
}
// StartHost starts a host VM.
@ -141,23 +139,35 @@ func StartHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error)
return h, nil
}
// localDriver returns whether or not the driver should be considered local
func localDriver(name string) bool {
if name == constants.DriverNone || name == constants.DriverMock {
return true
}
return false
}
// configureHost handles any post-powerup configuration required
func configureHost(h *host.Host, e *engine.Options) error {
glog.Infof("configureHost: %T %+v", h, h)
// Slightly counter-intuitive, but this is what DetectProvisioner & ConfigureAuth block on.
console.OutT(console.Waiting, "Waiting for SSH access ...", console.Arg{})
if len(e.Env) > 0 {
h.HostOptions.EngineOptions.Env = e.Env
glog.Infof("Detecting provisioner ...")
provisioner, err := provision.DetectProvisioner(h.Driver)
if err != nil {
return errors.Wrap(err, "detecting provisioner")
}
glog.Infof("Provisioning: %+v", *h.HostOptions)
if err := provisioner.Provision(*h.HostOptions.SwarmOptions, *h.HostOptions.AuthOptions, *h.HostOptions.EngineOptions); err != nil {
return errors.Wrap(err, "provision")
}
}
if h.Driver.DriverName() != constants.DriverNone {
if !localDriver(h.Driver.DriverName()) {
glog.Infof("Configuring auth for driver %s ...", h.Driver.DriverName())
if err := h.ConfigureAuth(); err != nil {
return &util.RetriableError{Err: errors.Wrap(err, "Error configuring auth on host")}
}
@ -362,9 +372,8 @@ func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error
See https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#vmware-unified-driver for more information.
To disable this message, run [minikube config set ShowDriverDeprecationNotification false]`)
}
if config.VMDriver != constants.DriverNone {
if !localDriver(config.VMDriver) {
console.OutT(console.StartingVM, "Creating {{.driver_name}} VM (CPUs={{.number_of_cpus}}, Memory={{.memory_size}MB, Disk={{.disk_size}}MB) ...", console.Arg{"driver_name": config.VMDriver, "number_of_cpus": config.CPUs, "memory_size": config.Memory, "disk_size": config.DiskSize})
} else {
info, err := getHostInfo()
if err == nil {
@ -375,9 +384,9 @@ func createHost(api libmachine.API, config cfg.MachineConfig) (*host.Host, error
def, err := registry.Driver(config.VMDriver)
if err != nil {
if err == registry.ErrDriverNotFound {
exit.UsageT("unsupported driver: {{.driver_name}}", console.Arg{"driver_name": config.VMDriver})
return nil, fmt.Errorf("unsupported driver: %s", config.VMDriver)
}
exit.WithError("error getting driver", err)
return nil, errors.Wrap(err, "error getting driver")
}
driver := def.ConfigCreator(config)

View File

@ -37,14 +37,40 @@ type MockDownloader struct{}
func (d MockDownloader) GetISOFileURI(isoURL string) string { return "" }
func (d MockDownloader) CacheMinikubeISOFromURL(isoURL string) error { return nil }
func createMockDriverHost(c config.MachineConfig) interface{} {
return nil
}
func RegisterMockDriver(t *testing.T) {
t.Helper()
_, err := registry.Driver(constants.DriverMock)
// Already registered
if err == nil {
return
}
err = registry.Register(registry.DriverDef{
Name: constants.DriverMock,
Builtin: true,
ConfigCreator: createMockDriverHost,
DriverCreator: func() drivers.Driver {
return &tests.MockDriver{T: t}
},
})
if err != nil {
t.Fatalf("register failed: %v", err)
}
}
var defaultMachineConfig = config.MachineConfig{
VMDriver: constants.DefaultVMDriver,
VMDriver: constants.DriverMock,
MinikubeISO: constants.DefaultISOURL,
Downloader: MockDownloader{},
DockerEnv: []string{"MOCK_MAKE_IT_PROVISION=true"},
}
func TestCreateHost(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
exists, _ := api.Exists(config.GetMachineName())
if exists {
@ -54,9 +80,12 @@ func TestCreateHost(t *testing.T) {
if err != nil {
t.Fatalf("Error creating host: %v", err)
}
exists, _ = api.Exists(config.GetMachineName())
exists, err = api.Exists(config.GetMachineName())
if err != nil {
t.Fatalf("exists failed for %q: %v", config.GetMachineName(), err)
}
if !exists {
t.Fatal("Machine does not exist, but should.")
t.Fatalf("%q does not exist, but should.", config.GetMachineName())
}
h, err := api.Load(config.GetMachineName())
@ -82,7 +111,8 @@ func TestCreateHost(t *testing.T) {
}
func TestStartHostExists(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
// Create an initial host.
_, err := createHost(api, defaultMachineConfig)
if err != nil {
@ -101,10 +131,10 @@ func TestStartHostExists(t *testing.T) {
// This should pass without calling Create because the host exists already.
h, err := StartHost(api, defaultMachineConfig)
if err != nil {
t.Fatal("Error starting host.")
t.Fatalf("Error starting host: %v", err)
}
if h.Name != config.GetMachineName() {
t.Fatalf("Machine created with incorrect name: %s", h.Name)
t.Fatalf("GetMachineName()=%q, want %q", config.GetMachineName(), h.Name)
}
if s, _ := h.Driver.GetState(); s != state.Running {
t.Fatalf("Machine not started.")
@ -115,13 +145,14 @@ func TestStartHostExists(t *testing.T) {
}
func TestStartStoppedHost(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
// Create an initial host.
h, err := createHost(api, defaultMachineConfig)
if err != nil {
t.Fatalf("Error creating host: %v", err)
}
d := tests.MockDriver{}
d := tests.MockDriver{T: t}
h.Driver = &d
d.CurrentState = state.Stopped
@ -149,7 +180,8 @@ func TestStartStoppedHost(t *testing.T) {
}
func TestStartHost(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
md := &tests.MockDetector{Provisioner: &tests.MockProvisioner{}}
provision.SetDetector(md)
@ -159,7 +191,7 @@ func TestStartHost(t *testing.T) {
t.Fatal("Error starting host.")
}
if h.Name != config.GetMachineName() {
t.Fatalf("Machine created with incorrect name: %s", h.Name)
t.Fatalf("GetMachineName()=%q, want %q", config.GetMachineName(), h.Name)
}
if exists, _ := api.Exists(h.Name); !exists {
t.Fatal("Machine not saved.")
@ -176,7 +208,8 @@ func TestStartHost(t *testing.T) {
}
func TestStartHostConfig(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
md := &tests.MockDetector{Provisioner: &tests.MockProvisioner{}}
provision.SetDetector(md)
@ -208,14 +241,16 @@ func TestStartHostConfig(t *testing.T) {
}
func TestStopHostError(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
if err := StopHost(api); err == nil {
t.Fatal("An error should be thrown when stopping non-existing machine.")
}
}
func TestStopHost(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
h, err := createHost(api, defaultMachineConfig)
if err != nil {
t.Errorf("createHost failed: %v", err)
@ -230,7 +265,8 @@ func TestStopHost(t *testing.T) {
}
func TestDeleteHost(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
if _, err := createHost(api, defaultMachineConfig); err != nil {
t.Errorf("createHost failed: %v", err)
}
@ -241,14 +277,14 @@ func TestDeleteHost(t *testing.T) {
}
func TestDeleteHostErrorDeletingVM(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
h, err := createHost(api, defaultMachineConfig)
if err != nil {
t.Errorf("createHost failed: %v", err)
}
d := &tests.MockDriver{RemoveError: true}
d := &tests.MockDriver{RemoveError: true, T: t}
h.Driver = d
if err := DeleteHost(api); err == nil {
@ -257,7 +293,8 @@ func TestDeleteHostErrorDeletingVM(t *testing.T) {
}
func TestDeleteHostErrorDeletingFiles(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
api.RemoveError = true
if _, err := createHost(api, defaultMachineConfig); err != nil {
t.Errorf("createHost failed: %v", err)
@ -269,7 +306,8 @@ func TestDeleteHostErrorDeletingFiles(t *testing.T) {
}
func TestGetHostStatus(t *testing.T) {
api := tests.NewMockAPI()
RegisterMockDriver(t)
api := tests.NewMockAPI(t)
checkState := func(expected string) {
s, err := GetHostStatus(api)
@ -296,10 +334,11 @@ func TestGetHostStatus(t *testing.T) {
}
func TestGetHostDockerEnv(t *testing.T) {
RegisterMockDriver(t)
tempDir := tests.MakeTempDir()
defer os.RemoveAll(tempDir)
api := tests.NewMockAPI()
api := tests.NewMockAPI(t)
h, err := createHost(api, defaultMachineConfig)
if err != nil {
t.Fatalf("Error creating host: %v", err)
@ -308,6 +347,7 @@ func TestGetHostDockerEnv(t *testing.T) {
BaseDriver: drivers.BaseDriver{
IPAddress: "127.0.0.1",
},
T: t,
}
h.Driver = d
@ -332,7 +372,7 @@ func TestGetHostDockerEnvIPv6(t *testing.T) {
tempDir := tests.MakeTempDir()
defer os.RemoveAll(tempDir)
api := tests.NewMockAPI()
api := tests.NewMockAPI(t)
h, err := createHost(api, defaultMachineConfig)
if err != nil {
t.Fatalf("Error creating host: %v", err)
@ -341,6 +381,7 @@ func TestGetHostDockerEnvIPv6(t *testing.T) {
BaseDriver: drivers.BaseDriver{
IPAddress: "fe80::215:5dff:fe00:a903",
},
T: t,
}
h.Driver = d
@ -357,7 +398,7 @@ func TestGetHostDockerEnvIPv6(t *testing.T) {
}
func TestCreateSSHShell(t *testing.T) {
api := tests.NewMockAPI()
api := tests.NewMockAPI(t)
s, _ := tests.NewSSHServer(t)
port, err := s.Start()
@ -372,6 +413,7 @@ func TestCreateSSHShell(t *testing.T) {
IPAddress: "127.0.0.1",
SSHKeyPath: "",
},
T: t,
}
api.Hosts[config.GetMachineName()] = &host.Host{Driver: d}

View File

@ -96,6 +96,7 @@ func decode(r io.Reader) (MinikubeConfig, error) {
// GetMachineName gets the machine name for the VM
func GetMachineName() string {
// REFACTOR NECESSARY: This function should not rely on globals.
if viper.GetString(MachineProfile) == "" {
return constants.DefaultMachineName
}

View File

@ -59,6 +59,9 @@ func ArchTag(hasTag bool) string {
return "-" + runtime.GOARCH + ":"
}
// DriverMock is a mock driver.
const DriverMock = "mock-driver"
// DriverNone is the none driver.
const DriverNone = "none"

View File

@ -147,6 +147,9 @@ func (api *LocalClient) Close() error {
// CommandRunner returns best available command runner for this host
func CommandRunner(h *host.Host) (command.Runner, error) {
if h.DriverName == constants.DriverMock {
return &command.FakeCommandRunner{}, nil
}
if h.DriverName == constants.DriverNone {
return &command.ExecRunner{}, nil
}

View File

@ -41,6 +41,7 @@ func TestNewSSHClient(t *testing.T) {
IPAddress: "127.0.0.1",
SSHKeyPath: "",
},
T: t,
}
c, err := NewSSHClient(d)
if err != nil {

View File

@ -19,10 +19,15 @@ package tests
import (
"encoding/json"
"fmt"
"math/rand"
"testing"
"github.com/docker/machine/libmachine/auth"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/swarm"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/viper"
)
// MockAPI is a struct used to mock out libmachine.API
@ -31,18 +36,31 @@ type MockAPI struct {
CreateError bool
RemoveError bool
SaveCalled bool
t *testing.T
}
// NewMockAPI returns a new MockAPI
func NewMockAPI() *MockAPI {
func NewMockAPI(t *testing.T) *MockAPI {
t.Helper()
m := MockAPI{
FakeStore: FakeStore{
Hosts: make(map[string]*host.Host),
T: t,
},
t: t,
}
return &m
}
// Logf logs mock interactions
func (api *MockAPI) Logf(format string, args ...interface{}) {
if api.t == nil {
glog.Infof(format, args...)
return
}
api.t.Logf(format, args...)
}
// Close closes the API.
func (api *MockAPI) Close() error {
return nil
@ -54,21 +72,44 @@ func (api *MockAPI) NewHost(driverName string, rawDriver []byte) (*host.Host, er
if err := json.Unmarshal(rawDriver, &driver); err != nil {
return nil, errors.Wrap(err, "error unmarshalling json")
}
h := &host.Host{
DriverName: driverName,
RawDriver: rawDriver,
Driver: &MockDriver{},
Name: driver.GetMachineName(),
HostOptions: &host.Options{AuthOptions: &auth.Options{}},
Name: fmt.Sprintf("mock-machine-%.8f", rand.Float64()),
HostOptions: &host.Options{
AuthOptions: &auth.Options{},
SwarmOptions: &swarm.Options{},
},
}
// HACK: Make future calls to config.GetMachineName() work properly.
api.Logf("MockAPI.NewHost: Setting profile=%q", h.Name)
viper.Set("profile", h.Name)
api.Logf("MockAPI.NewHost: %+v", h)
return h, nil
}
// Load a created mock
func (api *MockAPI) Load(name string) (*host.Host, error) {
h, err := api.FakeStore.Load(name)
api.Logf("MockAPI.Load: %+v - %v", h, err)
return h, err
}
// Create creates the actual host.
func (api *MockAPI) Create(h *host.Host) error {
api.Logf("MockAPI.Create: %+v", h)
if api.CreateError {
return errors.New("error creating host")
}
// Propagate test info messages
drv, ok := h.Driver.(*MockDriver)
if ok {
drv.T = api.t
}
return h.Driver.Create()
}
@ -79,6 +120,7 @@ func (api *MockAPI) List() ([]string, error) {
// Remove a host.
func (api *MockAPI) Remove(name string) error {
api.Logf("MockAPI.Delete: %s", name)
if api.RemoveError {
return fmt.Errorf("error removing %s", name)
}
@ -90,6 +132,7 @@ func (api *MockAPI) Remove(name string) error {
// Save saves a host to disk.
func (api *MockAPI) Save(host *host.Host) error {
api.SaveCalled = true
api.Logf("MockAPI.Save: %+v", host)
return api.FakeStore.Save(host)
}

View File

@ -17,9 +17,14 @@ limitations under the License.
package tests
import (
"testing"
"k8s.io/minikube/pkg/minikube/constants"
"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/mcnflag"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
)
@ -31,16 +36,28 @@ type MockDriver struct {
HostError bool
Port int
IP string
T *testing.T
}
// Logf logs mock interactions
func (driver *MockDriver) Logf(format string, args ...interface{}) {
if driver.T == nil {
glog.Infof(format, args...)
return
}
driver.T.Logf(format, args...)
}
// Create creates a MockDriver instance
func (driver *MockDriver) Create() error {
driver.Logf("MockDriver.Create")
driver.CurrentState = state.Running
return nil
}
// GetIP returns the IP address
func (driver *MockDriver) GetIP() (string, error) {
driver.Logf("MockDriver.GetIP")
if driver.IP != "" {
return driver.IP, nil
}
@ -75,6 +92,7 @@ func (driver *MockDriver) GetSSHKeyPath() string {
// GetState returns the state of the driver
func (driver *MockDriver) GetState() (state.State, error) {
driver.Logf("MockDriver.GetState: %v", driver.CurrentState)
return driver.CurrentState, nil
}
@ -85,12 +103,14 @@ func (driver *MockDriver) GetURL() (string, error) {
// Kill kills the machine
func (driver *MockDriver) Kill() error {
driver.Logf("MockDriver.Kill")
driver.CurrentState = state.Stopped
return nil
}
// Remove removes the machine
func (driver *MockDriver) Remove() error {
driver.Logf("MockDriver.Remove")
if driver.RemoveError {
return errors.New("error deleting machine")
}
@ -99,6 +119,7 @@ func (driver *MockDriver) Remove() error {
// Restart restarts the machine
func (driver *MockDriver) Restart() error {
driver.Logf("MockDriver.Restart")
driver.CurrentState = state.Running
return nil
}
@ -110,12 +131,20 @@ func (driver *MockDriver) SetConfigFromFlags(opts drivers.DriverOptions) error {
// Start starts the machine
func (driver *MockDriver) Start() error {
driver.Logf("MockDriver.Start")
driver.CurrentState = state.Running
return nil
}
// Stop stops the machine
func (driver *MockDriver) Stop() error {
driver.Logf("MockDriver.Stop")
driver.CurrentState = state.Stopped
return nil
}
// DriverName returns the name of the driver
func (driver *MockDriver) DriverName() string {
driver.Logf("MockDriver.Name")
return constants.DriverMock
}

View File

@ -17,6 +17,8 @@ limitations under the License.
package tests
import (
"testing"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/mcnerror"
)
@ -24,6 +26,7 @@ import (
// FakeStore implements persist.Store from libmachine
type FakeStore struct {
Hosts map[string]*host.Host
T *testing.T
}
// Exists determines if the host already exists.
@ -67,7 +70,7 @@ func (s *FakeStore) Remove(name string) error {
}
// Save persists a machine in the store
func (s *FakeStore) Save(host *host.Host) error {
s.Hosts[host.Name] = host
func (s *FakeStore) Save(h *host.Host) error {
s.Hosts[h.Name] = h
return nil
}

View File

@ -34,7 +34,7 @@ import (
func TestAPIError(t *testing.T) {
machineName := "nonexistentmachine"
machineAPI := tests.NewMockAPI()
machineAPI := tests.NewMockAPI(t)
configLoader := &stubConfigLoader{}
inspector := &clusterInspector{
machineAPI, configLoader, machineName,

View File

@ -21,8 +21,6 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/user"
"path/filepath"
@ -32,7 +30,6 @@ import (
units "github.com/docker/go-units"
"github.com/golang/glog"
retryablehttp "github.com/hashicorp/go-retryablehttp"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/console"
"k8s.io/minikube/pkg/minikube/exit"
@ -136,24 +133,6 @@ func RetryAfter(attempts int, callback func() error, d time.Duration) (err error
return m.ToError()
}
// ParseSHAFromURL downloads and reads a SHA checksum from an URL
func ParseSHAFromURL(url string) (string, error) {
r, err := retryablehttp.Get(url)
if err != nil {
return "", errors.Wrap(err, "Error downloading checksum.")
} else if r.StatusCode != http.StatusOK {
return "", errors.Errorf("Error downloading checksum. Got HTTP Error: %s", r.Status)
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return "", errors.Wrap(err, "Error reading checksum.")
}
return strings.Trim(string(body), "\n"), nil
}
// GetBinaryDownloadURL returns a suitable URL for the platform
func GetBinaryDownloadURL(version, platform string) string {
switch platform {

View File

@ -19,9 +19,6 @@ package util
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"sync"
"testing"
@ -88,45 +85,6 @@ func TestRetryNotRetriableError(t *testing.T) {
}
}
type getTestArgs struct {
input string
expected string
expectedError bool
}
var testSHAString = "test"
func TestParseSHAFromURL(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if _, err := io.WriteString(w, testSHAString); err != nil {
t.Fatalf("WriteString: %v", err)
}
}))
serverBadResponse := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
if _, err := w.Write([]byte("500 HTTP status code returned!")); err != nil {
t.Fatalf("Write: %v", err)
}
}))
argsList := [...]getTestArgs{
{server.URL, testSHAString, false},
{serverBadResponse.URL, "", true},
{"abc", "", true},
}
for _, args := range argsList {
url, err := ParseSHAFromURL(args.input)
wasError := err != nil
if wasError != args.expectedError {
t.Errorf("ParseSHAFromURL Expected error was: %t, Actual Error was: %s",
args.expectedError, err)
}
if url != args.expected {
t.Errorf("ParseSHAFromURL: Expected %s, Actual: %s", args.expected, url)
}
}
}
func TestMultiError(t *testing.T) {
m := MultiError{}