sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/commentpruner/commentpruner_test.go (about)

     1  /*
     2  Copyright 2017 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 commentpruner
    18  
    19  import (
    20  	"reflect"
    21  	"sort"
    22  	"testing"
    23  
    24  	"github.com/sirupsen/logrus"
    25  
    26  	"sigs.k8s.io/prow/pkg/github"
    27  )
    28  
    29  type fakeGHClient struct {
    30  	comments        []github.IssueComment
    31  	deletedComments []int
    32  	listCallCount   int
    33  }
    34  
    35  func (*fakeGHClient) BotUserChecker() (func(candidate string) bool, error) {
    36  	return func(candidate string) bool {
    37  		return candidate == "k8s-ci-robot"
    38  	}, nil
    39  }
    40  
    41  func (f *fakeGHClient) ListIssueComments(_, _ string, _ int) ([]github.IssueComment, error) {
    42  	f.listCallCount++
    43  	return f.comments, nil
    44  }
    45  
    46  func (f *fakeGHClient) DeleteComment(_, _ string, ID int) error {
    47  	f.deletedComments = append(f.deletedComments, ID)
    48  	return nil
    49  }
    50  
    51  func newFakeGHClient(commentsToLogins map[int]string) *fakeGHClient {
    52  	comments := make([]github.IssueComment, 0, len(commentsToLogins))
    53  	for num, login := range commentsToLogins {
    54  		comments = append(comments, github.IssueComment{ID: num, User: github.User{Login: login}})
    55  	}
    56  	return &fakeGHClient{
    57  		comments:        comments,
    58  		deletedComments: []int{},
    59  	}
    60  }
    61  
    62  func testPruneFunc(errorComments *[]int, toPrunes, toErrs []int) func(github.IssueComment) bool {
    63  	return func(ic github.IssueComment) bool {
    64  		for _, toErr := range toErrs {
    65  			if ic.ID == toErr {
    66  				*errorComments = append(*errorComments, ic.ID)
    67  				break
    68  			}
    69  		}
    70  		for _, toPrune := range toPrunes {
    71  			if ic.ID == toPrune {
    72  				return true
    73  			}
    74  		}
    75  		return false
    76  	}
    77  }
    78  
    79  func TestPruneComments(t *testing.T) {
    80  	botLogin := "k8s-ci-robot"
    81  	humanLogin := "cjwagner"
    82  
    83  	var errs *[]int
    84  	tcs := []struct {
    85  		name            string
    86  		comments        map[int]string
    87  		callers         []func(github.IssueComment) bool
    88  		expectedDeleted []int
    89  	}{
    90  		{
    91  			name:            "One caller, multiple deletions.",
    92  			comments:        map[int]string{1: botLogin, 2: botLogin, 3: botLogin},
    93  			callers:         []func(github.IssueComment) bool{testPruneFunc(errs, []int{1, 2}, nil)},
    94  			expectedDeleted: []int{1, 2},
    95  		},
    96  		{
    97  			name:            "One caller, no deletions.",
    98  			comments:        map[int]string{3: botLogin},
    99  			callers:         []func(github.IssueComment) bool{testPruneFunc(errs, []int{1, 2}, nil)},
   100  			expectedDeleted: []int{},
   101  		},
   102  		{
   103  			name:     "Two callers.",
   104  			comments: map[int]string{1: botLogin, 2: botLogin, 3: botLogin, 4: botLogin, 5: botLogin},
   105  			callers: []func(github.IssueComment) bool{
   106  				testPruneFunc(errs, []int{1, 2}, nil),
   107  				testPruneFunc(errs, []int{4}, []int{1, 2}),
   108  			},
   109  			expectedDeleted: []int{1, 2, 4},
   110  		},
   111  		{
   112  			name:     "Three callers. Some Human messages",
   113  			comments: map[int]string{1: humanLogin, 2: botLogin, 3: botLogin, 4: botLogin, 5: botLogin, 6: humanLogin, 7: botLogin},
   114  			callers: []func(github.IssueComment) bool{
   115  				testPruneFunc(errs, []int{2, 3}, []int{1, 6}),
   116  				testPruneFunc(errs, []int{5}, []int{1, 2, 3, 6}),
   117  				testPruneFunc(errs, []int{4}, []int{1, 2, 3, 5, 6}),
   118  			},
   119  			expectedDeleted: []int{2, 3, 4, 5},
   120  		},
   121  	}
   122  
   123  	/*
   124  		Ensure the following:
   125  		When multiple callers ask for comment deletion from the same client...
   126  		- They should not see comments deleted by previous caller.
   127  		- Comments should be listed only once.
   128  		- All comments that are stale should be deleted.
   129  	*/
   130  	for _, tc := range tcs {
   131  		errs = &[]int{}
   132  		fgc := newFakeGHClient(tc.comments)
   133  		client := NewEventClient(fgc, logrus.WithField("client", "commentpruner"), "org", "repo", 1)
   134  		for _, call := range tc.callers {
   135  			client.PruneComments(call)
   136  		}
   137  
   138  		if fgc.listCallCount != 1 {
   139  			t.Errorf("[%s]: Expected comments to be fetched exactly once, instead got %d.", tc.name, fgc.listCallCount)
   140  		}
   141  		if len(*errs) > 0 {
   142  			t.Errorf("[%s]: The following comments should not have been seen be subsequent callers: %v.", tc.name, *errs)
   143  		}
   144  		sort.Ints(tc.expectedDeleted)
   145  		sort.Ints(fgc.deletedComments)
   146  		if !reflect.DeepEqual(tc.expectedDeleted, fgc.deletedComments) {
   147  			t.Errorf("[%s]: Expected the comments %#v to be deleted, but %#v were deleted instead.", tc.name, tc.expectedDeleted, fgc.deletedComments)
   148  		}
   149  	}
   150  }