...

Source file src/github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/basic.go

Documentation: github.com/chaos-mesh/chaos-mesh/test/e2e/chaos

     1  // Copyright 2020 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package chaos
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"net/http"
    20  	"strconv"
    21  	"time"
    22  
    23  	"github.com/onsi/ginkgo"
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/labels"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/client-go/kubernetes"
    29  	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
    30  	restClient "k8s.io/client-go/rest"
    31  	"k8s.io/kubernetes/test/e2e/framework"
    32  	"sigs.k8s.io/controller-runtime/pkg/client"
    33  
    34  	"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
    35  	"github.com/chaos-mesh/chaos-mesh/pkg/portforward"
    36  	e2econfig "github.com/chaos-mesh/chaos-mesh/test/e2e/config"
    37  	"github.com/chaos-mesh/chaos-mesh/test/e2e/e2econst"
    38  	"github.com/chaos-mesh/chaos-mesh/test/e2e/util"
    39  	"github.com/chaos-mesh/chaos-mesh/test/pkg/fixture"
    40  
    41  	// testcases
    42  	dnschaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/dnschaos"
    43  	iochaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/iochaos"
    44  	networkchaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/networkchaos"
    45  	podchaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/podchaos"
    46  	sidecartestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/sidecar"
    47  	timechaostestcases "github.com/chaos-mesh/chaos-mesh/test/e2e/chaos/timechaos"
    48  )
    49  
    50  var _ = ginkgo.Describe("[Basic]", func() {
    51  	f := framework.NewDefaultFramework("chaos-mesh")
    52  	var ns string
    53  	var fwCancel context.CancelFunc
    54  	var fw portforward.PortForward
    55  	var kubeCli kubernetes.Interface
    56  	var config *restClient.Config
    57  	var cli client.Client
    58  	c := http.Client{
    59  		Timeout: 10 * time.Second,
    60  	}
    61  
    62  	ginkgo.BeforeEach(func() {
    63  		ns = f.Namespace.Name
    64  		ctx, cancel := context.WithCancel(context.Background())
    65  		clientRawConfig, err := e2econfig.LoadClientRawConfig()
    66  		framework.ExpectNoError(err, "failed to load raw config")
    67  		fw, err = portforward.NewPortForwarder(ctx, e2econfig.NewSimpleRESTClientGetter(clientRawConfig), true)
    68  		framework.ExpectNoError(err, "failed to create port forwarder")
    69  		fwCancel = cancel
    70  		kubeCli = f.ClientSet
    71  		config, err = framework.LoadConfig()
    72  		framework.ExpectNoError(err, "config error")
    73  		scheme := runtime.NewScheme()
    74  		_ = clientgoscheme.AddToScheme(scheme)
    75  		_ = v1alpha1.AddToScheme(scheme)
    76  		cli, err = client.New(config, client.Options{Scheme: scheme})
    77  		framework.ExpectNoError(err, "create client error")
    78  	})
    79  
    80  	ginkgo.AfterEach(func() {
    81  		if fwCancel != nil {
    82  			fwCancel()
    83  		}
    84  	})
    85  
    86  	ginkgo.Context("[PodChaos]", func() {
    87  		ginkgo.Context("[PodFailure]", func() {
    88  			ginkgo.It("[Schedule]", func() {
    89  				podchaostestcases.TestcasePodFailureOnceThenDelete(ns, kubeCli, cli)
    90  			})
    91  			ginkgo.It("[Pause]", func() {
    92  				podchaostestcases.TestcasePodFailurePauseThenUnPause(ns, kubeCli, cli)
    93  			})
    94  		})
    95  		ginkgo.Context("[PodKill]", func() {
    96  			ginkgo.It("[Schedule]", func() {
    97  				podchaostestcases.TestcasePodKillOnceThenDelete(ns, kubeCli, cli)
    98  			})
    99  			ginkgo.It("[Pause]", func() {
   100  				podchaostestcases.TestcasePodKillPauseThenUnPause(ns, kubeCli, cli)
   101  			})
   102  		})
   103  		ginkgo.Context("[ContainerKill]", func() {
   104  			ginkgo.It("[Schedule]", func() {
   105  				podchaostestcases.TestcaseContainerKillOnceThenDelete(ns, kubeCli, cli)
   106  			})
   107  			ginkgo.It("[Pause]", func() {
   108  				podchaostestcases.TestcaseContainerKillPauseThenUnPause(ns, kubeCli, cli)
   109  			})
   110  		})
   111  	})
   112  
   113  	// time chaos case in [TimeChaos] context
   114  	ginkgo.Context("[TimeChaos]", func() {
   115  
   116  		var err error
   117  		var port uint16
   118  		var pfCancel context.CancelFunc
   119  
   120  		ginkgo.JustBeforeEach(func() {
   121  			svc := fixture.NewE2EService("timer", ns)
   122  			_, err = kubeCli.CoreV1().Services(ns).Create(svc)
   123  			framework.ExpectNoError(err, "create service error")
   124  			nd := fixture.NewTimerDeployment("timer", ns)
   125  			_, err = kubeCli.AppsV1().Deployments(ns).Create(nd)
   126  			framework.ExpectNoError(err, "create timer deployment error")
   127  			err = util.WaitDeploymentReady("timer", ns, kubeCli)
   128  			framework.ExpectNoError(err, "wait timer deployment ready error")
   129  			_, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/timer", 8080)
   130  			framework.ExpectNoError(err, "create helper port-forward failed")
   131  		})
   132  
   133  		ginkgo.JustAfterEach(func() {
   134  			if pfCancel != nil {
   135  				pfCancel()
   136  			}
   137  		})
   138  
   139  		// time skew chaos case in [TimeSkew] context
   140  		ginkgo.Context("[TimeSkew]", func() {
   141  
   142  			ginkgo.It("[Schedule]", func() {
   143  				timechaostestcases.TestcaseTimeSkewOnceThenRecover(ns, cli, c, port)
   144  			})
   145  
   146  			ginkgo.It("[Pause]", func() {
   147  				timechaostestcases.TestcaseTimeSkewPauseThenUnpause(ns, cli, c, port)
   148  			})
   149  
   150  			ginkgo.It("[StartAtWaiting]", func() {
   151  				timechaostestcases.TestcaseTimeSkewStartAtWaitingThenIntoRunning(ns, cli, c, port)
   152  			})
   153  		})
   154  	})
   155  
   156  	// io chaos case in [IOChaos] context
   157  	ginkgo.Context("[IOChaos]", func() {
   158  
   159  		var (
   160  			err      error
   161  			port     uint16
   162  			pfCancel context.CancelFunc
   163  		)
   164  
   165  		ginkgo.JustBeforeEach(func() {
   166  			svc := fixture.NewE2EService("io", ns)
   167  			_, err = kubeCli.CoreV1().Services(ns).Create(svc)
   168  			framework.ExpectNoError(err, "create service error")
   169  			nd := fixture.NewIOTestDeployment("io-test", ns)
   170  			_, err = kubeCli.AppsV1().Deployments(ns).Create(nd)
   171  			framework.ExpectNoError(err, "create io-test deployment error")
   172  			err = util.WaitDeploymentReady("io-test", ns, kubeCli)
   173  			framework.ExpectNoError(err, "wait io-test deployment ready error")
   174  			_, port, pfCancel, err = portforward.ForwardOnePort(fw, ns, "svc/io", 8080)
   175  			framework.ExpectNoError(err, "create helper io port port-forward failed")
   176  		})
   177  
   178  		ginkgo.JustAfterEach(func() {
   179  			if pfCancel != nil {
   180  				pfCancel()
   181  			}
   182  		})
   183  
   184  		// io chaos case in [IODelay] context
   185  		ginkgo.Context("[IODelay]", func() {
   186  
   187  			ginkgo.It("[Schedule]", func() {
   188  				iochaostestcases.TestcaseIODelayDurationForATimeThenRecover(ns, cli, c, port)
   189  			})
   190  
   191  			ginkgo.It("[Pause]", func() {
   192  				iochaostestcases.TestcaseIODelayDurationForATimePauseAndUnPause(ns, cli, c, port)
   193  			})
   194  			ginkgo.It("[SpecifyContainer]", func() {
   195  				iochaostestcases.TestcaseIODelayWithSpecifiedContainer(ns, cli, c, port)
   196  			})
   197  			ginkgo.It("[WrongSpec]", func() {
   198  				iochaostestcases.TestcaseIODelayWithWrongSpec(ns, cli, c, port)
   199  			})
   200  		})
   201  
   202  		// io chaos case in [IOError] context
   203  		ginkgo.Context("[IOErrno]", func() {
   204  
   205  			ginkgo.It("[Schedule]", func() {
   206  				iochaostestcases.TestcaseIOErrorDurationForATimeThenRecover(ns, cli, c, port)
   207  			})
   208  			ginkgo.It("[Pause]", func() {
   209  				iochaostestcases.TestcaseIOErrorDurationForATimePauseAndUnPause(ns, cli, c, port)
   210  			})
   211  			ginkgo.It("[SpecifyContainer]", func() {
   212  				iochaostestcases.TestcaseIOErrorWithSpecifiedContainer(ns, cli, c, port)
   213  			})
   214  		})
   215  
   216  		// io mistake case in [IOMistake] context
   217  		ginkgo.Context("[IOMistake]", func() {
   218  
   219  			ginkgo.It("[Schedule]", func() {
   220  				iochaostestcases.TestcaseIOMistakeDurationForATimeThenRecover(ns, cli, c, port)
   221  			})
   222  			ginkgo.It("[Pause]", func() {
   223  				iochaostestcases.TestcaseIOMistakeDurationForATimePauseAndUnPause(ns, cli, c, port)
   224  			})
   225  			ginkgo.It("[SpecifyContainer]", func() {
   226  				iochaostestcases.TestcaseIOMistakeWithSpecifiedContainer(ns, cli, c, port)
   227  			})
   228  		})
   229  	})
   230  
   231  	ginkgo.Context("[Sidecar Config]", func() {
   232  		var (
   233  			cmName      string
   234  			cmNamespace string
   235  		)
   236  
   237  		// delete the created config map in each test case
   238  		ginkgo.JustAfterEach(func() {
   239  			kubeCli.CoreV1().ConfigMaps(cmNamespace).Delete(cmName, &metav1.DeleteOptions{})
   240  		})
   241  
   242  		ginkgo.Context("[Template Config]", func() {
   243  
   244  			ginkgo.It("[InValid ConfigMap key]", func() {
   245  				cmName = "incorrect-key-name"
   246  				cmNamespace = e2econst.ChaosMeshNamespace
   247  				sidecartestcases.TestcaseInvalidConfigMapKey(ns, cmNamespace, cmName, kubeCli, cli)
   248  			})
   249  
   250  			ginkgo.It("[InValid Configuration]", func() {
   251  				cmName = "incorrect-configuration"
   252  				cmNamespace = e2econst.ChaosMeshNamespace
   253  				sidecartestcases.TestcaseInvalidConfiguration(ns, cmNamespace, cmName, kubeCli, cli)
   254  			})
   255  		})
   256  
   257  		ginkgo.Context("[Injection Config]", func() {
   258  			ginkgo.It("[No Template]", func() {
   259  				cmName = "no-template-name"
   260  				cmNamespace = e2econst.ChaosMeshNamespace
   261  				sidecartestcases.TestcaseNoTemplate(ns, cmNamespace, cmName, kubeCli, cli)
   262  			})
   263  
   264  			ginkgo.It("[No Template Args]", func() {
   265  				cmName = "no-template-args"
   266  				cmNamespace = e2econst.ChaosMeshNamespace
   267  				sidecartestcases.TestcaseNoTemplateArgs(ns, cmNamespace, cmName, kubeCli, cli)
   268  			})
   269  		})
   270  	})
   271  
   272  	ginkgo.Context("[NetworkChaos]", func() {
   273  		var err error
   274  
   275  		var networkPeers []*v1.Pod
   276  		var ports []uint16
   277  		var pfCancels []context.CancelFunc
   278  
   279  		ginkgo.JustBeforeEach(func() {
   280  			ports = []uint16{}
   281  			networkPeers = []*v1.Pod{}
   282  			for index := 0; index < 4; index++ {
   283  				name := fmt.Sprintf("network-peer-%d", index)
   284  
   285  				svc := fixture.NewE2EService(name, ns)
   286  				_, err = kubeCli.CoreV1().Services(ns).Create(svc)
   287  				framework.ExpectNoError(err, "create service error")
   288  				nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": strconv.Itoa(index % 2)})
   289  				_, err = kubeCli.AppsV1().Deployments(ns).Create(nd)
   290  				framework.ExpectNoError(err, "create network-peer deployment error")
   291  				err = util.WaitDeploymentReady(name, ns, kubeCli)
   292  				framework.ExpectNoError(err, "wait network-peer deployment ready error")
   293  
   294  				pod, err := getPod(kubeCli, ns, name)
   295  				framework.ExpectNoError(err, "select network-peer pod error")
   296  				networkPeers = append(networkPeers, pod)
   297  
   298  				_, port, pfCancel, err := portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080)
   299  				ports = append(ports, port)
   300  				pfCancels = append(pfCancels, pfCancel)
   301  				framework.ExpectNoError(err, "create helper io port port-forward failed")
   302  			}
   303  		})
   304  
   305  		ginkgo.Context("[ForbidHostNetwork]", func() {
   306  			ginkgo.It("[Schedule]", func() {
   307  				networkchaostestcases.TestcaseForbidHostNetwork(ns, kubeCli, cli)
   308  			})
   309  		})
   310  
   311  		ginkgo.Context("[NetworkPartition]", func() {
   312  			ginkgo.It("[Schedule]", func() {
   313  				networkchaostestcases.TestcaseNetworkPartition(ns, cli, networkPeers, ports, c)
   314  			})
   315  		})
   316  
   317  		ginkgo.Context("[Netem]", func() {
   318  			ginkgo.It("[Schedule]", func() {
   319  				networkchaostestcases.TestcaseNetworkDelay(ns, cli, networkPeers, ports, c)
   320  			})
   321  			ginkgo.It("[PeersCrossoverWithDirectionBoth]", func() {
   322  				networkchaostestcases.TestcasePeersCrossover(ns, cli, networkPeers, ports, c)
   323  			})
   324  		})
   325  
   326  		ginkgo.JustAfterEach(func() {
   327  			for _, cancel := range pfCancels {
   328  				cancel()
   329  			}
   330  		})
   331  	})
   332  	// DNS chaos case in [DNSChaos] context
   333  	ginkgo.Context("[DNSChaos]", func() {
   334  		var err error
   335  		var port uint16
   336  
   337  		ginkgo.JustBeforeEach(func() {
   338  			name := "network-peer"
   339  
   340  			svc := fixture.NewE2EService(name, ns)
   341  			_, err = kubeCli.CoreV1().Services(ns).Create(svc)
   342  			framework.ExpectNoError(err, "create service error")
   343  			nd := fixture.NewNetworkTestDeployment(name, ns, map[string]string{"partition": "0"})
   344  			_, err = kubeCli.AppsV1().Deployments(ns).Create(nd)
   345  			framework.ExpectNoError(err, "create network-peer deployment error")
   346  			err = util.WaitDeploymentReady(name, ns, kubeCli)
   347  			framework.ExpectNoError(err, "wait network-peer deployment ready error")
   348  
   349  			_, err = getPod(kubeCli, ns, name)
   350  			framework.ExpectNoError(err, "select network-peer pod error")
   351  
   352  			_, port, _, err = portforward.ForwardOnePort(fw, ns, "svc/"+svc.Name, 8080)
   353  			framework.ExpectNoError(err, "create helper io port port-forward failed")
   354  		})
   355  		ginkgo.It("[RANDOM]", func() {
   356  			dnschaostestcases.TestcaseDNSRandom(ns, cli, port, c)
   357  		})
   358  
   359  		ginkgo.It("[ERROR]", func() {
   360  			dnschaostestcases.TestcaseDNSError(ns, cli, port, c)
   361  		})
   362  	})
   363  })
   364  
   365  func getPod(kubeCli kubernetes.Interface, ns string, appLabel string) (*v1.Pod, error) {
   366  	listOption := metav1.ListOptions{
   367  		LabelSelector: labels.SelectorFromSet(map[string]string{
   368  			"app": appLabel,
   369  		}).String(),
   370  	}
   371  
   372  	pods, err := kubeCli.CoreV1().Pods(ns).List(listOption)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  
   377  	if len(pods.Items) > 1 {
   378  		return nil, fmt.Errorf("select more than one pod")
   379  	}
   380  
   381  	if len(pods.Items) == 0 {
   382  		return nil, fmt.Errorf("cannot select any pod")
   383  	}
   384  
   385  	return &pods.Items[0], nil
   386  }
   387