github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/maintenance/migratestatus/migrator/migrator_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 migrator
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/google/go-github/github"
    24  )
    25  
    26  type modeTest struct {
    27  	name          string
    28  	start         []github.RepoStatus
    29  	expectedDiffs []*github.RepoStatus
    30  }
    31  
    32  // compareDiffs checks if a list of status updates matches an expected list of status updates.
    33  func compareDiffs(diffs []*github.RepoStatus, expectedDiffs []*github.RepoStatus) error {
    34  	if len(diffs) != len(expectedDiffs) {
    35  		return fmt.Errorf("failed because the returned diff had %d changes instead of %d.", len(diffs), len(expectedDiffs))
    36  	}
    37  	for _, diff := range diffs {
    38  		if diff == nil {
    39  			return fmt.Errorf("failed because the returned diff contained a nil RepoStatus.")
    40  		}
    41  		if diff.Context == nil {
    42  			return fmt.Errorf("failed because the returned diff contained a RepoStatus with a nil Context field.")
    43  		}
    44  		if diff.Description == nil {
    45  			return fmt.Errorf("failed because the returned diff contained a RepoStatus with a nil Description field.")
    46  		}
    47  		if diff.State == nil {
    48  			return fmt.Errorf("failed because the returned diff contained a RepoStatus with a nil State field.")
    49  		}
    50  		var match *github.RepoStatus
    51  		for _, expected := range expectedDiffs {
    52  			if *expected.Context == *diff.Context {
    53  				match = expected
    54  				break
    55  			}
    56  		}
    57  		if match == nil {
    58  			return fmt.Errorf("failed because the returned diff contained an unexpected change to context '%s'.", *diff.Context)
    59  		}
    60  		// Found a matching context. Make sure that fields are equal.
    61  		if *match.Description != *diff.Description {
    62  			return fmt.Errorf("failed because the returned diff for context '%s' had Description '%s' instead of '%s'.", *diff.Context, *diff.Description, *match.Description)
    63  		}
    64  		if *match.State != *diff.State {
    65  			return fmt.Errorf("failed because the returned diff for context '%s' had State '%s' instead of '%s'.", *diff.Context, *diff.State, *match.State)
    66  		}
    67  
    68  		if match.TargetURL == nil {
    69  			if diff.TargetURL != nil {
    70  				return fmt.Errorf("failed because the returned diff for context '%s' had a non-nil TargetURL.", *diff.Context)
    71  			}
    72  		} else if diff.TargetURL == nil {
    73  			return fmt.Errorf("failed because the returned diff for context '%s' had a nil TargetURL.", *diff.Context)
    74  		} else if *match.TargetURL != *diff.TargetURL {
    75  			return fmt.Errorf("failed because the returned diff for context '%s' had TargetURL '%s' instead of '%s'.", *diff.Context, *diff.TargetURL, *match.TargetURL)
    76  		}
    77  	}
    78  	return nil
    79  }
    80  
    81  func TestMoveMode(t *testing.T) {
    82  	contextA := "context A"
    83  	contextB := "context B"
    84  	desc := "Context retired. Status moved to \"context B\"."
    85  
    86  	tests := []*modeTest{
    87  		{
    88  			name: "simple",
    89  			start: []github.RepoStatus{
    90  				*makeStatus(contextA, "failure", "description 1", "url 1"),
    91  			},
    92  			expectedDiffs: []*github.RepoStatus{
    93  				makeStatus(contextA, "success", desc, ""),
    94  				makeStatus(contextB, "failure", "description 1", "url 1"),
    95  			},
    96  		},
    97  		{
    98  			name: "unrelated contexts",
    99  			start: []github.RepoStatus{
   100  				*makeStatus("also not related", "error", "description 4", "url 4"),
   101  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   102  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   103  			},
   104  			expectedDiffs: []*github.RepoStatus{
   105  				makeStatus(contextA, "success", desc, ""),
   106  				makeStatus(contextB, "failure", "description 1", "url 1"),
   107  			},
   108  		},
   109  		{
   110  			name: "unrelated contexts; missing context A",
   111  			start: []github.RepoStatus{
   112  				*makeStatus("also not related", "error", "description 4", "url 4"),
   113  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   114  			},
   115  			expectedDiffs: []*github.RepoStatus{},
   116  		},
   117  		{
   118  			name: "unrelated contexts; already have context A and B",
   119  			start: []github.RepoStatus{
   120  				*makeStatus("also not related", "error", "description 4", "url 4"),
   121  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   122  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   123  				*makeStatus(contextB, "failure", "description 1", "url 1"),
   124  			},
   125  			expectedDiffs: []*github.RepoStatus{},
   126  		},
   127  		{
   128  			name: "unrelated contexts; already have context B; no context A",
   129  			start: []github.RepoStatus{
   130  				*makeStatus("also not related", "error", "description 4", "url 4"),
   131  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   132  				*makeStatus(contextB, "failure", "description 1", "url 1"),
   133  			},
   134  			expectedDiffs: []*github.RepoStatus{},
   135  		},
   136  		{
   137  			name:          "no contexts",
   138  			start:         []github.RepoStatus{},
   139  			expectedDiffs: []*github.RepoStatus{},
   140  		},
   141  	}
   142  
   143  	m := *MoveMode(contextA, contextB)
   144  	for _, test := range tests {
   145  		diff := m.ProcessStatuses(&github.CombinedStatus{Statuses: test.start})
   146  		if err := compareDiffs(diff, test.expectedDiffs); err != nil {
   147  			t.Errorf("MoveMode test '%s' %v\n", test.name, err)
   148  		}
   149  	}
   150  }
   151  
   152  func TestCopyMode(t *testing.T) {
   153  	contextA := "context A"
   154  	contextB := "context B"
   155  
   156  	tests := []*modeTest{
   157  		{
   158  			name: "simple",
   159  			start: []github.RepoStatus{
   160  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   161  			},
   162  			expectedDiffs: []*github.RepoStatus{
   163  				makeStatus(contextB, "failure", "description 1", "url 1"),
   164  			},
   165  		},
   166  		{
   167  			name: "unrelated contexts",
   168  			start: []github.RepoStatus{
   169  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   170  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   171  				*makeStatus("also not related", "error", "description 4", "url 4"),
   172  			},
   173  			expectedDiffs: []*github.RepoStatus{
   174  				makeStatus(contextB, "failure", "description 1", "url 1"),
   175  			},
   176  		},
   177  		{
   178  			name: "already have context B",
   179  			start: []github.RepoStatus{
   180  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   181  				*makeStatus(contextB, "failure", "description 1", "url 1"),
   182  			},
   183  			expectedDiffs: []*github.RepoStatus{},
   184  		},
   185  		{
   186  			name: "already have updated context B",
   187  			start: []github.RepoStatus{
   188  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   189  				*makeStatus(contextB, "success", "description 2", "url 2"),
   190  			},
   191  			expectedDiffs: []*github.RepoStatus{},
   192  		},
   193  		{
   194  			name: "unrelated contexts already have updated context B",
   195  			start: []github.RepoStatus{
   196  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   197  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   198  				*makeStatus("also not related", "error", "description 4", "url 4"),
   199  				*makeStatus(contextB, "error", "description 3", "url 3"),
   200  			},
   201  			expectedDiffs: []*github.RepoStatus{},
   202  		},
   203  		{
   204  			name: "only have context B",
   205  			start: []github.RepoStatus{
   206  				*makeStatus(contextB, "failure", "description 1", "url 1"),
   207  			},
   208  			expectedDiffs: []*github.RepoStatus{},
   209  		},
   210  		{
   211  			name: "unrelated contexts; context B but not A",
   212  			start: []github.RepoStatus{
   213  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   214  				*makeStatus(contextB, "failure", "description 1", "url 1"),
   215  				*makeStatus("also not related", "error", "description 4", "url 4"),
   216  			},
   217  			expectedDiffs: []*github.RepoStatus{},
   218  		},
   219  		{
   220  			name:          "no contexts",
   221  			start:         []github.RepoStatus{},
   222  			expectedDiffs: []*github.RepoStatus{},
   223  		},
   224  	}
   225  
   226  	m := *CopyMode(contextA, contextB)
   227  	for _, test := range tests {
   228  		diff := m.ProcessStatuses(&github.CombinedStatus{Statuses: test.start})
   229  		if err := compareDiffs(diff, test.expectedDiffs); err != nil {
   230  			t.Errorf("CopyMode test '%s' %v\n", test.name, err)
   231  		}
   232  	}
   233  }
   234  
   235  func TestRetireModeReplacement(t *testing.T) {
   236  	contextA := "context A"
   237  	contextB := "context B"
   238  	desc := "Context retired. Status moved to \"context B\"."
   239  
   240  	tests := []*modeTest{
   241  		{
   242  			name: "simple",
   243  			start: []github.RepoStatus{
   244  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   245  				*makeStatus(contextB, "failure", "description 1", "url 1"),
   246  			},
   247  			expectedDiffs: []*github.RepoStatus{
   248  				makeStatus(contextA, "success", desc, ""),
   249  			},
   250  		},
   251  		{
   252  			name: "unrelated contexts;updated context B",
   253  			start: []github.RepoStatus{
   254  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   255  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   256  				*makeStatus("also not related", "error", "description 4", "url 4"),
   257  				*makeStatus(contextB, "success", "description 3", "url 3"),
   258  			},
   259  			expectedDiffs: []*github.RepoStatus{
   260  				makeStatus(contextA, "success", desc, ""),
   261  			},
   262  		},
   263  		{
   264  			name: "missing context B",
   265  			start: []github.RepoStatus{
   266  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   267  			},
   268  			expectedDiffs: []*github.RepoStatus{},
   269  		},
   270  		{
   271  			name: "unrelated contexts;missing context B",
   272  			start: []github.RepoStatus{
   273  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   274  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   275  				*makeStatus("also not related", "error", "description 4", "url 4"),
   276  			},
   277  			expectedDiffs: []*github.RepoStatus{},
   278  		},
   279  		{
   280  			name: "missing context A",
   281  			start: []github.RepoStatus{
   282  				*makeStatus(contextB, "failure", "description 1", "url 1"),
   283  			},
   284  			expectedDiffs: []*github.RepoStatus{},
   285  		},
   286  		{
   287  			name: "unrelated contexts;missing context A",
   288  			start: []github.RepoStatus{
   289  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   290  				*makeStatus("also not related", "error", "description 4", "url 4"),
   291  				*makeStatus(contextB, "success", "description 3", "url 3"),
   292  			},
   293  			expectedDiffs: []*github.RepoStatus{},
   294  		},
   295  		{
   296  			name:          "no contexts",
   297  			start:         []github.RepoStatus{},
   298  			expectedDiffs: []*github.RepoStatus{},
   299  		},
   300  	}
   301  
   302  	m := *RetireMode(contextA, contextB)
   303  	for _, test := range tests {
   304  		diff := m.ProcessStatuses(&github.CombinedStatus{Statuses: test.start})
   305  		if err := compareDiffs(diff, test.expectedDiffs); err != nil {
   306  			t.Errorf("RetireMode(Replacement) test '%s' %v\n", test.name, err)
   307  		}
   308  	}
   309  }
   310  
   311  func TestRetireModeNoReplacement(t *testing.T) {
   312  	contextA := "context A"
   313  	desc := "Context retired without replacement."
   314  
   315  	tests := []*modeTest{
   316  		{
   317  			name: "simple",
   318  			start: []github.RepoStatus{
   319  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   320  			},
   321  			expectedDiffs: []*github.RepoStatus{
   322  				makeStatus(contextA, "success", desc, ""),
   323  			},
   324  		},
   325  		{
   326  			name: "unrelated contexts",
   327  			start: []github.RepoStatus{
   328  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   329  				*makeStatus(contextA, "failure", "description 1", "url 1"),
   330  				*makeStatus("also not related", "error", "description 4", "url 4"),
   331  			},
   332  			expectedDiffs: []*github.RepoStatus{
   333  				makeStatus(contextA, "success", desc, ""),
   334  			},
   335  		},
   336  		{
   337  			name:          "missing context A",
   338  			start:         []github.RepoStatus{},
   339  			expectedDiffs: []*github.RepoStatus{},
   340  		},
   341  		{
   342  			name: "unrelated contexts;missing context A",
   343  			start: []github.RepoStatus{
   344  				*makeStatus("unrelated context", "success", "description 2", "url 2"),
   345  				*makeStatus("also not related", "error", "description 4", "url 4"),
   346  			},
   347  			expectedDiffs: []*github.RepoStatus{},
   348  		},
   349  	}
   350  
   351  	m := *RetireMode(contextA, "")
   352  	for _, test := range tests {
   353  		diff := m.ProcessStatuses(&github.CombinedStatus{Statuses: test.start})
   354  		if err := compareDiffs(diff, test.expectedDiffs); err != nil {
   355  			t.Errorf("RetireMode(NoReplace) test '%s' %v\n", test.name, err)
   356  		}
   357  	}
   358  }
   359  
   360  // makeStatus returns a new RepoStatus struct with the specified fields.
   361  // targetURL=="" means TargetURL==nil
   362  func makeStatus(context, state, description, targetURL string) *github.RepoStatus {
   363  	var url *string
   364  	if targetURL != "" {
   365  		url = &targetURL
   366  	}
   367  	return &github.RepoStatus{
   368  		Context:     &context,
   369  		State:       &state,
   370  		Description: &description,
   371  		TargetURL:   url,
   372  	}
   373  }