github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/spyglass/podlogartifact_test.go (about)

     1  /*
     2  Copyright 2018 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 spyglass
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"testing"
    24  
    25  	"k8s.io/test-infra/prow/kube"
    26  	"k8s.io/test-infra/prow/spyglass/lenses"
    27  )
    28  
    29  // fakePodLogJAgent used for pod log artifact dependency injection
    30  type fakePodLogJAgent struct {
    31  }
    32  
    33  func (j *fakePodLogJAgent) GetProwJob(job, id string) (kube.ProwJob, error) {
    34  	return kube.ProwJob{}, nil
    35  }
    36  
    37  func (j *fakePodLogJAgent) GetJobLog(job, id string) ([]byte, error) {
    38  	if job == "BFG" && id == "435" {
    39  		return []byte("frobscottle"), nil
    40  	} else if job == "Fantastic Mr. Fox" && id == "4" {
    41  		return []byte("a hundred smoked hams and fifty sides of bacon"), nil
    42  	}
    43  	return nil, fmt.Errorf("could not find job %s, id %s", job, id)
    44  }
    45  
    46  func (j *fakePodLogJAgent) GetJobLogTail(job, id string, n int64) ([]byte, error) {
    47  	log, err := j.GetJobLog(job, id)
    48  	if err != nil {
    49  		return nil, fmt.Errorf("error getting log tail: %v", err)
    50  	}
    51  	logLen := int64(len(log))
    52  	if n > logLen {
    53  		return log, nil
    54  	}
    55  	return log[logLen-n:], nil
    56  
    57  }
    58  
    59  func TestNewPodLogArtifact(t *testing.T) {
    60  	testCases := []struct {
    61  		name         string
    62  		jobName      string
    63  		buildID      string
    64  		sizeLimit    int64
    65  		expectedErr  error
    66  		expectedLink string
    67  	}{
    68  		{
    69  			name:         "Create pod log with valid fields",
    70  			jobName:      "job",
    71  			buildID:      "123",
    72  			sizeLimit:    500e6,
    73  			expectedErr:  nil,
    74  			expectedLink: "/log?id=123&job=job",
    75  		},
    76  		{
    77  			name:         "Create pod log with no jobName",
    78  			jobName:      "",
    79  			buildID:      "123",
    80  			sizeLimit:    500e6,
    81  			expectedErr:  errInsufficientJobInfo,
    82  			expectedLink: "",
    83  		},
    84  		{
    85  			name:         "Create pod log with no buildID",
    86  			jobName:      "job",
    87  			buildID:      "",
    88  			sizeLimit:    500e6,
    89  			expectedErr:  errInsufficientJobInfo,
    90  			expectedLink: "",
    91  		},
    92  		{
    93  			name:         "Create pod log with negative sizeLimit",
    94  			jobName:      "job",
    95  			buildID:      "123",
    96  			sizeLimit:    -4,
    97  			expectedErr:  errInvalidSizeLimit,
    98  			expectedLink: "",
    99  		},
   100  	}
   101  	for _, tc := range testCases {
   102  		t.Run(tc.name, func(t *testing.T) {
   103  			artifact, err := NewPodLogArtifact(tc.jobName, tc.buildID, tc.sizeLimit, &fakePodLogJAgent{})
   104  			if err != nil {
   105  				if err != tc.expectedErr {
   106  					t.Fatalf("failed creating artifact. err: %v", err)
   107  				}
   108  				return
   109  			}
   110  			link := artifact.CanonicalLink()
   111  			if link != tc.expectedLink {
   112  				t.Errorf("Unexpected link, expected %s, got %q", tc.expectedLink, link)
   113  			}
   114  		})
   115  	}
   116  }
   117  
   118  func TestReadTail_PodLog(t *testing.T) {
   119  	testCases := []struct {
   120  		name      string
   121  		jobName   string
   122  		buildID   string
   123  		artifact  *PodLogArtifact
   124  		n         int64
   125  		expected  []byte
   126  		expectErr bool
   127  	}{
   128  		{
   129  			name:     "Podlog ReadTail longer than contents",
   130  			jobName:  "BFG",
   131  			buildID:  "435",
   132  			n:        50,
   133  			expected: []byte("frobscottle"),
   134  		},
   135  		{
   136  			name:     "Podlog ReadTail shorter than contents",
   137  			jobName:  "Fantastic Mr. Fox",
   138  			buildID:  "4",
   139  			n:        3,
   140  			expected: []byte("con"),
   141  		},
   142  		{
   143  			name:      "Podlog ReadTail nonexistent pod",
   144  			jobName:   "Fax",
   145  			buildID:   "4",
   146  			n:         3,
   147  			expectErr: true,
   148  		},
   149  	}
   150  	for _, tc := range testCases {
   151  		t.Run(tc.name, func(t *testing.T) {
   152  			artifact, err := NewPodLogArtifact(tc.jobName, tc.buildID, 500e6, &fakePodLogJAgent{})
   153  			if err != nil {
   154  				t.Fatalf("Pod Log Tests failed to create pod log artifact, err %v", err)
   155  			}
   156  			res, err := artifact.ReadTail(tc.n)
   157  			if err != nil && !tc.expectErr {
   158  				t.Fatalf("failed reading bytes of log. did not expect err, got err: %v", err)
   159  			}
   160  			if err == nil && tc.expectErr {
   161  				t.Errorf("expected an error, got none")
   162  			}
   163  			if !bytes.Equal(tc.expected, res) {
   164  				t.Errorf("Unexpected result of reading pod logs, expected %q, got %q", tc.expected, res)
   165  			}
   166  		})
   167  	}
   168  
   169  }
   170  func TestReadAt_PodLog(t *testing.T) {
   171  	testCases := []struct {
   172  		name        string
   173  		jobName     string
   174  		buildID     string
   175  		n           int64
   176  		offset      int64
   177  		expectedErr error
   178  		expected    []byte
   179  	}{
   180  		{
   181  			name:        "Podlog ReadAt range longer than contents",
   182  			n:           100,
   183  			jobName:     "BFG",
   184  			buildID:     "435",
   185  			offset:      3,
   186  			expectedErr: io.EOF,
   187  			expected:    []byte("bscottle"),
   188  		},
   189  		{
   190  			name:        "Podlog ReadAt range within contents",
   191  			n:           4,
   192  			jobName:     "Fantastic Mr. Fox",
   193  			buildID:     "4",
   194  			offset:      2,
   195  			expectedErr: nil,
   196  			expected:    []byte("hund"),
   197  		},
   198  	}
   199  	for _, tc := range testCases {
   200  		t.Run(tc.name, func(t *testing.T) {
   201  			artifact, err := NewPodLogArtifact(tc.jobName, tc.buildID, 500e6, &fakePodLogJAgent{})
   202  			if err != nil {
   203  				t.Fatalf("Pod Log Tests failed to create pod log artifact, err %v", err)
   204  			}
   205  			res := make([]byte, tc.n)
   206  			readBytes, err := artifact.ReadAt(res, tc.offset)
   207  			if err != tc.expectedErr {
   208  				t.Fatalf("failed reading bytes of log. err: %v, expected err: %v", err, tc.expectedErr)
   209  			}
   210  			if !bytes.Equal(tc.expected, res[:readBytes]) {
   211  				t.Errorf("Unexpected result of reading pod logs, expected %q, got %q", tc.expected, res)
   212  			}
   213  		})
   214  	}
   215  
   216  }
   217  func TestReadAtMost_PodLog(t *testing.T) {
   218  	testCases := []struct {
   219  		name        string
   220  		n           int64
   221  		jobName     string
   222  		buildID     string
   223  		expectedErr error
   224  		expected    []byte
   225  	}{
   226  		{
   227  			name:        "Podlog ReadAtMost longer than contents",
   228  			jobName:     "BFG",
   229  			buildID:     "435",
   230  			n:           100,
   231  			expectedErr: io.EOF,
   232  			expected:    []byte("frobscottle"),
   233  		},
   234  		{
   235  			name:        "Podlog ReadAtMost shorter than contents",
   236  			n:           3,
   237  			jobName:     "BFG",
   238  			buildID:     "435",
   239  			expectedErr: nil,
   240  			expected:    []byte("fro"),
   241  		},
   242  	}
   243  	for _, tc := range testCases {
   244  		t.Run(tc.name, func(t *testing.T) {
   245  			artifact, err := NewPodLogArtifact(tc.jobName, tc.buildID, 500e6, &fakePodLogJAgent{})
   246  			if err != nil {
   247  				t.Fatalf("Pod Log Tests failed to create pod log artifact, err %v", err)
   248  			}
   249  			res, err := artifact.ReadAtMost(tc.n)
   250  			if err != tc.expectedErr {
   251  				t.Fatalf("failed reading bytes of log. err: %v, expected err: %v", err, tc.expectedErr)
   252  			}
   253  			if !bytes.Equal(tc.expected, res) {
   254  				t.Errorf("Unexpected result of reading pod logs, expected %q, got %q", tc.expected, res)
   255  			}
   256  		})
   257  	}
   258  
   259  }
   260  
   261  func TestReadAll_PodLog(t *testing.T) {
   262  	fakePodLogAgent := &fakePodLogJAgent{}
   263  	testCases := []struct {
   264  		name        string
   265  		jobName     string
   266  		buildID     string
   267  		sizeLimit   int64
   268  		expectedErr error
   269  		expected    []byte
   270  	}{
   271  		{
   272  			name:        "Podlog readall not found",
   273  			jobName:     "job",
   274  			buildID:     "123",
   275  			sizeLimit:   500e6,
   276  			expectedErr: fmt.Errorf("error getting pod log size: error getting size of pod log: could not find job job, id 123"),
   277  			expected:    nil,
   278  		},
   279  		{
   280  			name:        "Simple \"BFG\" Podlog readall",
   281  			jobName:     "BFG",
   282  			buildID:     "435",
   283  			sizeLimit:   500e6,
   284  			expectedErr: nil,
   285  			expected:    []byte("frobscottle"),
   286  		},
   287  		{
   288  			name:        "\"Fantastic Mr. Fox\" Podlog readall",
   289  			jobName:     "Fantastic Mr. Fox",
   290  			buildID:     "4",
   291  			sizeLimit:   500e6,
   292  			expectedErr: nil,
   293  			expected:    []byte("a hundred smoked hams and fifty sides of bacon"),
   294  		},
   295  		{
   296  			name:        "Podlog readall over size limit",
   297  			jobName:     "Fantastic Mr. Fox",
   298  			buildID:     "4",
   299  			sizeLimit:   5,
   300  			expectedErr: lenses.ErrFileTooLarge,
   301  			expected:    nil,
   302  		},
   303  	}
   304  	for _, tc := range testCases {
   305  		artifact, err := NewPodLogArtifact(tc.jobName, tc.buildID, tc.sizeLimit, fakePodLogAgent)
   306  		if err != nil {
   307  			t.Fatalf("Pod Log Tests failed to create pod log artifact, err %v", err)
   308  		}
   309  		res, err := artifact.ReadAll()
   310  		if err != nil && err.Error() != tc.expectedErr.Error() {
   311  			t.Fatalf("%s failed reading bytes of log. got err: %v, expected err: %v", tc.name, err, tc.expectedErr)
   312  		}
   313  		if err != nil {
   314  			continue
   315  		}
   316  		if !bytes.Equal(tc.expected, res) {
   317  			t.Errorf("Unexpected result of reading pod logs, expected %q, got %q", tc.expected, res)
   318  		}
   319  
   320  	}
   321  
   322  }