github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/kubetest/process/process_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package process
    18  
    19  import (
    20  	"errors"
    21  	"log"
    22  	"os/exec"
    23  	"strconv"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"k8s.io/test-infra/kubetest/util"
    29  )
    30  
    31  var suite util.TestSuite
    32  
    33  func TestXMLWrap(t *testing.T) {
    34  	cases := []struct {
    35  		name            string
    36  		interrupted     bool
    37  		shouldInterrupt bool
    38  		err             string
    39  		expectSkipped   bool
    40  		expectError     bool
    41  	}{
    42  		{
    43  			name: "xmlWrap can pass",
    44  		},
    45  		{
    46  			name:        "xmlWrap can error",
    47  			err:         "hello there",
    48  			expectError: true,
    49  		},
    50  		{
    51  			name:            "xmlWrap always errors on interrupt",
    52  			err:             "",
    53  			shouldInterrupt: true,
    54  			expectError:     true,
    55  		},
    56  		{
    57  			name:            "xmlWrap errors on interrupt",
    58  			shouldInterrupt: true,
    59  			err:             "the step failed",
    60  			expectError:     true,
    61  		},
    62  		{
    63  			name:          "xmlWrap skips errors when already interrupted",
    64  			interrupted:   true,
    65  			err:           "this failed because we interrupted the previous step",
    66  			expectSkipped: true,
    67  		},
    68  		{
    69  			name:        "xmlWrap can pass when interrupted",
    70  			interrupted: true,
    71  			err:         "",
    72  		},
    73  	}
    74  
    75  	for _, tc := range cases {
    76  		interrupt := time.NewTimer(time.Duration(0))
    77  		terminate := time.NewTimer(time.Duration(0))
    78  		c := NewControl(time.Duration(0), interrupt, terminate, false)
    79  		c.interrupted = tc.interrupted
    80  		suite.Cases = suite.Cases[:0]
    81  		suite.Failures = 6
    82  		suite.Tests = 9
    83  		err := c.XMLWrap(&suite, tc.name, func() error {
    84  			if tc.shouldInterrupt {
    85  				c.interrupted = true
    86  			}
    87  			if tc.err != "" {
    88  				return errors.New(tc.err)
    89  			}
    90  			return nil
    91  		})
    92  
    93  		if tc.shouldInterrupt && tc.expectError {
    94  			if err == nil {
    95  				t.Fatalf("Case %s did not error", tc.name)
    96  			}
    97  			if tc.err == "" {
    98  				tc.err = err.Error()
    99  			}
   100  		}
   101  		if (tc.err == "") != (err == nil) {
   102  			t.Errorf("Case %s expected err: %s != actual: %v", tc.name, tc.err, err)
   103  		}
   104  		if tc.shouldInterrupt && !c.interrupted {
   105  			t.Errorf("Case %s did not interrupt", tc.name)
   106  		}
   107  		if len(suite.Cases) != 1 {
   108  			t.Fatalf("Case %s did not result in a single suite testcase: %v", tc.name, suite.Cases)
   109  		}
   110  
   111  		sc := suite.Cases[0]
   112  		if sc.Name != tc.name {
   113  			t.Errorf("Case %s resulted in wrong test case name %s", tc.name, sc.Name)
   114  		}
   115  		if tc.expectError {
   116  			if sc.Failure != tc.err {
   117  				t.Errorf("Case %s expected error %s but got %s", tc.name, tc.err, sc.Failure)
   118  			}
   119  			if suite.Failures != 7 {
   120  				t.Errorf("Case %s failed and should increase suite failures from 6 to 7, found: %d", tc.name, suite.Failures)
   121  			}
   122  		} else if tc.expectSkipped {
   123  			if sc.Skipped != tc.err {
   124  				t.Errorf("Case %s expected skipped %s but got %s", tc.name, tc.err, sc.Skipped)
   125  			}
   126  			if suite.Failures != 7 {
   127  				t.Errorf("Case %s interrupted and increase suite failures from 6 to 7, found: %d", tc.name, suite.Failures)
   128  			}
   129  		} else {
   130  			if suite.Failures != 6 {
   131  				t.Errorf("Case %s passed so suite failures should remain at 6, found: %d", tc.name, suite.Failures)
   132  			}
   133  		}
   134  
   135  	}
   136  }
   137  
   138  func TestOutput(t *testing.T) {
   139  	cases := []struct {
   140  		name              string
   141  		terminated        bool
   142  		interrupted       bool
   143  		causeTermination  bool
   144  		causeInterruption bool
   145  		pass              bool
   146  		sleep             int
   147  		output            bool
   148  		shouldError       bool
   149  		shouldInterrupt   bool
   150  		shouldTerminate   bool
   151  	}{
   152  		{
   153  			name: "finishRunning can pass",
   154  			pass: true,
   155  		},
   156  		{
   157  			name:   "output can pass",
   158  			output: true,
   159  			pass:   true,
   160  		},
   161  		{
   162  			name:        "finishRuning can fail",
   163  			pass:        false,
   164  			shouldError: true,
   165  		},
   166  		{
   167  			name:        "output can fail",
   168  			pass:        false,
   169  			output:      true,
   170  			shouldError: true,
   171  		},
   172  		{
   173  			name:        "finishRunning should error when terminated",
   174  			terminated:  true,
   175  			pass:        true,
   176  			shouldError: true,
   177  		},
   178  		{
   179  			name:        "output should error when terminated",
   180  			terminated:  true,
   181  			pass:        true,
   182  			output:      true,
   183  			shouldError: true,
   184  		},
   185  		{
   186  			name:              "finishRunning should interrupt when interrupted",
   187  			pass:              true,
   188  			sleep:             60,
   189  			causeInterruption: true,
   190  			shouldError:       true,
   191  		},
   192  		{
   193  			name:              "output should interrupt when interrupted",
   194  			pass:              true,
   195  			sleep:             60,
   196  			output:            true,
   197  			causeInterruption: true,
   198  			shouldError:       true,
   199  		},
   200  		{
   201  			name:             "output should terminate when terminated",
   202  			pass:             true,
   203  			sleep:            60,
   204  			output:           true,
   205  			causeTermination: true,
   206  			shouldError:      true,
   207  		},
   208  		{
   209  			name:             "finishRunning should terminate when terminated",
   210  			pass:             true,
   211  			sleep:            60,
   212  			causeTermination: true,
   213  			shouldError:      true,
   214  		},
   215  	}
   216  
   217  	clearTimers := func(c *Control) {
   218  		if !c.Terminate.Stop() {
   219  			<-c.Terminate.C
   220  		}
   221  		if !c.Interrupt.Stop() {
   222  			<-c.Interrupt.C
   223  		}
   224  	}
   225  
   226  	for _, tc := range cases {
   227  		log.Println(tc.name)
   228  		interrupt := time.NewTimer(time.Duration(0))
   229  		terminate := time.NewTimer(time.Duration(0))
   230  		c := NewControl(time.Duration(0), interrupt, terminate, false)
   231  		c.terminated = tc.terminated
   232  		c.interrupted = tc.interrupted
   233  		clearTimers(c)
   234  		if tc.causeInterruption {
   235  			interrupt.Reset(0)
   236  		}
   237  		if tc.causeTermination {
   238  			terminate.Reset(0)
   239  		}
   240  		var cmd *exec.Cmd
   241  		if !tc.pass {
   242  			cmd = exec.Command("false")
   243  		} else if tc.sleep == 0 {
   244  			cmd = exec.Command("true")
   245  		} else {
   246  			cmd = exec.Command("sleep", strconv.Itoa(tc.sleep))
   247  		}
   248  		var err error
   249  		if tc.output {
   250  			_, err = c.Output(cmd)
   251  		} else {
   252  			err = c.FinishRunning(cmd)
   253  		}
   254  		if err == nil == tc.shouldError {
   255  			t.Errorf("Step %s shouldError=%v error: %v", tc.name, tc.shouldError, err)
   256  		}
   257  		if tc.causeInterruption && !c.interrupted {
   258  			t.Errorf("Step %s did not interrupt, err: %v", tc.name, err)
   259  		} else if tc.causeInterruption && !terminate.Reset(0) {
   260  			t.Errorf("Step %s did not reset the terminate timer: %v", tc.name, err)
   261  		}
   262  		if tc.causeTermination && !c.terminated {
   263  			t.Errorf("Step %s did not terminate, err: %v", tc.name, err)
   264  		}
   265  	}
   266  }
   267  
   268  func TestFinishRunningParallel(t *testing.T) {
   269  	cases := []struct {
   270  		name              string
   271  		terminated        bool
   272  		interrupted       bool
   273  		causeTermination  bool
   274  		causeInterruption bool
   275  		cmds              []*exec.Cmd
   276  		shouldError       bool
   277  		shouldInterrupt   bool
   278  		shouldTerminate   bool
   279  	}{
   280  		{
   281  			name: "finishRunningParallel with single command can pass",
   282  			cmds: []*exec.Cmd{exec.Command("true")},
   283  		},
   284  		{
   285  			name: "finishRunningParallel with multiple commands can pass",
   286  			cmds: []*exec.Cmd{exec.Command("true"), exec.Command("true")},
   287  		},
   288  		{
   289  			name:        "finishRunningParallel with single command can fail",
   290  			cmds:        []*exec.Cmd{exec.Command("false")},
   291  			shouldError: true,
   292  		},
   293  		{
   294  			name:        "finishRunningParallel with multiple commands can fail",
   295  			cmds:        []*exec.Cmd{exec.Command("true"), exec.Command("false")},
   296  			shouldError: true,
   297  		},
   298  		{
   299  			name:        "finishRunningParallel should error when terminated",
   300  			cmds:        []*exec.Cmd{exec.Command("true"), exec.Command("true")},
   301  			terminated:  true,
   302  			shouldError: true,
   303  		},
   304  		{
   305  			name:              "finishRunningParallel should interrupt when interrupted",
   306  			cmds:              []*exec.Cmd{exec.Command("true"), exec.Command("sleep", "60"), exec.Command("sleep", "30")},
   307  			causeInterruption: true,
   308  			shouldError:       true,
   309  		},
   310  		{
   311  			name:             "finishRunningParallel should terminate when terminated",
   312  			cmds:             []*exec.Cmd{exec.Command("true"), exec.Command("sleep", "60"), exec.Command("sleep", "30")},
   313  			causeTermination: true,
   314  			shouldError:      true,
   315  		},
   316  	}
   317  
   318  	clearTimers := func(c *Control) {
   319  		if !c.Terminate.Stop() {
   320  			<-c.Terminate.C
   321  		}
   322  		if !c.Interrupt.Stop() {
   323  			<-c.Interrupt.C
   324  		}
   325  	}
   326  
   327  	for _, tc := range cases {
   328  		log.Println(tc.name)
   329  		interrupt := time.NewTimer(time.Duration(0))
   330  		terminate := time.NewTimer(time.Duration(0))
   331  		c := NewControl(time.Duration(0), interrupt, terminate, false)
   332  		c.terminated = tc.terminated
   333  		c.interrupted = tc.interrupted
   334  		clearTimers(c)
   335  		if tc.causeInterruption {
   336  			interrupt.Reset(1 * time.Second)
   337  		}
   338  		if tc.causeTermination {
   339  			terminate.Reset(1 * time.Second)
   340  		}
   341  
   342  		err := c.FinishRunningParallel(tc.cmds...)
   343  		if err == nil == tc.shouldError {
   344  			t.Errorf("TC %q shouldError=%v error: %v", tc.name, tc.shouldError, err)
   345  		}
   346  		if tc.causeInterruption && !c.interrupted {
   347  			t.Errorf("TC %q did not interrupt, err: %v", tc.name, err)
   348  		} else if tc.causeInterruption && !terminate.Reset(0) {
   349  			t.Errorf("TC %q did not reset the terminate timer: %v", tc.name, err)
   350  		}
   351  		if tc.causeTermination && !c.terminated {
   352  			t.Errorf("TC %q did not terminate, err: %v", tc.name, err)
   353  		}
   354  	}
   355  }
   356  
   357  func TestOutputOutputs(t *testing.T) {
   358  	interrupt := time.NewTimer(time.Duration(1) * time.Second)
   359  	terminate := time.NewTimer(time.Duration(1) * time.Second)
   360  	c := NewControl(time.Duration(1)*time.Second, interrupt, terminate, false)
   361  
   362  	b, err := c.Output(exec.Command("echo", "hello world"))
   363  	txt := string(b)
   364  	if err != nil {
   365  		t.Fatalf("failed to echo: %v", err)
   366  	}
   367  	if !strings.Contains(txt, "hello world") {
   368  		t.Errorf("output() did not echo hello world: %v", txt)
   369  	}
   370  }