github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/client/container_exec_test.go (about)

     1  package client // import "github.com/docker/docker/client"
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/docker/docker/api/types"
    14  	"github.com/docker/docker/errdefs"
    15  	"gotest.tools/v3/assert"
    16  	is "gotest.tools/v3/assert/cmp"
    17  )
    18  
    19  func TestContainerExecCreateError(t *testing.T) {
    20  	client := &Client{
    21  		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
    22  	}
    23  	_, err := client.ContainerExecCreate(context.Background(), "container_id", types.ExecConfig{})
    24  	assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
    25  }
    26  
    27  // TestContainerExecCreateConnectionError verifies that connection errors occurring
    28  // during API-version negotiation are not shadowed by API-version errors.
    29  //
    30  // Regression test for https://github.com/docker/cli/issues/4890
    31  func TestContainerExecCreateConnectionError(t *testing.T) {
    32  	client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
    33  	assert.NilError(t, err)
    34  
    35  	_, err = client.ContainerExecCreate(context.Background(), "", types.ExecConfig{})
    36  	assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
    37  }
    38  
    39  func TestContainerExecCreate(t *testing.T) {
    40  	expectedURL := "/containers/container_id/exec"
    41  	client := &Client{
    42  		client: newMockClient(func(req *http.Request) (*http.Response, error) {
    43  			if !strings.HasPrefix(req.URL.Path, expectedURL) {
    44  				return nil, fmt.Errorf("expected URL '%s', got '%s'", expectedURL, req.URL)
    45  			}
    46  			if req.Method != http.MethodPost {
    47  				return nil, fmt.Errorf("expected POST method, got %s", req.Method)
    48  			}
    49  			// FIXME validate the content is the given ExecConfig ?
    50  			if err := req.ParseForm(); err != nil {
    51  				return nil, err
    52  			}
    53  			execConfig := &types.ExecConfig{}
    54  			if err := json.NewDecoder(req.Body).Decode(execConfig); err != nil {
    55  				return nil, err
    56  			}
    57  			if execConfig.User != "user" {
    58  				return nil, fmt.Errorf("expected an execConfig with User == 'user', got %v", execConfig)
    59  			}
    60  			b, err := json.Marshal(types.IDResponse{
    61  				ID: "exec_id",
    62  			})
    63  			if err != nil {
    64  				return nil, err
    65  			}
    66  			return &http.Response{
    67  				StatusCode: http.StatusOK,
    68  				Body:       io.NopCloser(bytes.NewReader(b)),
    69  			}, nil
    70  		}),
    71  	}
    72  
    73  	r, err := client.ContainerExecCreate(context.Background(), "container_id", types.ExecConfig{
    74  		User: "user",
    75  	})
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	if r.ID != "exec_id" {
    80  		t.Fatalf("expected `exec_id`, got %s", r.ID)
    81  	}
    82  }
    83  
    84  func TestContainerExecStartError(t *testing.T) {
    85  	client := &Client{
    86  		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
    87  	}
    88  	err := client.ContainerExecStart(context.Background(), "nothing", types.ExecStartCheck{})
    89  	assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
    90  }
    91  
    92  func TestContainerExecStart(t *testing.T) {
    93  	expectedURL := "/exec/exec_id/start"
    94  	client := &Client{
    95  		client: newMockClient(func(req *http.Request) (*http.Response, error) {
    96  			if !strings.HasPrefix(req.URL.Path, expectedURL) {
    97  				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
    98  			}
    99  			if err := req.ParseForm(); err != nil {
   100  				return nil, err
   101  			}
   102  			execStartCheck := &types.ExecStartCheck{}
   103  			if err := json.NewDecoder(req.Body).Decode(execStartCheck); err != nil {
   104  				return nil, err
   105  			}
   106  			if execStartCheck.Tty || !execStartCheck.Detach {
   107  				return nil, fmt.Errorf("expected execStartCheck{Detach:true,Tty:false}, got %v", execStartCheck)
   108  			}
   109  
   110  			return &http.Response{
   111  				StatusCode: http.StatusOK,
   112  				Body:       io.NopCloser(bytes.NewReader([]byte(""))),
   113  			}, nil
   114  		}),
   115  	}
   116  
   117  	err := client.ContainerExecStart(context.Background(), "exec_id", types.ExecStartCheck{
   118  		Detach: true,
   119  		Tty:    false,
   120  	})
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  }
   125  
   126  func TestContainerExecInspectError(t *testing.T) {
   127  	client := &Client{
   128  		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
   129  	}
   130  	_, err := client.ContainerExecInspect(context.Background(), "nothing")
   131  	assert.Check(t, is.ErrorType(err, errdefs.IsSystem))
   132  }
   133  
   134  func TestContainerExecInspect(t *testing.T) {
   135  	expectedURL := "/exec/exec_id/json"
   136  	client := &Client{
   137  		client: newMockClient(func(req *http.Request) (*http.Response, error) {
   138  			if !strings.HasPrefix(req.URL.Path, expectedURL) {
   139  				return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
   140  			}
   141  			b, err := json.Marshal(types.ContainerExecInspect{
   142  				ExecID:      "exec_id",
   143  				ContainerID: "container_id",
   144  			})
   145  			if err != nil {
   146  				return nil, err
   147  			}
   148  			return &http.Response{
   149  				StatusCode: http.StatusOK,
   150  				Body:       io.NopCloser(bytes.NewReader(b)),
   151  			}, nil
   152  		}),
   153  	}
   154  
   155  	inspect, err := client.ContainerExecInspect(context.Background(), "exec_id")
   156  	if err != nil {
   157  		t.Fatal(err)
   158  	}
   159  	if inspect.ExecID != "exec_id" {
   160  		t.Fatalf("expected ExecID to be `exec_id`, got %s", inspect.ExecID)
   161  	}
   162  	if inspect.ContainerID != "container_id" {
   163  		t.Fatalf("expected ContainerID `container_id`, got %s", inspect.ContainerID)
   164  	}
   165  }