github.com/abayer/test-infra@v0.0.5/prow/plugins/dog/dog_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 dog
    18  
    19  import (
    20  	"encoding/json"
    21  	"flag"
    22  	"fmt"
    23  	"io"
    24  	"net/http"
    25  	"net/http/httptest"
    26  	"regexp"
    27  	"strings"
    28  	"testing"
    29  
    30  	"github.com/sirupsen/logrus"
    31  
    32  	"k8s.io/test-infra/prow/github"
    33  	"k8s.io/test-infra/prow/github/fakegithub"
    34  )
    35  
    36  type fakePack string
    37  
    38  var human = flag.Bool("human", false, "Enable to run additional manual tests")
    39  
    40  func (c fakePack) readDog() (string, error) {
    41  	return string(c), nil
    42  }
    43  
    44  func TestRealDog(t *testing.T) {
    45  	if !*human {
    46  		t.Skip("Real dogs disabled for automation. Manual users can add --human [--category=foo]")
    47  	}
    48  	if dog, err := dogURL.readDog(); err != nil {
    49  		t.Errorf("Could not read dog from %s: %v", dogURL, err)
    50  	} else {
    51  		fmt.Println(dog)
    52  	}
    53  }
    54  
    55  func TestFormat(t *testing.T) {
    56  	re := regexp.MustCompile(`\[!\[.+\]\(.+\)\]\(.+\)`)
    57  	basicURL := "http://example.com"
    58  	testcases := []struct {
    59  		name string
    60  		url  string
    61  		err  bool
    62  	}{
    63  		{
    64  			name: "basically works",
    65  			url:  basicURL,
    66  			err:  false,
    67  		},
    68  		{
    69  			name: "empty url",
    70  			url:  "",
    71  			err:  true,
    72  		},
    73  		{
    74  			name: "bad url",
    75  			url:  "http://this is not a url",
    76  			err:  true,
    77  		},
    78  	}
    79  	for _, tc := range testcases {
    80  		ret, err := dogResult{
    81  			URL: tc.url,
    82  		}.Format()
    83  		switch {
    84  		case tc.err:
    85  			if err == nil {
    86  				t.Errorf("%s: failed to raise an error", tc.name)
    87  			}
    88  		case err != nil:
    89  			t.Errorf("%s: unexpected error: %v", tc.name, err)
    90  		case !re.MatchString(ret):
    91  			t.Errorf("%s: bad return value: %s", tc.name, ret)
    92  		}
    93  	}
    94  }
    95  
    96  // Medium integration test (depends on ability to open a TCP port)
    97  func TestHttpResponse(t *testing.T) {
    98  	// create test cases for handling content length of images
    99  	contentLength := make(map[string]string)
   100  	contentLength["/dog.jpg"] = "717987"
   101  	contentLength["/doggo.mp4"] = "37943259"
   102  	contentLength["/bigdog.jpg"] = "12647753"
   103  
   104  	// fake server for images
   105  	ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   106  		if s, ok := contentLength[r.URL.Path]; ok {
   107  			body := "binary image"
   108  			w.Header().Set("Content-Length", s)
   109  			io.WriteString(w, body)
   110  		} else {
   111  			t.Errorf("Cannot find content length for %s", r.URL.Path)
   112  		}
   113  	}))
   114  	defer ts2.Close()
   115  
   116  	// setup a stock valid request
   117  	url := ts2.URL + "/dog.jpg"
   118  	b, err := json.Marshal(&dogResult{
   119  		URL: url,
   120  	})
   121  	if err != nil {
   122  		t.Errorf("Failed to encode test data: %v", err)
   123  	}
   124  
   125  	// create test cases for handling http responses
   126  	validResponse := string(b)
   127  	var testcases = []struct {
   128  		name     string
   129  		path     string
   130  		response string
   131  		isValid  bool
   132  	}{
   133  		{
   134  			name:     "valid",
   135  			path:     "/valid",
   136  			response: validResponse,
   137  			isValid:  true,
   138  		},
   139  		{
   140  			name:     "invalid JSON",
   141  			path:     "/bad-json",
   142  			response: `{"bad-blob": "not-a-url"`,
   143  			isValid:  false,
   144  		},
   145  		{
   146  			name:     "invalid URL",
   147  			path:     "/bad-url",
   148  			response: `{"url": "not a url.."}`,
   149  			isValid:  false,
   150  		},
   151  		{
   152  			name:     "mp4 doggo unsupported :(",
   153  			path:     "/mp4-doggo",
   154  			response: fmt.Sprintf(`{"url": "%s/doggo.mp4"}`, ts2.URL),
   155  			isValid:  false,
   156  		},
   157  		{
   158  			name:     "image too big",
   159  			path:     "/too-big",
   160  			response: fmt.Sprintf(`{"url": "%s/bigdog.jpg"}`, ts2.URL),
   161  			isValid:  false,
   162  		},
   163  	}
   164  
   165  	// fake server for image urls
   166  	pathToResponse := make(map[string]string)
   167  	for _, testcase := range testcases {
   168  		pathToResponse[testcase.path] = testcase.response
   169  	}
   170  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   171  		if r, ok := pathToResponse[r.URL.Path]; ok {
   172  			io.WriteString(w, r)
   173  		} else {
   174  			io.WriteString(w, validResponse)
   175  		}
   176  	}))
   177  	defer ts.Close()
   178  
   179  	// github fake client
   180  	fc := &fakegithub.FakeClient{
   181  		IssueComments: make(map[int][]github.IssueComment),
   182  	}
   183  
   184  	// run test for each case
   185  	for _, testcase := range testcases {
   186  		dog, err := realPack(ts.URL + testcase.path).readDog()
   187  		if testcase.isValid && err != nil {
   188  			t.Errorf("For case %s, didn't expect error: %v", testcase.name, err)
   189  		} else if !testcase.isValid && err == nil {
   190  			t.Errorf("For case %s, expected error, received dog: %s", testcase.name, dog)
   191  		}
   192  	}
   193  
   194  	// fully test handling a comment
   195  	comment := "/woof"
   196  	e := &github.GenericCommentEvent{
   197  		Action:     github.GenericCommentActionCreated,
   198  		Body:       comment,
   199  		Number:     5,
   200  		IssueState: "open",
   201  	}
   202  	err = handle(fc, logrus.WithField("plugin", pluginName), e, realPack(ts.URL))
   203  	if err != nil {
   204  		t.Errorf("For comment /woof, didn't expect error: %v", err)
   205  	}
   206  
   207  	if len(fc.IssueComments[5]) != 1 {
   208  		t.Error("should have commented.")
   209  	}
   210  	if c := fc.IssueComments[5][0]; !strings.Contains(c.Body, url) {
   211  		t.Errorf("missing image url: %s from comment: %v", url, c)
   212  	}
   213  }
   214  
   215  // Small, unit tests
   216  func TestDogs(t *testing.T) {
   217  	var testcases = []struct {
   218  		name          string
   219  		action        github.GenericCommentEventAction
   220  		body          string
   221  		state         string
   222  		pr            bool
   223  		shouldComment bool
   224  	}{
   225  		{
   226  			name:          "ignore edited comment",
   227  			state:         "open",
   228  			action:        github.GenericCommentActionEdited,
   229  			body:          "/woof",
   230  			shouldComment: false,
   231  		},
   232  		{
   233  			name:          "leave dog on pr",
   234  			state:         "open",
   235  			action:        github.GenericCommentActionCreated,
   236  			body:          "/woof",
   237  			pr:            true,
   238  			shouldComment: true,
   239  		},
   240  		{
   241  			name:          "leave dog on issue",
   242  			state:         "open",
   243  			action:        github.GenericCommentActionCreated,
   244  			body:          "/woof",
   245  			shouldComment: true,
   246  		},
   247  		{
   248  			name:          "leave dog on issue, trailing space",
   249  			state:         "open",
   250  			action:        github.GenericCommentActionCreated,
   251  			body:          "/woof \r",
   252  			shouldComment: true,
   253  		},
   254  		{
   255  			name:          "leave dog on issue, trailing /bark",
   256  			state:         "open",
   257  			action:        github.GenericCommentActionCreated,
   258  			body:          "/bark",
   259  			shouldComment: true,
   260  		},
   261  		{
   262  			name:          "leave dog on issue, trailing /bark, trailing space",
   263  			state:         "open",
   264  			action:        github.GenericCommentActionCreated,
   265  			body:          "/bark \r",
   266  			shouldComment: true,
   267  		},
   268  	}
   269  	for _, tc := range testcases {
   270  		fc := &fakegithub.FakeClient{
   271  			IssueComments: make(map[int][]github.IssueComment),
   272  		}
   273  		e := &github.GenericCommentEvent{
   274  			Action:     tc.action,
   275  			Body:       tc.body,
   276  			Number:     5,
   277  			IssueState: tc.state,
   278  			IsPR:       tc.pr,
   279  		}
   280  		err := handle(fc, logrus.WithField("plugin", pluginName), e, fakePack("doge"))
   281  		if err != nil {
   282  			t.Errorf("For case %s, didn't expect error: %v", tc.name, err)
   283  		}
   284  		if tc.shouldComment && len(fc.IssueComments[5]) != 1 {
   285  			t.Errorf("For case %s, should have commented.", tc.name)
   286  		} else if !tc.shouldComment && len(fc.IssueComments[5]) != 0 {
   287  			t.Errorf("For case %s, should not have commented.", tc.name)
   288  		}
   289  	}
   290  }