2016-12-05 22:49:52 +00:00
// +build integration
/ *
Copyright 2016 The Kubernetes Authors All rights reserved .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package integration
import (
2019-09-11 16:59:38 +00:00
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"os/exec"
2020-03-04 22:48:40 +00:00
"path"
2019-09-11 16:59:38 +00:00
"path/filepath"
2019-10-11 14:43:00 +00:00
"regexp"
2019-11-06 22:14:56 +00:00
"runtime"
2019-09-11 16:59:38 +00:00
"strings"
2016-12-05 22:49:52 +00:00
"testing"
2019-09-11 16:59:38 +00:00
"time"
2019-11-07 01:20:52 +00:00
"github.com/google/go-cmp/cmp"
2020-04-07 04:03:12 +00:00
"k8s.io/minikube/pkg/minikube/config"
2019-11-07 01:20:52 +00:00
"k8s.io/minikube/pkg/minikube/localpath"
2020-04-07 04:26:45 +00:00
"k8s.io/minikube/pkg/util/retry"
2019-11-07 01:20:52 +00:00
2019-09-11 16:59:38 +00:00
"github.com/elazarl/goproxy"
"github.com/hashicorp/go-retryablehttp"
2019-11-07 01:20:52 +00:00
"github.com/otiai10/copy"
2019-09-11 16:59:38 +00:00
"github.com/phayes/freeport"
"github.com/pkg/errors"
"golang.org/x/build/kubernetes/api"
2016-12-05 22:49:52 +00:00
)
2019-09-11 16:59:38 +00:00
// validateFunc are for subtests that share a single setup
type validateFunc func ( context . Context , * testing . T , string )
2020-04-07 20:14:30 +00:00
// used in validateStartWithProxy and validateSoftStart
var apiPortTest = 8441
2019-09-11 16:59:38 +00:00
// TestFunctional are functionality tests which can safely share a profile in parallel
2017-05-30 20:23:24 +00:00
func TestFunctional ( t * testing . T ) {
2019-09-11 16:59:38 +00:00
profile := UniqueProfileName ( "functional" )
2020-02-21 00:19:59 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , Minutes ( 40 ) )
2020-02-12 22:26:38 +00:00
defer func ( ) {
2020-03-04 22:48:40 +00:00
if ! * cleanup {
return
}
2020-02-12 22:26:38 +00:00
p := localSyncTestPath ( )
if err := os . Remove ( p ) ; err != nil {
2020-03-26 04:43:32 +00:00
t . Logf ( "unable to remove %q: %v" , p , err )
2020-02-12 22:26:38 +00:00
}
2020-03-04 22:48:40 +00:00
p = localTestCertPath ( )
if err := os . Remove ( p ) ; err != nil {
2020-03-26 04:43:32 +00:00
t . Logf ( "unable to remove %q: %v" , p , err )
2020-03-04 22:48:40 +00:00
}
2020-04-08 22:04:12 +00:00
p = localEmptyCertPath ( )
if err := os . Remove ( p ) ; err != nil {
t . Logf ( "unable to remove %q: %v" , p , err )
}
2020-02-12 22:26:38 +00:00
CleanupWithLogs ( t , profile , cancel )
} ( )
2019-09-11 16:59:38 +00:00
// Serial tests
t . Run ( "serial" , func ( t * testing . T ) {
tests := [ ] struct {
name string
validator validateFunc
} {
2020-02-12 17:54:17 +00:00
{ "CopySyncFile" , setupFileSync } , // Set file for the file sync test case
{ "StartWithProxy" , validateStartWithProxy } , // Set everything else up for success
2020-04-07 04:06:27 +00:00
{ "SoftStart" , validateSoftStart } , // do a soft start. ensure config didnt change.
2020-02-12 17:54:17 +00:00
{ "KubeContext" , validateKubeContext } , // Racy: must come immediately after "minikube start"
{ "KubectlGetPods" , validateKubectlGetPods } , // Make sure apiserver is up
{ "CacheCmd" , validateCacheCmd } , // Caches images needed for subsequent tests because of proxy
{ "MinikubeKubectlCmd" , validateMinikubeKubectl } , // Make sure `minikube kubectl` works
2019-09-11 16:59:38 +00:00
}
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
2020-04-07 04:26:45 +00:00
tc . validator ( ctx , t , profile )
2019-09-11 16:59:38 +00:00
} )
2019-07-30 04:52:05 +00:00
}
2019-09-11 16:59:38 +00:00
} )
2019-07-30 04:52:05 +00:00
2019-09-11 16:59:38 +00:00
// Now that we are out of the woods, lets go.
MaybeParallel ( t )
// Parallelized tests
t . Run ( "parallel" , func ( t * testing . T ) {
tests := [ ] struct {
name string
validator validateFunc
} {
{ "ComponentHealth" , validateComponentHealth } ,
{ "ConfigCmd" , validateConfigCmd } ,
{ "DashboardCmd" , validateDashboardCmd } ,
{ "DNS" , validateDNS } ,
2020-01-09 19:10:23 +00:00
{ "DryRun" , validateDryRun } ,
2019-10-13 15:24:40 +00:00
{ "StatusCmd" , validateStatusCmd } ,
2019-09-11 16:59:38 +00:00
{ "LogsCmd" , validateLogsCmd } ,
{ "MountCmd" , validateMountCmd } ,
{ "ProfileCmd" , validateProfileCmd } ,
2019-10-30 17:44:54 +00:00
{ "ServiceCmd" , validateServiceCmd } ,
2019-10-11 14:43:00 +00:00
{ "AddonsCmd" , validateAddonsCmd } ,
2019-09-11 16:59:38 +00:00
{ "PersistentVolumeClaim" , validatePersistentVolumeClaim } ,
{ "TunnelCmd" , validateTunnelCmd } ,
{ "SSHCmd" , validateSSHCmd } ,
2019-10-29 05:31:57 +00:00
{ "MySQL" , validateMySQL } ,
2019-11-07 01:20:52 +00:00
{ "FileSync" , validateFileSync } ,
2020-03-04 22:48:40 +00:00
{ "CertSync" , validateCertSync } ,
2019-12-16 15:58:45 +00:00
{ "UpdateContextCmd" , validateUpdateContextCmd } ,
2020-02-13 09:17:11 +00:00
{ "DockerEnv" , validateDockerEnv } ,
2020-02-20 21:57:09 +00:00
{ "NodeLabels" , validateNodeLabels } ,
2019-09-11 16:59:38 +00:00
}
for _ , tc := range tests {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
MaybeParallel ( t )
tc . validator ( ctx , t , profile )
} )
}
2019-07-30 04:52:05 +00:00
} )
2019-09-11 16:59:38 +00:00
}
2020-02-20 21:57:09 +00:00
// validateNodeLabels checks if minikube cluster is created with correct kubernetes's node label
func validateNodeLabels ( ctx context . Context , t * testing . T , profile string ) {
2020-02-22 00:01:47 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "nodes" , "--output=go-template" , "--template='{{range $k, $v := (index .items 0).metadata.labels}}{{$k}} {{end}}'" ) )
2020-02-20 21:57:09 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to 'kubectl get nodes' with args %q: %v" , rr . Command ( ) , err )
2020-02-20 21:57:09 +00:00
}
expectedLabels := [ ] string { "minikube.k8s.io/commit" , "minikube.k8s.io/version" , "minikube.k8s.io/updated_at" , "minikube.k8s.io/name" }
for _ , el := range expectedLabels {
2020-02-22 00:01:47 +00:00
if ! strings . Contains ( rr . Output ( ) , el ) {
2020-04-02 04:34:37 +00:00
t . Errorf ( "expected to have label %q in node labels but got : %s" , el , rr . Output ( ) )
2020-02-20 21:57:09 +00:00
}
}
}
2020-02-13 09:17:11 +00:00
// check functionality of minikube after evaling docker-env
func validateDockerEnv ( ctx context . Context , t * testing . T , profile string ) {
2020-02-21 00:19:59 +00:00
mctx , cancel := context . WithTimeout ( ctx , Seconds ( 13 ) )
2020-02-13 09:17:11 +00:00
defer cancel ( )
// we should be able to get minikube status with a bash which evaled docker-env
c := exec . CommandContext ( mctx , "/bin/bash" , "-c" , "eval $(" + Target ( ) + " -p " + profile + " docker-env) && " + Target ( ) + " status -p " + profile )
rr , err := Run ( t , c )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed to do minikube status after eval-ing docker-env %s" , err )
2020-02-13 09:17:11 +00:00
}
if ! strings . Contains ( rr . Output ( ) , "Running" ) {
2020-04-02 04:40:09 +00:00
t . Fatalf ( "expected status output to include 'Running' after eval docker-env but got: *%s*" , rr . Output ( ) )
2020-02-13 09:17:11 +00:00
}
2020-02-21 00:19:59 +00:00
mctx , cancel = context . WithTimeout ( ctx , Seconds ( 13 ) )
2020-02-13 09:17:11 +00:00
defer cancel ( )
// do a eval $(minikube -p profile docker-env) and check if we are point to docker inside minikube
c = exec . CommandContext ( mctx , "/bin/bash" , "-c" , "eval $(" + Target ( ) + " -p " + profile + " docker-env) && docker images" )
rr , err = Run ( t , c )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to run minikube docker-env. args %q : %v " , rr . Command ( ) , err )
2020-02-13 09:17:11 +00:00
}
expectedImgInside := "gcr.io/k8s-minikube/storage-provisioner"
if ! strings . Contains ( rr . Output ( ) , expectedImgInside ) {
2020-04-02 04:40:09 +00:00
t . Fatalf ( "expected 'docker images' to have %q inside minikube. but the output is: *%s*" , expectedImgInside , rr . Output ( ) )
2020-02-13 09:17:11 +00:00
}
}
2020-04-07 04:26:45 +00:00
func validateStartWithProxy ( ctx context . Context , t * testing . T , profile string ) {
2019-09-11 16:59:38 +00:00
srv , err := startHTTPProxy ( t )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed to set up the test proxy: %s" , err )
2019-09-11 16:59:38 +00:00
}
2019-11-06 23:17:09 +00:00
// Use more memory so that we may reliably fit MySQL and nginx
2020-04-07 04:03:12 +00:00
// changing api server so later in soft start we verify it didn't change
2020-04-07 20:14:30 +00:00
startArgs := append ( [ ] string { "start" , "-p" , profile , fmt . Sprintf ( "--apiserver-port=%d" , apiPortTest ) , "--wait=true" } , StartArgs ( ) ... )
2019-09-11 20:08:44 +00:00
c := exec . CommandContext ( ctx , Target ( ) , startArgs ... )
2019-09-11 16:59:38 +00:00
env := os . Environ ( )
env = append ( env , fmt . Sprintf ( "HTTP_PROXY=%s" , srv . Addr ) )
env = append ( env , "NO_PROXY=" )
c . Env = env
rr , err := Run ( t , c )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed minikube start. args %q: %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
want := "Found network options:"
if ! strings . Contains ( rr . Stdout . String ( ) , want ) {
t . Errorf ( "start stdout=%s, want: *%s*" , rr . Stdout . String ( ) , want )
}
want = "You appear to be using a proxy"
if ! strings . Contains ( rr . Stderr . String ( ) , want ) {
t . Errorf ( "start stderr=%s, want: *%s*" , rr . Stderr . String ( ) , want )
}
}
2020-04-07 04:03:12 +00:00
// validateSoftStart validates that after minikube already started, a "minikube start" should not change the configs.
2020-04-07 04:26:45 +00:00
func validateSoftStart ( ctx context . Context , t * testing . T , profile string ) {
2020-04-07 04:06:27 +00:00
start := time . Now ( )
2020-04-07 04:08:09 +00:00
// the test before this had been start with --apiserver-port=8441
2020-04-07 04:26:45 +00:00
beforeCfg , err := config . LoadProfile ( profile )
if err != nil {
t . Errorf ( "error reading cluster config before soft start: %v" , err )
}
2020-04-07 20:14:30 +00:00
if beforeCfg . Config . KubernetesConfig . NodePort != apiPortTest {
t . Errorf ( "expected cluster config node port before soft start to be %d but got %d" , apiPortTest , beforeCfg . Config . KubernetesConfig . NodePort )
2020-04-07 04:03:12 +00:00
}
2020-04-07 04:26:45 +00:00
softStartArgs := [ ] string { "start" , "-p" , profile }
2020-04-07 04:03:12 +00:00
c := exec . CommandContext ( ctx , Target ( ) , softStartArgs ... )
2020-04-07 04:26:45 +00:00
rr , err := Run ( t , c )
2020-04-07 04:03:12 +00:00
if err != nil {
t . Errorf ( "failed to soft start minikube. args %q: %v" , rr . Command ( ) , err )
}
2020-04-07 04:06:27 +00:00
t . Logf ( "soft start took %s for %q cluster." , time . Since ( start ) , profile )
2020-04-07 04:03:12 +00:00
2020-04-07 04:26:45 +00:00
afterCfg , err := config . LoadProfile ( profile )
if err != nil {
t . Errorf ( "error reading cluster config after soft start: %v" , err )
}
2020-04-07 20:14:30 +00:00
if afterCfg . Config . KubernetesConfig . NodePort != apiPortTest {
t . Errorf ( "expected node port in the config not change after soft start. exepceted node port to be %d but got %d." , apiPortTest , afterCfg . Config . KubernetesConfig . NodePort )
2020-04-07 04:03:12 +00:00
}
2020-04-07 04:06:27 +00:00
2020-04-07 04:03:12 +00:00
}
2019-09-11 16:59:38 +00:00
// validateKubeContext asserts that kubectl is properly configured (race-condition prone!)
func validateKubeContext ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "config" , "current-context" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to get current-context. args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
if ! strings . Contains ( rr . Stdout . String ( ) , profile ) {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected current-context = %q, but got *%q*" , profile , rr . Stdout . String ( ) )
2019-09-11 16:59:38 +00:00
}
}
2019-10-28 23:50:01 +00:00
// validateKubectlGetPods asserts that `kubectl get pod -A` returns non-zero content
func validateKubectlGetPods ( ctx context . Context , t * testing . T , profile string ) {
2019-11-13 05:38:31 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "po" , "-A" ) )
2019-10-28 23:50:01 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to get kubectl pods: args %q : %v" , rr . Command ( ) , err )
2019-10-28 23:50:01 +00:00
}
2019-11-13 05:38:31 +00:00
if rr . Stderr . String ( ) != "" {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected stderr to be empty but got *%q*: args %q" , rr . Stderr , rr . Command ( ) )
2019-11-13 05:38:31 +00:00
}
2019-11-12 22:19:52 +00:00
if ! strings . Contains ( rr . Stdout . String ( ) , "kube-system" ) {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected stdout to include *kube-system* but got *%q*. args: %q" , rr . Stdout , rr . Command ( ) )
2019-10-28 23:50:01 +00:00
}
}
2020-02-12 17:54:17 +00:00
// validateMinikubeKubectl validates that the `minikube kubectl` command returns content
func validateMinikubeKubectl ( ctx context . Context , t * testing . T , profile string ) {
2020-03-25 21:57:27 +00:00
// Must set the profile so that it knows what version of Kubernetes to use
kubectlArgs := [ ] string { "-p" , profile , "kubectl" , "--" , "--context" , profile , "get" , "pods" }
2020-02-13 21:34:05 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , kubectlArgs ... ) )
2020-02-12 17:54:17 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to get pods. args %q: %v" , rr . Command ( ) , err )
2020-02-12 17:54:17 +00:00
}
}
2019-09-11 16:59:38 +00:00
// validateComponentHealth asserts that all Kubernetes components are healthy
func validateComponentHealth ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "get" , "cs" , "-o=json" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to get components. args %q: %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
cs := api . ComponentStatusList { }
d := json . NewDecoder ( bytes . NewReader ( rr . Stdout . Bytes ( ) ) )
if err := d . Decode ( & cs ) ; err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to decode kubectl json output: args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
for _ , i := range cs . Items {
status := api . ConditionFalse
for _ , c := range i . Conditions {
if c . Type != api . ComponentHealthy {
continue
}
status = c . Status
}
if status != api . ConditionTrue {
t . Errorf ( "unexpected status: %v - item: %+v" , status , i )
}
}
}
2019-10-13 15:24:40 +00:00
func validateStatusCmd ( ctx context . Context , t * testing . T , profile string ) {
2019-10-21 18:00:01 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "status" ) )
2019-10-13 15:24:40 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run minikube status. args %q : %v" , rr . Command ( ) , err )
2019-10-13 15:24:40 +00:00
}
// Custom format
2019-10-21 18:00:01 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "status" , "-f" , "host:{{.Host}},kublet:{{.Kubelet}},apiserver:{{.APIServer}},kubeconfig:{{.Kubeconfig}}" ) )
2019-10-13 15:24:40 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run minikube status with custom format: args %q: %v" , rr . Command ( ) , err )
2019-10-13 15:24:40 +00:00
}
2020-03-26 04:43:32 +00:00
re := ` host:([A-z]+),kublet:([A-z]+),apiserver:([A-z]+),kubeconfig:([A-z]+) `
match , _ := regexp . MatchString ( re , rr . Stdout . String ( ) )
2019-10-13 15:24:40 +00:00
if ! match {
2020-04-02 04:40:09 +00:00
t . Errorf ( "failed to match regex %q for minikube status with custom format. args %q. output: %s" , re , rr . Command ( ) , rr . Output ( ) )
2019-10-13 15:24:40 +00:00
}
// Json output
2019-10-21 18:00:01 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "status" , "-o" , "json" ) )
2019-10-13 15:24:40 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run minikube status with json output. args %q : %v" , rr . Command ( ) , err )
2019-10-13 15:24:40 +00:00
}
var jsonObject map [ string ] interface { }
err = json . Unmarshal ( rr . Stdout . Bytes ( ) , & jsonObject )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to decode json from minikube status. args %q. %v" , rr . Command ( ) , err )
2019-10-13 15:24:40 +00:00
}
if _ , ok := jsonObject [ "Host" ] ; ! ok {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%q failed: %v. Missing key %s in json object" , rr . Command ( ) , err , "Host" )
2019-10-13 15:24:40 +00:00
}
if _ , ok := jsonObject [ "Kubelet" ] ; ! ok {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%q failed: %v. Missing key %s in json object" , rr . Command ( ) , err , "Kubelet" )
2019-10-13 15:24:40 +00:00
}
if _ , ok := jsonObject [ "APIServer" ] ; ! ok {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%q failed: %v. Missing key %s in json object" , rr . Command ( ) , err , "APIServer" )
2019-10-13 15:24:40 +00:00
}
if _ , ok := jsonObject [ "Kubeconfig" ] ; ! ok {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%q failed: %v. Missing key %s in json object" , rr . Command ( ) , err , "Kubeconfig" )
2019-10-13 15:24:40 +00:00
}
}
2019-09-11 16:59:38 +00:00
// validateDashboardCmd asserts that the dashboard command works
func validateDashboardCmd ( ctx context . Context , t * testing . T , profile string ) {
args := [ ] string { "dashboard" , "--url" , "-p" , profile , "--alsologtostderr" , "-v=1" }
ss , err := Start ( t , exec . CommandContext ( ctx , Target ( ) , args ... ) )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to run minikube dashboard. args %q : %v" , args , err )
2019-09-11 16:59:38 +00:00
}
defer func ( ) {
ss . Stop ( t )
} ( )
start := time . Now ( )
2020-02-21 00:19:59 +00:00
s , err := ReadLineWithTimeout ( ss . Stdout , Seconds ( 300 ) )
2019-09-11 16:59:38 +00:00
if err != nil {
2019-11-06 22:14:56 +00:00
if runtime . GOOS == "windows" {
t . Skipf ( "failed to read url within %s: %v\noutput: %q\n" , time . Since ( start ) , err , s )
}
t . Fatalf ( "failed to read url within %s: %v\noutput: %q\n" , time . Since ( start ) , err , s )
2019-09-11 16:59:38 +00:00
}
u , err := url . Parse ( strings . TrimSpace ( s ) )
if err != nil {
t . Fatalf ( "failed to parse %q: %v" , s , err )
}
resp , err := retryablehttp . Get ( u . String ( ) )
if err != nil {
2020-04-02 17:51:15 +00:00
t . Fatalf ( "failed to http get %q: %v\nresponse: %+v" , u . String ( ) , err , resp )
2019-09-11 16:59:38 +00:00
}
2020-04-02 17:51:15 +00:00
2019-09-11 16:59:38 +00:00
if resp . StatusCode != http . StatusOK {
body , err := ioutil . ReadAll ( resp . Body )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to read http response body from dashboard %q: %v" , u . String ( ) , err )
2019-09-11 16:59:38 +00:00
}
t . Errorf ( "%s returned status code %d, expected %d.\nbody:\n%s" , u , resp . StatusCode , http . StatusOK , body )
}
}
2019-07-30 04:52:05 +00:00
2019-09-11 16:59:38 +00:00
// validateDNS asserts that all Kubernetes DNS is healthy
func validateDNS ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "replace" , "--force" , "-f" , filepath . Join ( * testdataDir , "busybox.yaml" ) ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to kubectl replace busybox : args %q: %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
2020-02-21 01:01:28 +00:00
names , err := PodWait ( ctx , t , profile , "default" , "integration-test=busybox" , Minutes ( 4 ) )
2019-09-11 16:59:38 +00:00
if err != nil {
2020-03-26 02:58:38 +00:00
t . Fatalf ( "failed waiting for busybox pod : %v" , err )
2019-09-11 16:59:38 +00:00
}
2019-09-11 20:08:44 +00:00
nslookup := func ( ) error {
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "exec" , names [ 0 ] , "nslookup" , "kubernetes.default" ) )
return err
}
// If the coredns process was stable, this retry wouldn't be necessary.
2020-02-21 00:40:18 +00:00
if err = retry . Expo ( nslookup , 1 * time . Second , Minutes ( 1 ) ) ; err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "failed to do nslookup on kubernetes.default: %v" , err )
2019-09-11 16:59:38 +00:00
}
want := [ ] byte ( "10.96.0.1" )
if ! bytes . Contains ( rr . Stdout . Bytes ( ) , want ) {
2020-03-26 02:58:38 +00:00
t . Errorf ( "failed nslookup: got=%q, want=*%q*" , rr . Stdout . Bytes ( ) , want )
2019-09-11 16:59:38 +00:00
}
}
2020-01-09 19:10:23 +00:00
// validateDryRun asserts that the dry-run mode quickly exits with the right code
func validateDryRun ( ctx context . Context , t * testing . T , profile string ) {
2020-01-22 20:14:05 +00:00
// dry-run mode should always be able to finish quickly (<5s)
2020-02-21 00:19:59 +00:00
mctx , cancel := context . WithTimeout ( ctx , Seconds ( 5 ) )
2020-01-09 19:10:23 +00:00
defer cancel ( )
// Too little memory!
2020-01-22 20:14:05 +00:00
startArgs := append ( [ ] string { "start" , "-p" , profile , "--dry-run" , "--memory" , "250MB" , "--alsologtostderr" , "-v=1" } , StartArgs ( ) ... )
2020-01-09 19:10:23 +00:00
c := exec . CommandContext ( mctx , Target ( ) , startArgs ... )
rr , err := Run ( t , c )
wantCode := 78 // exit.Config
if rr . ExitCode != wantCode {
t . Errorf ( "dry-run(250MB) exit code = %d, wanted = %d: %v" , rr . ExitCode , wantCode , err )
}
2020-02-21 00:19:59 +00:00
dctx , cancel := context . WithTimeout ( ctx , Seconds ( 5 ) )
2020-01-09 19:10:23 +00:00
defer cancel ( )
2020-01-22 20:14:05 +00:00
startArgs = append ( [ ] string { "start" , "-p" , profile , "--dry-run" , "--alsologtostderr" , "-v=1" } , StartArgs ( ) ... )
2020-01-09 19:10:23 +00:00
c = exec . CommandContext ( dctx , Target ( ) , startArgs ... )
rr , err = Run ( t , c )
if rr . ExitCode != 0 || err != nil {
t . Errorf ( "dry-run exit code = %d, wanted = %d: %v" , rr . ExitCode , 0 , err )
}
}
2019-11-27 00:08:07 +00:00
// validateCacheCmd tests functionality of cache command (cache add, delete, list)
2019-09-11 16:59:38 +00:00
func validateCacheCmd ( ctx context . Context , t * testing . T , profile string ) {
if NoneDriver ( ) {
t . Skipf ( "skipping: cache unsupported by none" )
}
2019-11-27 00:19:29 +00:00
t . Run ( "cache" , func ( t * testing . T ) {
t . Run ( "add" , func ( t * testing . T ) {
2020-02-13 09:20:32 +00:00
for _ , img := range [ ] string { "busybox:latest" , "busybox:1.28.4-glibc" , "k8s.gcr.io/pause:latest" } {
2020-03-26 04:43:32 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "cache" , "add" , img ) )
2019-11-27 00:19:29 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to cache add image %q. args %q err %v" , img , rr . Command ( ) , err )
2019-11-27 00:19:29 +00:00
}
}
} )
2020-02-13 02:11:44 +00:00
t . Run ( "delete_busybox:1.28.4-glibc" , func ( t * testing . T ) {
2020-03-26 04:43:32 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "cache" , "delete" , "busybox:1.28.4-glibc" ) )
2019-11-27 00:19:29 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to delete image busybox:1.28.4-glibc from cache. args %q: %v" , rr . Command ( ) , err )
2019-11-27 00:19:29 +00:00
}
} )
2019-11-27 00:08:07 +00:00
2019-11-27 00:19:29 +00:00
t . Run ( "list" , func ( t * testing . T ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "cache" , "list" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to do cache list. args %q: %v" , rr . Command ( ) , err )
2019-11-27 00:19:29 +00:00
}
if ! strings . Contains ( rr . Output ( ) , "k8s.gcr.io/pause" ) {
2020-04-02 04:40:09 +00:00
t . Errorf ( "expected 'cache list' output to include 'k8s.gcr.io/pause' but got:\n ***%s***" , rr . Output ( ) )
2019-11-27 00:19:29 +00:00
}
if strings . Contains ( rr . Output ( ) , "busybox:1.28.4-glibc" ) {
2020-04-02 04:40:09 +00:00
t . Errorf ( "expected 'cache list' output not to include busybox:1.28.4-glibc but got:\n ***%s***" , rr . Output ( ) )
2019-11-27 00:19:29 +00:00
}
} )
2019-11-27 00:08:07 +00:00
2020-02-13 02:11:44 +00:00
t . Run ( "verify_cache_inside_node" , func ( t * testing . T ) {
2019-12-10 20:15:20 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "sudo" , "crictl" , "images" ) )
2019-11-27 00:19:29 +00:00
if err != nil {
2019-12-11 05:01:12 +00:00
t . Errorf ( "failed to get images by %q ssh %v" , rr . Command ( ) , err )
2019-11-27 00:19:29 +00:00
}
2019-12-10 20:15:20 +00:00
if ! strings . Contains ( rr . Output ( ) , "1.28.4-glibc" ) {
2020-04-02 04:40:09 +00:00
t . Errorf ( "expected '1.28.4-glibc' to be in the output but got *%s*" , rr . Output ( ) )
2019-11-27 00:19:29 +00:00
}
} )
2019-12-11 05:01:12 +00:00
2020-02-13 02:11:44 +00:00
t . Run ( "cache_reload" , func ( t * testing . T ) { // deleting image inside minikube node manually and expecting reload to bring it back
2019-12-11 05:01:12 +00:00
img := "busybox:latest"
// deleting image inside minikube node manually
2019-12-11 05:26:37 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "sudo" , "docker" , "rmi" , img ) ) // for some reason crictl rmi doesn't work
2019-12-11 05:01:12 +00:00
if err != nil {
t . Errorf ( "failed to delete inside the node %q : %v" , rr . Command ( ) , err )
}
// make sure the image is deleted.
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "sudo" , "crictl" , "inspecti" , img ) )
if err == nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "expected an error. because image should not exist. but got *nil error* ! cmd: %q" , rr . Command ( ) )
2019-12-11 05:01:12 +00:00
}
2019-12-11 05:06:17 +00:00
// minikube cache reload.
2019-12-11 05:01:12 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "cache" , "reload" ) )
if err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "expected %q to run successfully but got error: %v" , rr . Command ( ) , err )
2019-12-11 05:01:12 +00:00
}
2019-12-11 05:06:17 +00:00
// make sure 'cache reload' brought back the manually deleted image.
2019-12-11 05:01:12 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , "sudo" , "crictl" , "inspecti" , img ) )
if err != nil {
2020-03-26 02:58:38 +00:00
t . Errorf ( "expected %q to run successfully but got error: %v" , rr . Command ( ) , err )
2019-12-11 05:01:12 +00:00
}
} )
2019-11-27 00:19:29 +00:00
} )
2019-09-11 16:59:38 +00:00
}
// validateConfigCmd asserts basic "config" command functionality
func validateConfigCmd ( ctx context . Context , t * testing . T , profile string ) {
tests := [ ] struct {
args [ ] string
wantOut string
wantErr string
} {
{ [ ] string { "unset" , "cpus" } , "" , "" } ,
{ [ ] string { "get" , "cpus" } , "" , "Error: specified key could not be found in config" } ,
2020-04-02 19:27:19 +00:00
{ [ ] string { "set" , "cpus" , "2" } , "" , "! These changes will take effect upon a minikube delete and then a minikube start" } ,
2019-09-11 16:59:38 +00:00
{ [ ] string { "get" , "cpus" } , "2" , "" } ,
{ [ ] string { "unset" , "cpus" } , "" , "" } ,
{ [ ] string { "get" , "cpus" } , "" , "Error: specified key could not be found in config" } ,
}
for _ , tc := range tests {
args := append ( [ ] string { "-p" , profile , "config" } , tc . args ... )
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , args ... ) )
if err != nil && tc . wantErr == "" {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to config minikube. args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
got := strings . TrimSpace ( rr . Stdout . String ( ) )
if got != tc . wantOut {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected config output for %q to be -%q- but got *%q*" , rr . Command ( ) , tc . wantOut , got )
2019-09-11 16:59:38 +00:00
}
got = strings . TrimSpace ( rr . Stderr . String ( ) )
if got != tc . wantErr {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected config error for %q to be -%q- but got *%q*" , rr . Command ( ) , tc . wantErr , got )
2019-09-11 16:59:38 +00:00
}
}
}
// validateLogsCmd asserts basic "logs" command functionality
func validateLogsCmd ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "logs" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
for _ , word := range [ ] string { "Docker" , "apiserver" , "Linux" , "kubelet" } {
if ! strings . Contains ( rr . Stdout . String ( ) , word ) {
2020-04-02 04:40:09 +00:00
t . Errorf ( "excpeted minikube logs to include word: -%q- but got \n***%s***\n" , word , rr . Output ( ) )
2019-09-11 16:59:38 +00:00
}
}
}
2019-10-11 17:16:26 +00:00
// validateProfileCmd asserts "profile" command functionality
2019-09-11 16:59:38 +00:00
func validateProfileCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-02-20 06:30:47 +00:00
t . Run ( "profile_not_create" , func ( t * testing . T ) {
// Profile command should not create a nonexistent profile
nonexistentProfile := "lis"
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , nonexistentProfile ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , "list" , "--output" , "json" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
var profileJSON map [ string ] [ ] map [ string ] interface { }
err = json . Unmarshal ( rr . Stdout . Bytes ( ) , & profileJSON )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
for profileK := range profileJSON {
for _ , p := range profileJSON [ profileK ] {
var name = p [ "Name" ]
if name == nonexistentProfile {
t . Errorf ( "minikube profile %s should not exist" , nonexistentProfile )
}
2020-02-20 03:56:32 +00:00
}
2020-02-18 12:10:27 +00:00
}
2020-02-20 06:30:47 +00:00
} )
2020-02-18 12:10:27 +00:00
2020-02-20 06:30:47 +00:00
t . Run ( "profile_list" , func ( t * testing . T ) {
// List profiles
2020-02-20 06:41:23 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , "list" ) )
2020-02-20 06:30:47 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to list profiles: args %q : %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
2019-10-11 17:16:26 +00:00
2020-02-20 06:30:47 +00:00
// Table output
listLines := strings . Split ( strings . TrimSpace ( rr . Stdout . String ( ) ) , "\n" )
profileExists := false
for i := 3 ; i < ( len ( listLines ) - 1 ) ; i ++ {
profileLine := listLines [ i ]
if strings . Contains ( profileLine , profile ) {
profileExists = true
break
}
}
if ! profileExists {
2020-03-26 05:21:19 +00:00
t . Errorf ( "expected 'profile list' output to include %q but got *%q*. args: %q" , profile , rr . Stdout . String ( ) , rr . Command ( ) )
2019-10-11 17:16:26 +00:00
}
2020-02-20 06:30:47 +00:00
} )
t . Run ( "profile_json_output" , func ( t * testing . T ) {
// Json output
2020-02-20 06:41:23 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "profile" , "list" , "--output" , "json" ) )
2020-02-20 06:30:47 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to list profiles with json format. args %q: %v" , rr . Command ( ) , err )
2019-10-11 17:16:26 +00:00
}
2020-02-20 06:30:47 +00:00
var jsonObject map [ string ] [ ] map [ string ] interface { }
err = json . Unmarshal ( rr . Stdout . Bytes ( ) , & jsonObject )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to decode json from profile list: args %q: %v" , rr . Command ( ) , err )
2020-02-20 06:30:47 +00:00
}
validProfiles := jsonObject [ "valid" ]
2020-02-20 06:41:23 +00:00
profileExists := false
2020-02-20 06:30:47 +00:00
for _ , profileObject := range validProfiles {
if profileObject [ "Name" ] == profile {
profileExists = true
break
}
}
if ! profileExists {
2020-03-26 05:21:19 +00:00
t . Errorf ( "expected the json of 'profile list' to include %q but got *%q*. args: %q" , profile , rr . Stdout . String ( ) , rr . Command ( ) )
2020-02-20 06:30:47 +00:00
}
} )
2019-09-11 16:59:38 +00:00
}
// validateServiceCmd asserts basic "service" command functionality
2019-10-30 17:44:54 +00:00
func validateServiceCmd ( ctx context . Context , t * testing . T , profile string ) {
2019-10-30 20:57:08 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "create" , "deployment" , "hello-node" , "--image=gcr.io/hello-minikube-zero-install/hello-node" ) )
2019-10-30 17:44:54 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Logf ( "%q failed: %v (may not be an error)." , rr . Command ( ) , err )
2019-10-30 17:44:54 +00:00
}
2019-10-30 20:57:08 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "expose" , "deployment" , "hello-node" , "--type=NodePort" , "--port=8080" ) )
2019-10-30 17:44:54 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Logf ( "%q failed: %v (may not be an error)" , rr . Command ( ) , err )
2019-10-30 17:44:54 +00:00
}
2020-02-21 00:40:18 +00:00
if _ , err := PodWait ( ctx , t , profile , "default" , "app=hello-node" , Minutes ( 10 ) ) ; err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed waiting for hello-node pod: %v" , err )
2019-10-30 20:57:08 +00:00
}
2019-10-30 17:44:54 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "list" ) )
2019-09-11 16:59:38 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to do service list. args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
2019-10-30 20:57:08 +00:00
if ! strings . Contains ( rr . Stdout . String ( ) , "hello-node" ) {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected 'service list' to contain *hello-node* but got -%q-" , rr . Stdout . String ( ) )
2019-10-30 17:44:54 +00:00
}
2020-04-02 17:51:15 +00:00
if NeedsPortForward ( ) {
t . Skipf ( "test is broken for port-forwarded drivers: https://github.com/kubernetes/minikube/issues/7383" )
}
2019-10-30 17:44:54 +00:00
// Test --https --url mode
2019-10-30 20:57:08 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "--namespace=default" , "--https" , "--url" , "hello-node" ) )
2019-10-30 17:44:54 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to get service url. args %q : %v" , rr . Command ( ) , err )
2019-10-30 20:57:08 +00:00
}
if rr . Stderr . String ( ) != "" {
2020-04-18 21:37:58 +00:00
t . Errorf ( "expected stderr to be empty but got *%q* . args %q" , rr . Stderr , rr . Command ( ) )
2019-10-30 17:44:54 +00:00
}
2019-10-30 20:57:08 +00:00
endpoint := strings . TrimSpace ( rr . Stdout . String ( ) )
2019-10-30 17:44:54 +00:00
u , err := url . Parse ( endpoint )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed to parse service url endpoint %q: %v" , endpoint , err )
2019-10-30 17:44:54 +00:00
}
if u . Scheme != "https" {
2020-03-26 04:43:32 +00:00
t . Errorf ( "expected scheme to be 'https' but got %q" , u . Scheme )
2019-10-30 17:44:54 +00:00
}
// Test --format=IP
2019-10-30 20:57:08 +00:00
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "hello-node" , "--url" , "--format={{.IP}}" ) )
2019-10-30 17:44:54 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to get service url with custom format. args %q: %v" , rr . Command ( ) , err )
2019-10-30 17:44:54 +00:00
}
2019-10-30 20:57:08 +00:00
if strings . TrimSpace ( rr . Stdout . String ( ) ) != u . Hostname ( ) {
2020-03-26 05:21:19 +00:00
t . Errorf ( "expected 'service --format={{.IP}}' output to be -%q- but got *%q* . args %q." , u . Hostname ( ) , rr . Stdout . String ( ) , rr . Command ( ) )
2019-10-30 17:44:54 +00:00
}
2019-10-30 20:57:08 +00:00
// Test a regular URLminikube
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "service" , "hello-node" , "--url" ) )
2019-10-30 17:44:54 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to get service url. args: %q: %v" , rr . Command ( ) , err )
2019-10-30 17:44:54 +00:00
}
2019-10-30 20:57:08 +00:00
endpoint = strings . TrimSpace ( rr . Stdout . String ( ) )
u , err = url . Parse ( endpoint )
if err != nil {
t . Fatalf ( "failed to parse %q: %v" , endpoint , err )
}
if u . Scheme != "http" {
2020-03-26 05:15:24 +00:00
t . Fatalf ( "expected scheme to be -%q- got scheme: *%q*" , "http" , u . Scheme )
2019-10-30 20:57:08 +00:00
}
t . Logf ( "url: %s" , endpoint )
resp , err := retryablehttp . Get ( endpoint )
2019-10-30 17:44:54 +00:00
if err != nil {
2019-10-30 20:57:08 +00:00
t . Fatalf ( "get failed: %v\nresp: %v" , err , resp )
2019-10-30 17:44:54 +00:00
}
if resp . StatusCode != http . StatusOK {
2020-03-26 05:15:24 +00:00
t . Fatalf ( "expected status code for %q to be -%q- but got *%q*" , endpoint , http . StatusOK , resp . StatusCode )
2019-09-11 16:59:38 +00:00
}
}
2019-10-11 14:43:00 +00:00
// validateAddonsCmd asserts basic "addon" command functionality
func validateAddonsCmd ( ctx context . Context , t * testing . T , profile string ) {
2020-01-11 00:39:17 +00:00
// Table output
2019-10-11 14:43:00 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "addons" , "list" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to do addon list: args %q : %v" , rr . Command ( ) , err )
2019-10-11 14:43:00 +00:00
}
2020-01-11 00:39:17 +00:00
for _ , a := range [ ] string { "dashboard" , "ingress" , "ingress-dns" } {
if ! strings . Contains ( rr . Output ( ) , a ) {
2020-04-02 04:40:09 +00:00
t . Errorf ( "expected 'addon list' output to include -%q- but got *%s*" , a , rr . Output ( ) )
2019-10-11 14:43:00 +00:00
}
}
2019-10-11 18:34:50 +00:00
// Json output
rr , err = Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "addons" , "list" , "-o" , "json" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to do addon list with json output. args %q: %v" , rr . Command ( ) , err )
2019-10-11 18:34:50 +00:00
}
var jsonObject map [ string ] interface { }
err = json . Unmarshal ( rr . Stdout . Bytes ( ) , & jsonObject )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to decode addon list json output : %v" , err )
2019-10-11 18:34:50 +00:00
}
2019-10-11 14:43:00 +00:00
}
2019-09-11 16:59:38 +00:00
// validateSSHCmd asserts basic "ssh" command functionality
func validateSSHCmd ( ctx context . Context , t * testing . T , profile string ) {
if NoneDriver ( ) {
t . Skipf ( "skipping: ssh unsupported by none" )
}
2020-03-23 21:40:02 +00:00
want := "hello\n"
2019-09-11 16:59:38 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "echo hello" ) ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run an ssh command. args %q : %v" , rr . Command ( ) , err )
2019-09-11 16:59:38 +00:00
}
if rr . Stdout . String ( ) != want {
2020-03-26 05:21:19 +00:00
t . Errorf ( "expected minikube ssh command output to be -%q- but got *%q*. args %q" , want , rr . Stdout . String ( ) , rr . Command ( ) )
2019-09-11 16:59:38 +00:00
}
}
2019-10-29 05:31:57 +00:00
// validateMySQL validates a minimalist MySQL deployment
func validateMySQL ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "replace" , "--force" , "-f" , filepath . Join ( * testdataDir , "mysql.yaml" ) ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Fatalf ( "failed to kubectl replace mysql: args %q failed: %v" , rr . Command ( ) , err )
2019-10-29 05:31:57 +00:00
}
2020-02-21 00:40:18 +00:00
names , err := PodWait ( ctx , t , profile , "default" , "app=mysql" , Minutes ( 10 ) )
2019-11-06 23:17:09 +00:00
if err != nil {
2020-03-26 04:43:32 +00:00
t . Fatalf ( "failed waiting for mysql pod: %v" , err )
2019-11-06 23:17:09 +00:00
}
2019-10-29 20:13:33 +00:00
// Retry, as mysqld first comes up without users configured. Scan for names in case of a reschedule.
mysql := func ( ) error {
rr , err = Run ( t , exec . CommandContext ( ctx , "kubectl" , "--context" , profile , "exec" , names [ 0 ] , "--" , "mysql" , "-ppassword" , "-e" , "show databases;" ) )
return err
2019-10-29 05:31:57 +00:00
}
2020-04-03 07:08:32 +00:00
if err = retry . Expo ( mysql , 1 * time . Second , Minutes ( 5 ) ) ; err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to exec 'mysql -ppassword -e show databases;': %v" , err )
2019-10-29 05:31:57 +00:00
}
}
2020-02-12 22:26:38 +00:00
// vmSyncTestPath is where the test file will be synced into the VM
func vmSyncTestPath ( ) string {
return fmt . Sprintf ( "/etc/test/nested/copy/%d/hosts" , os . Getpid ( ) )
}
// localSyncTestPath is where the test file will be synced into the VM
func localSyncTestPath ( ) string {
return filepath . Join ( localpath . MiniPath ( ) , "/files" , vmSyncTestPath ( ) )
}
2020-03-04 22:48:40 +00:00
// testCert is name of the test certificate installed
func testCert ( ) string {
return fmt . Sprintf ( "%d.pem" , os . Getpid ( ) )
}
// localTestCertPath is where the test file will be synced into the VM
func localTestCertPath ( ) string {
return filepath . Join ( localpath . MiniPath ( ) , "/certs" , testCert ( ) )
}
2020-04-08 22:04:12 +00:00
// localEmptyCertPath is where the test file will be synced into the VM
func localEmptyCertPath ( ) string {
return filepath . Join ( localpath . MiniPath ( ) , "/certs" , fmt . Sprintf ( "%d_empty.pem" , os . Getpid ( ) ) )
}
2019-11-07 01:20:52 +00:00
// Copy extra file into minikube home folder for file sync test
func setupFileSync ( ctx context . Context , t * testing . T , profile string ) {
2020-02-12 22:26:38 +00:00
p := localSyncTestPath ( )
t . Logf ( "local sync path: %s" , p )
err := copy . Copy ( "./testdata/sync.test" , p )
2019-11-07 01:20:52 +00:00
if err != nil {
2020-04-08 22:04:12 +00:00
t . Fatalf ( "failed to copy ./testdata/sync.test: %v" , err )
2019-11-07 01:20:52 +00:00
}
2020-03-04 22:48:40 +00:00
2020-04-08 22:04:12 +00:00
testPem := "./testdata/minikube_test.pem"
2020-04-10 15:32:41 +00:00
// Write to a temp file for an atomic write
tmpPem := localTestCertPath ( ) + ".pem"
if err := copy . Copy ( testPem , tmpPem ) ; err != nil {
2020-04-08 22:04:12 +00:00
t . Fatalf ( "failed to copy %s: %v" , testPem , err )
}
2020-04-10 15:32:41 +00:00
if err := os . Rename ( tmpPem , localTestCertPath ( ) ) ; err != nil {
t . Fatalf ( "failed to rename %s: %v" , tmpPem , err )
}
2020-04-08 22:04:12 +00:00
want , err := os . Stat ( testPem )
if err != nil {
t . Fatalf ( "stat failed: %v" , err )
}
got , err := os . Stat ( localTestCertPath ( ) )
if err != nil {
t . Fatalf ( "stat failed: %v" , err )
}
if want . Size ( ) != got . Size ( ) {
t . Errorf ( "%s size=%d, want %d" , localTestCertPath ( ) , got . Size ( ) , want . Size ( ) )
}
// Create an empty file just to mess with people
if _ , err := os . Create ( localEmptyCertPath ( ) ) ; err != nil {
t . Fatalf ( "create failed: %v" , err )
2020-03-04 22:48:40 +00:00
}
2019-11-07 01:20:52 +00:00
}
// validateFileSync to check existence of the test file
func validateFileSync ( ctx context . Context , t * testing . T , profile string ) {
if NoneDriver ( ) {
t . Skipf ( "skipping: ssh unsupported by none" )
}
2020-02-12 22:26:38 +00:00
vp := vmSyncTestPath ( )
t . Logf ( "Checking for existence of %s within VM" , vp )
2020-04-02 17:37:23 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "sudo cat %s" , vp ) ) )
2019-11-07 01:20:52 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "%s failed: %v" , rr . Command ( ) , err )
2019-11-07 01:20:52 +00:00
}
2020-02-12 22:26:38 +00:00
got := rr . Stdout . String ( )
t . Logf ( "file sync test content: %s" , got )
2019-11-07 01:20:52 +00:00
expected , err := ioutil . ReadFile ( "./testdata/sync.test" )
if err != nil {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed to read test file '/testdata/sync.test' : %v" , err )
2019-11-07 01:20:52 +00:00
}
2020-02-12 22:26:38 +00:00
if diff := cmp . Diff ( string ( expected ) , got ) ; diff != "" {
2019-11-07 01:20:52 +00:00
t . Errorf ( "/etc/sync.test content mismatch (-want +got):\n%s" , diff )
}
}
2020-03-04 22:48:40 +00:00
// validateCertSync to check existence of the test certificate
func validateCertSync ( ctx context . Context , t * testing . T , profile string ) {
if NoneDriver ( ) {
t . Skipf ( "skipping: ssh unsupported by none" )
}
want , err := ioutil . ReadFile ( "./testdata/minikube_test.pem" )
if err != nil {
t . Errorf ( "test file not found: %v" , err )
}
// Check both the installed & reference certs (they should be symlinked)
paths := [ ] string {
path . Join ( "/etc/ssl/certs" , testCert ( ) ) ,
path . Join ( "/usr/share/ca-certificates" , testCert ( ) ) ,
// hashed path generated by: 'openssl x509 -hash -noout -in testCert()'
"/etc/ssl/certs/51391683.0" ,
}
for _ , vp := range paths {
t . Logf ( "Checking for existence of %s within VM" , vp )
2020-04-02 17:37:23 +00:00
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "ssh" , fmt . Sprintf ( "sudo cat %s" , vp ) ) )
2020-03-04 22:48:40 +00:00
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to check existence of %q inside minikube. args %q: %v" , vp , rr . Command ( ) , err )
2020-03-04 22:48:40 +00:00
}
// Strip carriage returned by ssh
got := strings . Replace ( rr . Stdout . String ( ) , "\r" , "" , - 1 )
if diff := cmp . Diff ( string ( want ) , got ) ; diff != "" {
2020-03-26 04:43:32 +00:00
t . Errorf ( "failed verify pem file. minikube_test.pem -> %s mismatch (-want +got):\n%s" , vp , diff )
2020-03-04 22:48:40 +00:00
}
}
}
2019-12-16 15:58:45 +00:00
// validateUpdateContextCmd asserts basic "update-context" command functionality
func validateUpdateContextCmd ( ctx context . Context , t * testing . T , profile string ) {
rr , err := Run ( t , exec . CommandContext ( ctx , Target ( ) , "-p" , profile , "update-context" , "--alsologtostderr" , "-v=2" ) )
if err != nil {
2020-03-26 05:21:19 +00:00
t . Errorf ( "failed to run minikube update-context: args %q: %v" , rr . Command ( ) , err )
2019-12-16 15:58:45 +00:00
}
2020-04-01 20:53:47 +00:00
want := [ ] byte ( "No changes" )
2019-12-16 15:58:45 +00:00
if ! bytes . Contains ( rr . Stdout . Bytes ( ) , want ) {
t . Errorf ( "update-context: got=%q, want=*%q*" , rr . Stdout . Bytes ( ) , want )
}
}
2019-09-11 16:59:38 +00:00
// startHTTPProxy runs a local http proxy and sets the env vars for it.
func startHTTPProxy ( t * testing . T ) ( * http . Server , error ) {
port , err := freeport . GetFreePort ( )
if err != nil {
return nil , errors . Wrap ( err , "Failed to get an open port" )
}
addr := fmt . Sprintf ( "localhost:%d" , port )
proxy := goproxy . NewProxyHttpServer ( )
srv := & http . Server { Addr : addr , Handler : proxy }
go func ( s * http . Server , t * testing . T ) {
if err := s . ListenAndServe ( ) ; err != http . ErrServerClosed {
t . Errorf ( "Failed to start http server for proxy mock" )
}
} ( srv , t )
return srv , nil
2016-12-05 22:49:52 +00:00
}