github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubernetes/logger/formatter_test.go (about)

     1  /*
     2  Copyright 2021 The Skaffold 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 logger
    18  
    19  import (
    20  	"bytes"
    21  	"strings"
    22  	"sync"
    23  	"testing"
    24  
    25  	v1 "k8s.io/api/core/v1"
    26  
    27  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
    28  	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
    29  	"github.com/GoogleContainerTools/skaffold/testutil"
    30  )
    31  
    32  type mockColorPicker struct{}
    33  
    34  func (m *mockColorPicker) Pick(image string) output.Color {
    35  	return output.Default
    36  }
    37  
    38  func (m *mockColorPicker) AddImage(string) {}
    39  
    40  type mockConfig struct {
    41  	log latest.LogsConfig
    42  }
    43  
    44  func (c *mockConfig) Tail() bool {
    45  	return true
    46  }
    47  
    48  func (c *mockConfig) PipelineForImage(string) (latest.Pipeline, bool) {
    49  	var pipeline latest.Pipeline
    50  	pipeline.Deploy.Logs = c.log
    51  	return pipeline, true
    52  }
    53  
    54  func (c *mockConfig) DefaultPipeline() latest.Pipeline {
    55  	var pipeline latest.Pipeline
    56  	pipeline.Deploy.Logs = c.log
    57  	return pipeline
    58  }
    59  
    60  func (c *mockConfig) JSONParseConfig() latest.JSONParseConfig {
    61  	return c.log.JSONParse
    62  }
    63  
    64  func TestPrintLogLine(t *testing.T) {
    65  	testutil.Run(t, "verify lines are not intermixed", func(t *testutil.T) {
    66  		var (
    67  			buf bytes.Buffer
    68  			wg  sync.WaitGroup
    69  
    70  			linesPerGroup = 100
    71  			groups        = 5
    72  		)
    73  
    74  		f := newKubernetesLogFormatter(&mockConfig{log: latest.LogsConfig{Prefix: "none"}}, &mockColorPicker{}, func() bool { return false }, &v1.Pod{}, v1.ContainerStatus{})
    75  
    76  		for i := 0; i < groups; i++ {
    77  			wg.Add(1)
    78  
    79  			go func() {
    80  				for i := 0; i < linesPerGroup; i++ {
    81  					f.PrintLine(&buf, "TEXT\n")
    82  				}
    83  				wg.Done()
    84  			}()
    85  		}
    86  		wg.Wait()
    87  
    88  		lines := strings.Split(buf.String(), "\n")
    89  		for i := 0; i < groups*linesPerGroup; i++ {
    90  			t.CheckDeepEqual("TEXT", lines[i])
    91  		}
    92  	})
    93  }
    94  
    95  func TestColorForPod(t *testing.T) {
    96  	tests := []struct {
    97  		description   string
    98  		pod           *v1.Pod
    99  		expectedColor output.Color
   100  	}{
   101  		{
   102  			description:   "not found",
   103  			pod:           &v1.Pod{},
   104  			expectedColor: output.None,
   105  		},
   106  		{
   107  			description: "found",
   108  			pod: &v1.Pod{
   109  				Spec: v1.PodSpec{
   110  					Containers: []v1.Container{
   111  						{Image: "image"},
   112  					},
   113  				},
   114  			},
   115  			expectedColor: output.DefaultColorCodes[0],
   116  		},
   117  		{
   118  			description: "ignore tag",
   119  			pod: &v1.Pod{
   120  				Spec: v1.PodSpec{
   121  					Containers: []v1.Container{
   122  						{Image: "image:tag"},
   123  					},
   124  				},
   125  			},
   126  			expectedColor: output.DefaultColorCodes[0],
   127  		},
   128  		{
   129  			description: "second image",
   130  			pod: &v1.Pod{
   131  				Spec: v1.PodSpec{
   132  					Containers: []v1.Container{
   133  						{Image: "second:tag"},
   134  					},
   135  				},
   136  			},
   137  			expectedColor: output.DefaultColorCodes[1],
   138  		},
   139  		{
   140  			description: "accept image with digest",
   141  			pod: &v1.Pod{
   142  				Spec: v1.PodSpec{
   143  					Containers: []v1.Container{
   144  						{Image: "second:tag@sha256:d3f4dd1541ee34b96850efc46955bada1a415b0594dc9948607c0197d2d16749"},
   145  					},
   146  				},
   147  			},
   148  			expectedColor: output.DefaultColorCodes[1],
   149  		},
   150  	}
   151  
   152  	// artifacts are registered using their tag, since these have default repo substitutions applied
   153  	p := output.NewColorPicker()
   154  	p.AddImage("image")
   155  	p.AddImage("second")
   156  
   157  	for _, test := range tests {
   158  		f := newKubernetesLogFormatter(&mockConfig{log: latest.LogsConfig{Prefix: "none"}}, p, func() bool { return false }, test.pod, v1.ContainerStatus{})
   159  
   160  		testutil.Run(t, test.description, func(t *testutil.T) {
   161  			color := f.color()
   162  
   163  			t.CheckTrue(test.expectedColor == color)
   164  		})
   165  	}
   166  }
   167  
   168  func TestPrefix(t *testing.T) {
   169  	tests := []struct {
   170  		description    string
   171  		prefix         string
   172  		pod            v1.Pod
   173  		container      v1.ContainerStatus
   174  		expectedPrefix string
   175  	}{
   176  		{
   177  			description:    "auto (different names)",
   178  			prefix:         "auto",
   179  			pod:            podWithName("pod"),
   180  			container:      containerWithName("container"),
   181  			expectedPrefix: "[pod container]",
   182  		},
   183  		{
   184  			description:    "auto (same names)",
   185  			prefix:         "auto",
   186  			pod:            podWithName("hello"),
   187  			container:      containerWithName("hello"),
   188  			expectedPrefix: "[hello]",
   189  		},
   190  		{
   191  			description:    "container",
   192  			prefix:         "container",
   193  			pod:            podWithName("pod"),
   194  			container:      containerWithName("container"),
   195  			expectedPrefix: "[container]",
   196  		},
   197  		{
   198  			description:    "podAndContainer (different names)",
   199  			prefix:         "podAndContainer",
   200  			pod:            podWithName("pod"),
   201  			container:      containerWithName("container"),
   202  			expectedPrefix: "[pod container]",
   203  		},
   204  		{
   205  			description:    "podAndContainer (same names)",
   206  			prefix:         "podAndContainer",
   207  			pod:            podWithName("hello"),
   208  			container:      containerWithName("hello"),
   209  			expectedPrefix: "[hello hello]",
   210  		},
   211  		{
   212  			description:    "none",
   213  			prefix:         "none",
   214  			pod:            podWithName("hello"),
   215  			container:      containerWithName("hello"),
   216  			expectedPrefix: "",
   217  		},
   218  	}
   219  	for _, test := range tests {
   220  		testutil.Run(t, test.description, func(t *testutil.T) {
   221  			f := newKubernetesLogFormatter(&mockConfig{log: latest.LogsConfig{
   222  				Prefix: test.prefix,
   223  			}}, &mockColorPicker{}, func() bool { return false }, &test.pod, test.container)
   224  
   225  			t.CheckDeepEqual(test.expectedPrefix, f.prefix)
   226  		})
   227  	}
   228  }
   229  
   230  func TestPrintline(t *testing.T) {
   231  	tests := []struct {
   232  		description string
   233  		isMuted     bool
   234  		expected    string
   235  	}{
   236  		{
   237  			description: "muted",
   238  			isMuted:     true,
   239  		},
   240  		{
   241  			description: "unmuted",
   242  			expected:    "[hello container]test line",
   243  		},
   244  	}
   245  	for _, test := range tests {
   246  		testutil.Run(t, test.description, func(t *testutil.T) {
   247  			pod := podWithName("hello")
   248  			f := newKubernetesLogFormatter(&mockConfig{log: latest.LogsConfig{
   249  				Prefix: "auto",
   250  			}}, &mockColorPicker{}, func() bool { return test.isMuted }, &pod,
   251  				containerWithName("container"))
   252  			var out bytes.Buffer
   253  			f.PrintLine(&out, "test line")
   254  			t.CheckDeepEqual(test.expected, out.String())
   255  		})
   256  	}
   257  }