...

Source file src/github.com/Microsoft/hcsshim/internal/exec/exec_test.go

Documentation: github.com/Microsoft/hcsshim/internal/exec

     1  //go:build windows
     2  
     3  package exec
     4  
     5  import (
     6  	"context"
     7  	"io"
     8  	"os"
     9  	"path/filepath"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/Microsoft/hcsshim/internal/conpty"
    14  	"github.com/Microsoft/hcsshim/internal/jobobject"
    15  )
    16  
    17  func TestExec(t *testing.T) {
    18  	// Exec a simple process and wait for exit.
    19  	e, err := New(
    20  		`C:\Windows\System32\ping.exe`,
    21  		"ping 127.0.0.1",
    22  		WithEnv(os.Environ()),
    23  	)
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  
    28  	err = e.Start()
    29  	if err != nil {
    30  		t.Fatalf("failed to start process: %v", err)
    31  	}
    32  
    33  	err = e.Wait()
    34  	if err != nil {
    35  		t.Fatalf("error waiting for process: %v", err)
    36  	}
    37  	t.Logf("exit code was: %d", e.ExitCode())
    38  }
    39  
    40  func TestExecWithDir(t *testing.T) {
    41  	// Test that the working directory is successfully set to whatever was passed in.
    42  	dir := t.TempDir()
    43  
    44  	e, err := New(
    45  		`C:\Windows\System32\cmd.exe`,
    46  		"cmd /c echo 'test' > test.txt",
    47  		WithDir(dir),
    48  		WithEnv(os.Environ()),
    49  	)
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  
    54  	err = e.Start()
    55  	if err != nil {
    56  		t.Fatalf("failed to start process: %v", err)
    57  	}
    58  
    59  	err = e.Wait()
    60  	if err != nil {
    61  		t.Fatalf("error waiting for process: %v", err)
    62  	}
    63  
    64  	if _, err := os.Stat(filepath.Join(dir, "test.txt")); err != nil {
    65  		t.Fatal(err)
    66  	}
    67  
    68  	t.Logf("exit code was: %d", e.ExitCode())
    69  }
    70  
    71  func TestExecStdinPowershell(t *testing.T) {
    72  	// Exec a powershell instance and test that we can write commands to stdin and receive the output from stdout.
    73  	e, err := New(
    74  		`C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`,
    75  		"powershell",
    76  		WithStdio(true, false, true),
    77  		WithEnv(os.Environ()),
    78  	)
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  
    83  	err = e.Start()
    84  	if err != nil {
    85  		t.Fatalf("failed to start process: %v", err)
    86  	}
    87  
    88  	errChan := make(chan error)
    89  	go func() {
    90  		_, _ = io.Copy(os.Stdout, e.Stdout())
    91  	}()
    92  
    93  	go func() {
    94  		cmd := "ping 127.0.0.1\r\n"
    95  		if _, err := e.Stdin().Write([]byte(cmd)); err != nil {
    96  			errChan <- err
    97  		}
    98  
    99  		exit := "exit\r\n"
   100  		if _, err := e.Stdin().Write([]byte(exit)); err != nil {
   101  			errChan <- err
   102  		}
   103  		close(errChan)
   104  	}()
   105  
   106  	err = <-errChan
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	waitChan := make(chan error)
   112  	go func() {
   113  		waitChan <- e.Wait()
   114  	}()
   115  
   116  	select {
   117  	case err := <-waitChan:
   118  		if err != nil {
   119  			t.Fatalf("error waiting for process: %v", err)
   120  		}
   121  	case <-time.After(time.Second * 10):
   122  		_ = e.Kill()
   123  		t.Fatal("timed out waiting for process to complete")
   124  	}
   125  
   126  	t.Logf("exit code was: %d", e.ExitCode())
   127  }
   128  
   129  func TestExecsWithJob(t *testing.T) {
   130  	// Test that we can assign processes to a job object at creation time.
   131  	job, err := jobobject.Create(context.Background(), nil)
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  	defer job.Close()
   136  
   137  	e, err := New(
   138  		`C:\Windows\System32\ping.exe`,
   139  		"ping -t 127.0.0.1",
   140  		WithJobObject(job),
   141  		WithStdio(false, false, false),
   142  		WithEnv(os.Environ()),
   143  	)
   144  	if err != nil {
   145  		t.Fatal(err)
   146  	}
   147  
   148  	err = e.Start()
   149  	if err != nil {
   150  		t.Fatalf("failed to start process: %v", err)
   151  	}
   152  
   153  	// Launch a second process and check pids.
   154  	e2, err := New(
   155  		`C:\Windows\System32\ping.exe`,
   156  		"ping -t 127.0.0.1",
   157  		WithJobObject(job),
   158  		WithStdio(false, false, false),
   159  		WithEnv(os.Environ()),
   160  	)
   161  	if err != nil {
   162  		t.Fatal(err)
   163  	}
   164  
   165  	err = e2.Start()
   166  	if err != nil {
   167  		t.Fatalf("failed to start process: %v", err)
   168  	}
   169  
   170  	pidMap := map[int]struct{}{
   171  		e.Pid():  {},
   172  		e2.Pid(): {},
   173  	}
   174  
   175  	pids, err := job.Pids()
   176  	if err != nil {
   177  		t.Fatal(err)
   178  	}
   179  
   180  	if len(pids) != 2 {
   181  		t.Fatalf("should be two pids in job object, got: %d. Pids: %+v", len(pids), pids)
   182  	}
   183  
   184  	for _, pid := range pids {
   185  		if _, ok := pidMap[int(pid)]; !ok {
   186  			t.Fatalf("failed to find pid %d in job object", pid)
   187  		}
   188  	}
   189  
   190  	err = e.Kill()
   191  	if err != nil {
   192  		t.Fatalf("error killing process: %v", err)
   193  	}
   194  
   195  	err = e2.Kill()
   196  	if err != nil {
   197  		t.Fatalf("error killing process: %v", err)
   198  	}
   199  
   200  	_ = e.Wait()
   201  	_ = e2.Wait()
   202  
   203  	if !e.Exited() {
   204  		t.Fatalf("Process %d should have exited after kill", e.Pid())
   205  	}
   206  	if !e2.Exited() {
   207  		t.Fatalf("Process %d should have exited after kill", e2.Pid())
   208  	}
   209  }
   210  
   211  func TestPseudoConsolePowershell(t *testing.T) {
   212  	// This test is fairly flaky on the Github CI but seems to run fine locally. Skip this for now to let contributions continue without a hitch
   213  	// and until we can replace this with a better suited test shortly.
   214  	//
   215  	// TODO(dcantah): Fix/find a better test here
   216  	t.Skip("Skipping flaky test")
   217  	cpty, err := conpty.Create(80, 20, 0)
   218  	if err != nil {
   219  		t.Fatal(err)
   220  	}
   221  	defer cpty.Close()
   222  
   223  	// Exec a powershell instance and test that we can write commands to the input side of the pty and receive data
   224  	// from the output end.
   225  	e, err := New(
   226  		`C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`,
   227  		"powershell",
   228  		WithEnv(os.Environ()),
   229  		WithConPty(cpty),
   230  	)
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  
   235  	err = e.Start()
   236  	if err != nil {
   237  		t.Fatalf("failed to start process: %v", err)
   238  	}
   239  
   240  	errChan := make(chan error)
   241  	go func() {
   242  		_, _ = io.Copy(os.Stdout, cpty.OutPipe())
   243  	}()
   244  
   245  	go func() {
   246  		cmd := "ping 127.0.0.1\r\n"
   247  		if _, err := cpty.Write([]byte(cmd)); err != nil {
   248  			errChan <- err
   249  		}
   250  
   251  		exit := "exit\r\n"
   252  		if _, err := cpty.Write([]byte(exit)); err != nil {
   253  			errChan <- err
   254  		}
   255  		close(errChan)
   256  	}()
   257  
   258  	err = <-errChan
   259  	if err != nil {
   260  		t.Fatal(err)
   261  	}
   262  
   263  	waitChan := make(chan error)
   264  	go func() {
   265  		waitChan <- e.Wait()
   266  	}()
   267  
   268  	select {
   269  	case err := <-waitChan:
   270  		if err != nil {
   271  			t.Fatalf("error waiting for process: %v", err)
   272  		}
   273  	case <-time.After(time.Second * 10):
   274  		_ = e.Kill()
   275  		t.Fatal("timed out waiting for process to complete")
   276  	}
   277  
   278  	t.Logf("exit code was: %d", e.ExitCode())
   279  }
   280  

View as plain text