github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/telemetry_utils_test.go (about)

     1  package command
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/docker/cli/cli/streams"
    12  	"github.com/spf13/cobra"
    13  	"go.opentelemetry.io/otel/attribute"
    14  	"gotest.tools/v3/assert"
    15  )
    16  
    17  func setupCobraCommands() (*cobra.Command, *cobra.Command, *cobra.Command) {
    18  	rootCmd := &cobra.Command{
    19  		Use: "root [OPTIONS] COMMAND [ARG...]",
    20  	}
    21  	childCmd := &cobra.Command{
    22  		Use: "child [OPTIONS] COMMAND [ARG...]",
    23  	}
    24  	grandchildCmd := &cobra.Command{
    25  		Use: "grandchild [OPTIONS] COMMAND [ARG...]",
    26  	}
    27  	childCmd.AddCommand(grandchildCmd)
    28  	rootCmd.AddCommand(childCmd)
    29  
    30  	return rootCmd, childCmd, grandchildCmd
    31  }
    32  
    33  func TestGetFullCommandName(t *testing.T) {
    34  	rootCmd, childCmd, grandchildCmd := setupCobraCommands()
    35  
    36  	t.Parallel()
    37  
    38  	for _, tc := range []struct {
    39  		testName string
    40  		cmd      *cobra.Command
    41  		expected string
    42  	}{
    43  		{
    44  			testName: "rootCmd",
    45  			cmd:      rootCmd,
    46  			expected: "root",
    47  		},
    48  		{
    49  			testName: "childCmd",
    50  			cmd:      childCmd,
    51  			expected: "root child",
    52  		},
    53  		{
    54  			testName: "grandChild",
    55  			cmd:      grandchildCmd,
    56  			expected: "root child grandchild",
    57  		},
    58  	} {
    59  		tc := tc
    60  		t.Run(tc.testName, func(t *testing.T) {
    61  			t.Parallel()
    62  			actual := getFullCommandName(tc.cmd)
    63  			assert.Equal(t, actual, tc.expected)
    64  		})
    65  	}
    66  }
    67  
    68  func TestGetCommandName(t *testing.T) {
    69  	rootCmd, childCmd, grandchildCmd := setupCobraCommands()
    70  
    71  	t.Parallel()
    72  
    73  	for _, tc := range []struct {
    74  		testName string
    75  		cmd      *cobra.Command
    76  		expected string
    77  	}{
    78  		{
    79  			testName: "rootCmd",
    80  			cmd:      rootCmd,
    81  			expected: "",
    82  		},
    83  		{
    84  			testName: "childCmd",
    85  			cmd:      childCmd,
    86  			expected: "child",
    87  		},
    88  		{
    89  			testName: "grandchildCmd",
    90  			cmd:      grandchildCmd,
    91  			expected: "child grandchild",
    92  		},
    93  	} {
    94  		tc := tc
    95  		t.Run(tc.testName, func(t *testing.T) {
    96  			t.Parallel()
    97  			actual := getCommandName(tc.cmd)
    98  			assert.Equal(t, actual, tc.expected)
    99  		})
   100  	}
   101  }
   102  
   103  func TestStdioAttributes(t *testing.T) {
   104  	outBuffer := new(bytes.Buffer)
   105  	errBuffer := new(bytes.Buffer)
   106  	t.Parallel()
   107  	for _, tc := range []struct {
   108  		test      string
   109  		stdinTty  bool
   110  		stdoutTty bool
   111  		// TODO(laurazard): test stderr
   112  		expected []attribute.KeyValue
   113  	}{
   114  		{
   115  			test: "",
   116  			expected: []attribute.KeyValue{
   117  				attribute.Bool("command.stdin.isatty", false),
   118  				attribute.Bool("command.stdout.isatty", false),
   119  				attribute.Bool("command.stderr.isatty", false),
   120  			},
   121  		},
   122  		{
   123  			test:      "",
   124  			stdinTty:  true,
   125  			stdoutTty: true,
   126  			expected: []attribute.KeyValue{
   127  				attribute.Bool("command.stdin.isatty", true),
   128  				attribute.Bool("command.stdout.isatty", true),
   129  				attribute.Bool("command.stderr.isatty", false),
   130  			},
   131  		},
   132  	} {
   133  		tc := tc
   134  		t.Run(tc.test, func(t *testing.T) {
   135  			t.Parallel()
   136  			cli := &DockerCli{
   137  				in:  streams.NewIn(io.NopCloser(strings.NewReader(""))),
   138  				out: streams.NewOut(outBuffer),
   139  				err: errBuffer,
   140  			}
   141  			cli.In().SetIsTerminal(tc.stdinTty)
   142  			cli.Out().SetIsTerminal(tc.stdoutTty)
   143  			actual := stdioAttributes(cli)
   144  
   145  			assert.Check(t, reflect.DeepEqual(actual, tc.expected))
   146  		})
   147  	}
   148  }
   149  
   150  func TestAttributesFromError(t *testing.T) {
   151  	t.Parallel()
   152  
   153  	for _, tc := range []struct {
   154  		testName string
   155  		err      error
   156  		expected []attribute.KeyValue
   157  	}{
   158  		{
   159  			testName: "no error",
   160  			err:      nil,
   161  			expected: []attribute.KeyValue{
   162  				attribute.Int("command.status.code", 0),
   163  			},
   164  		},
   165  		{
   166  			testName: "non-0 exit code",
   167  			err:      statusError{StatusCode: 127},
   168  			expected: []attribute.KeyValue{
   169  				attribute.String("command.error.type", "generic"),
   170  				attribute.Int("command.status.code", 127),
   171  			},
   172  		},
   173  		{
   174  			testName: "canceled",
   175  			err:      context.Canceled,
   176  			expected: []attribute.KeyValue{
   177  				attribute.String("command.error.type", "canceled"),
   178  				attribute.Int("command.status.code", 1),
   179  			},
   180  		},
   181  	} {
   182  		tc := tc
   183  		t.Run(tc.testName, func(t *testing.T) {
   184  			t.Parallel()
   185  			actual := attributesFromError(tc.err)
   186  			assert.Check(t, reflect.DeepEqual(actual, tc.expected))
   187  		})
   188  	}
   189  }