github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/pubsub/subscriber/subscriber_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 subscriber
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"cloud.google.com/go/pubsub"
    29  	"github.com/sirupsen/logrus"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	clienttesting "k8s.io/client-go/testing"
    32  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    33  
    34  	prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1"
    35  	"sigs.k8s.io/prow/pkg/client/clientset/versioned/fake"
    36  	"sigs.k8s.io/prow/pkg/config"
    37  	reporter "sigs.k8s.io/prow/pkg/crier/reporters/pubsub"
    38  	"sigs.k8s.io/prow/pkg/flagutil"
    39  	"sigs.k8s.io/prow/pkg/gangway"
    40  	"sigs.k8s.io/prow/pkg/git/v2"
    41  	"sigs.k8s.io/prow/pkg/kube"
    42  
    43  	v1 "k8s.io/api/core/v1"
    44  )
    45  
    46  var (
    47  	trueBool  = true
    48  	namespace = "default"
    49  )
    50  
    51  type pubSubTestClient struct {
    52  	messageChan chan fakeMessage
    53  }
    54  
    55  type fakeSubscription struct {
    56  	name        string
    57  	messageChan chan fakeMessage
    58  }
    59  
    60  type fakeMessage pubsub.Message
    61  
    62  func (m *fakeMessage) getAttributes() map[string]string {
    63  	return m.Attributes
    64  }
    65  
    66  func (m *fakeMessage) getPayload() []byte {
    67  	return m.Data
    68  }
    69  
    70  func (m *fakeMessage) getID() string {
    71  	return m.ID
    72  }
    73  
    74  func (m *fakeMessage) ack()  {}
    75  func (m *fakeMessage) nack() {}
    76  
    77  func (s *fakeSubscription) string() string {
    78  	return s.name
    79  }
    80  
    81  func (s *fakeSubscription) receive(ctx context.Context, f func(context.Context, messageInterface)) error {
    82  	derivedCtx, cancel := context.WithCancel(ctx)
    83  	msg := <-s.messageChan
    84  	go func() {
    85  		f(derivedCtx, &msg)
    86  		cancel()
    87  	}()
    88  	for {
    89  		select {
    90  		case <-ctx.Done():
    91  			return ctx.Err()
    92  		case <-derivedCtx.Done():
    93  			return fmt.Errorf("message processed")
    94  		}
    95  	}
    96  }
    97  
    98  func (c *pubSubTestClient) new(ctx context.Context, project string) (pubsubClientInterface, error) {
    99  	return c, nil
   100  }
   101  
   102  func (c *pubSubTestClient) subscription(id string, maxOutstandingMessages int) subscriptionInterface {
   103  	return &fakeSubscription{name: id, messageChan: c.messageChan}
   104  }
   105  
   106  type fakeReporter struct {
   107  	reported bool
   108  }
   109  
   110  func (r *fakeReporter) Report(_ context.Context, _ *logrus.Entry, pj *prowapi.ProwJob) ([]*prowapi.ProwJob, *reconcile.Result, error) {
   111  	r.reported = true
   112  	return nil, nil, nil
   113  }
   114  
   115  func (r *fakeReporter) ShouldReport(_ context.Context, _ *logrus.Entry, pj *prowapi.ProwJob) bool {
   116  	return pj.Annotations[reporter.PubSubProjectLabel] != "" && pj.Annotations[reporter.PubSubTopicLabel] != ""
   117  }
   118  
   119  func tryGetCloneURIAndHost(pe ProwJobEvent) (cloneURI, host string) {
   120  	refs := pe.Refs
   121  	if refs == nil {
   122  		return "", ""
   123  	}
   124  	if len(refs.Org) == 0 {
   125  		return "", ""
   126  	}
   127  	if len(refs.Repo) == 0 {
   128  		return "", ""
   129  	}
   130  
   131  	// If the Refs struct already has a populated CloneURI field, use that
   132  	// instead.
   133  	if refs.CloneURI != "" {
   134  		if strings.HasPrefix(refs.Org, "http") {
   135  			return refs.CloneURI, refs.Org
   136  		}
   137  		return refs.CloneURI, ""
   138  	}
   139  
   140  	org, repo := refs.Org, refs.Repo
   141  	orgRepo := org + "/" + repo
   142  	// Add "https://" prefix to orgRepo if this is a gerrit job.
   143  	// (Unfortunately gerrit jobs use the full repo URL as the identifier.)
   144  	prefix := "https://"
   145  	if pe.Labels[kube.GerritRevision] != "" && !strings.HasPrefix(orgRepo, prefix) {
   146  		orgRepo = prefix + orgRepo
   147  	}
   148  	return orgRepo, org
   149  }
   150  
   151  func TestProwJobEvent_ToFromMessage(t *testing.T) {
   152  	pe := ProwJobEvent{
   153  		Annotations: map[string]string{
   154  			reporter.PubSubProjectLabel: "project",
   155  			reporter.PubSubTopicLabel:   "topic",
   156  			reporter.PubSubRunIDLabel:   "asdfasdfn",
   157  		},
   158  		Envs: map[string]string{
   159  			"ENV1": "test",
   160  			"ENV2": "test2",
   161  		},
   162  		Name: "ProwJobName",
   163  	}
   164  	m, err := pe.ToMessage()
   165  	if err != nil {
   166  		t.Error(err)
   167  	}
   168  	if m.Attributes[ProwEventType] != PeriodicProwJobEvent {
   169  		t.Errorf("%s should be %s found %s instead", ProwEventType, PeriodicProwJobEvent, m.Attributes[ProwEventType])
   170  	}
   171  	var newPe ProwJobEvent
   172  	if err = newPe.FromPayload(m.Data); err != nil {
   173  		t.Error(err)
   174  	}
   175  	if !reflect.DeepEqual(pe, newPe) {
   176  		t.Error("JSON encoding failed. ")
   177  	}
   178  }
   179  
   180  func TestHandleMessage(t *testing.T) {
   181  	for _, tc := range []struct {
   182  		name, eventType string
   183  		msg             *pubSubMessage
   184  		pe              *ProwJobEvent
   185  		config          *config.Config
   186  		err             string
   187  		labels          []string
   188  	}{
   189  		{
   190  			name:      "PeriodicJobNoPubsub",
   191  			eventType: PeriodicProwJobEvent,
   192  			pe: &ProwJobEvent{
   193  				Name: "test",
   194  			},
   195  			config: &config.Config{
   196  				JobConfig: config.JobConfig{
   197  					Periodics: []config.Periodic{
   198  						{
   199  							JobBase: config.JobBase{
   200  								Name: "test",
   201  							},
   202  						},
   203  					},
   204  				},
   205  			},
   206  		},
   207  		{
   208  			name:      "PresubmitForGitHub",
   209  			eventType: PresubmitProwJobEvent,
   210  			pe: &ProwJobEvent{
   211  				Name: "pull-github",
   212  				Refs: &prowapi.Refs{
   213  					Org:     "org",
   214  					Repo:    "repo",
   215  					BaseRef: "master",
   216  					BaseSHA: "SHA",
   217  					Pulls: []prowapi.Pull{
   218  						{
   219  							Number: 42,
   220  						},
   221  					},
   222  				},
   223  			},
   224  			config: &config.Config{
   225  				JobConfig: config.JobConfig{
   226  					PresubmitsStatic: map[string][]config.Presubmit{
   227  						"org/repo": {
   228  							{
   229  								JobBase: config.JobBase{
   230  									Name: "pull-github",
   231  								},
   232  							},
   233  						},
   234  					},
   235  				},
   236  			},
   237  		},
   238  		{
   239  			name:      "PresubmitForGerrit",
   240  			eventType: PresubmitProwJobEvent,
   241  			pe: &ProwJobEvent{
   242  				Name: "pull-gerrit",
   243  				Refs: &prowapi.Refs{
   244  					Org:     "org",
   245  					Repo:    "repo",
   246  					BaseRef: "master",
   247  					BaseSHA: "SHA",
   248  					Pulls: []prowapi.Pull{
   249  						{
   250  							Number: 42,
   251  						},
   252  					},
   253  				},
   254  				Labels: map[string]string{
   255  					kube.GerritRevision: "revision",
   256  				},
   257  			},
   258  			config: &config.Config{
   259  				JobConfig: config.JobConfig{
   260  					PresubmitsStatic: map[string][]config.Presubmit{
   261  						"https://org/repo": {
   262  							{
   263  								JobBase: config.JobBase{
   264  									Name: "pull-gerrit",
   265  								},
   266  							},
   267  						},
   268  					},
   269  				},
   270  			},
   271  		},
   272  		{
   273  			name:      "UnknownEventType",
   274  			eventType: PeriodicProwJobEvent,
   275  			msg: &pubSubMessage{
   276  				Message: pubsub.Message{
   277  					Attributes: map[string]string{
   278  						ProwEventType: "unsupported",
   279  					},
   280  					Data: []byte("{}"),
   281  				},
   282  			},
   283  			config: &config.Config{},
   284  			err:    "unsupported event type: unsupported",
   285  			labels: []string{reporter.PubSubTopicLabel, reporter.PubSubRunIDLabel, reporter.PubSubProjectLabel},
   286  		},
   287  		{
   288  			name:      "NoEventType",
   289  			eventType: PeriodicProwJobEvent,
   290  			msg: &pubSubMessage{
   291  				Message: pubsub.Message{
   292  					Data: []byte("{}"),
   293  				},
   294  			},
   295  			config: &config.Config{},
   296  			err:    "unable to find \"prow.k8s.io/pubsub.EventType\" from the attributes",
   297  			labels: []string{reporter.PubSubTopicLabel, reporter.PubSubRunIDLabel, reporter.PubSubProjectLabel},
   298  		},
   299  		{
   300  			name:      "PresubmitForGerritWithInRepoConfig",
   301  			eventType: PresubmitProwJobEvent,
   302  			pe: &ProwJobEvent{
   303  				Name: "pull-gerrit",
   304  				Refs: &prowapi.Refs{
   305  					Org:     "org",
   306  					Repo:    "repo",
   307  					BaseRef: "master",
   308  					BaseSHA: "SHA",
   309  					Pulls: []prowapi.Pull{
   310  						{
   311  							Number: 42,
   312  						},
   313  					},
   314  				},
   315  				Labels: map[string]string{
   316  					kube.GerritRevision: "revision",
   317  				},
   318  			},
   319  			config: &config.Config{
   320  				JobConfig: config.JobConfig{
   321  					ProwYAMLGetterWithDefaults: fakeProwYAMLGetter,
   322  					ProwYAMLGetter:             fakeProwYAMLGetter,
   323  				},
   324  				ProwConfig: config.ProwConfig{
   325  					PodNamespace: namespace,
   326  					InRepoConfig: config.InRepoConfig{
   327  						Enabled:         map[string]*bool{"*": &trueBool},
   328  						AllowedClusters: map[string][]string{"*": {"default"}},
   329  					},
   330  				},
   331  			},
   332  		},
   333  	} {
   334  		t.Run(tc.name, func(t1 *testing.T) {
   335  			fakeProwJobClient := fake.NewSimpleClientset()
   336  			ca := &config.Agent{}
   337  			tc.config.ProwJobNamespace = "prowjobs"
   338  			ca.Set(tc.config)
   339  			fr := fakeReporter{}
   340  			gitClient, _ := (&flagutil.GitHubOptions{}).GitClientFactory("abc", nil, true, false)
   341  			cache, _ := config.NewInRepoConfigCache(100, ca, gitClient)
   342  			s := Subscriber{
   343  				Metrics:            NewMetrics(),
   344  				ProwJobClient:      fakeProwJobClient.ProwV1().ProwJobs(tc.config.ProwJobNamespace),
   345  				ConfigAgent:        ca,
   346  				Reporter:           &fr,
   347  				InRepoConfigGetter: cache,
   348  			}
   349  			if tc.pe != nil {
   350  				m, err := tc.pe.ToMessageOfType(tc.eventType)
   351  				if err != nil {
   352  					t.Error(err)
   353  				}
   354  				m.ID = "id"
   355  				tc.msg = &pubSubMessage{*m}
   356  			}
   357  			if err := s.handleMessage(tc.msg, "", []string{"*"}); err != nil {
   358  				if err.Error() != tc.err {
   359  					t1.Errorf("Expected error '%v' got '%v'", tc.err, err.Error())
   360  				} else if tc.err == "" {
   361  					var created []*prowapi.ProwJob
   362  					for _, action := range fakeProwJobClient.Fake.Actions() {
   363  						switch action := action.(type) {
   364  						case clienttesting.CreateActionImpl:
   365  							if prowjob, ok := action.Object.(*prowapi.ProwJob); ok {
   366  								created = append(created, prowjob)
   367  							}
   368  						}
   369  					}
   370  					if len(created) != 1 {
   371  						t.Errorf("Expected to create 1 ProwJobs, got %d", len(created))
   372  					}
   373  					for _, k := range tc.labels {
   374  						if _, ok := created[0].Labels[k]; !ok {
   375  							t.Errorf("label %s is missing", k)
   376  						}
   377  					}
   378  				}
   379  			}
   380  		})
   381  	}
   382  }
   383  
   384  func CheckProwJob(pe *ProwJobEvent, pj *prowapi.ProwJob) error {
   385  	// checking labels
   386  	for label, value := range pe.Labels {
   387  		if pj.Labels[label] != value {
   388  			return fmt.Errorf("label %s should be set to %s, found %s instead", label, value, pj.Labels[label])
   389  		}
   390  	}
   391  	// Checking Annotations
   392  	for annotation, value := range pe.Annotations {
   393  		if pj.Annotations[annotation] != value {
   394  			return fmt.Errorf("annotation %s should be set to %s, found %s instead", annotation, value, pj.Annotations[annotation])
   395  		}
   396  	}
   397  	if pj.Spec.PodSpec != nil {
   398  		// Checking Envs
   399  		for _, container := range pj.Spec.PodSpec.Containers {
   400  			envs := map[string]string{}
   401  			for _, env := range container.Env {
   402  				envs[env.Name] = env.Value
   403  			}
   404  			for env, value := range pe.Envs {
   405  				if envs[env] != value {
   406  					return fmt.Errorf("env %s should be set to %s, found %s instead", env, value, pj.Annotations[env])
   407  				}
   408  			}
   409  		}
   410  	}
   411  
   412  	return nil
   413  }
   414  
   415  func TestHandlePeriodicJob(t *testing.T) {
   416  	for _, tc := range []struct {
   417  		name            string
   418  		pe              *ProwJobEvent
   419  		s               string
   420  		config          *config.Config
   421  		allowedClusters []string
   422  		err             string
   423  		reported        bool
   424  		clientFails     bool
   425  	}{
   426  		{
   427  			name: "PeriodicJobNoPubsub",
   428  			pe: &ProwJobEvent{
   429  				Name: "test",
   430  			},
   431  			config: &config.Config{
   432  				JobConfig: config.JobConfig{
   433  					Periodics: []config.Periodic{
   434  						{
   435  							JobBase: config.JobBase{
   436  								Name: "test",
   437  							},
   438  						},
   439  					},
   440  				},
   441  			},
   442  			allowedClusters: []string{"*"},
   443  		},
   444  		{
   445  			name: "PeriodicJobPubsubSet",
   446  			pe: &ProwJobEvent{
   447  				Name: "test",
   448  				Annotations: map[string]string{
   449  					reporter.PubSubProjectLabel: "project",
   450  					reporter.PubSubRunIDLabel:   "runid",
   451  					reporter.PubSubTopicLabel:   "topic",
   452  				},
   453  				Labels: map[string]string{
   454  					"label1": "label1",
   455  					"label2": "label2",
   456  				},
   457  				Envs: map[string]string{
   458  					"env1": "env1",
   459  					"env2": "env2",
   460  				},
   461  			},
   462  			config: &config.Config{
   463  				JobConfig: config.JobConfig{
   464  					Periodics: []config.Periodic{
   465  						{
   466  							JobBase: config.JobBase{
   467  								Name:        "test",
   468  								Labels:      map[string]string{},
   469  								Annotations: map[string]string{},
   470  								Spec: &v1.PodSpec{
   471  									Containers: []v1.Container{
   472  										{
   473  											Name: "test",
   474  										},
   475  									},
   476  								},
   477  							},
   478  						},
   479  					},
   480  				},
   481  			},
   482  			allowedClusters: []string{"*"},
   483  			reported:        true,
   484  		},
   485  		{
   486  			name: "ClusterNotAllowed",
   487  			pe: &ProwJobEvent{
   488  				Name: "test",
   489  			},
   490  			config: &config.Config{
   491  				JobConfig: config.JobConfig{
   492  					Periodics: []config.Periodic{
   493  						{
   494  							JobBase: config.JobBase{
   495  								Name:    "test",
   496  								Cluster: "precious-cluster",
   497  							},
   498  						},
   499  					},
   500  				},
   501  			},
   502  			allowedClusters: []string{"normal-cluster"},
   503  			err:             "cluster precious-cluster is not allowed. Can be fixed by defining this cluster under pubsub_triggers -> allowed_clusters",
   504  		},
   505  		{
   506  			name: "DefaultClusterNotAllowed",
   507  			pe: &ProwJobEvent{
   508  				Name: "test",
   509  			},
   510  			config: &config.Config{
   511  				JobConfig: config.JobConfig{
   512  					Periodics: []config.Periodic{
   513  						{
   514  							JobBase: config.JobBase{
   515  								Name: "test",
   516  							},
   517  						},
   518  					},
   519  				},
   520  			},
   521  			allowedClusters: []string{"normal-cluster"},
   522  			err:             "cluster  is not allowed. Can be fixed by defining this cluster under pubsub_triggers -> allowed_clusters",
   523  		},
   524  		{
   525  			name: "PeriodicJobPubsubSetCreationError",
   526  			pe: &ProwJobEvent{
   527  				Name: "test",
   528  				Annotations: map[string]string{
   529  					reporter.PubSubProjectLabel: "project",
   530  					reporter.PubSubRunIDLabel:   "runid",
   531  					reporter.PubSubTopicLabel:   "topic",
   532  				},
   533  			},
   534  			config: &config.Config{
   535  				JobConfig: config.JobConfig{
   536  					Periodics: []config.Periodic{
   537  						{
   538  							JobBase: config.JobBase{
   539  								Name: "test",
   540  							},
   541  						},
   542  					},
   543  				},
   544  			},
   545  			allowedClusters: []string{"*"},
   546  			err:             "failed to create prowjob",
   547  			clientFails:     true,
   548  			reported:        true,
   549  		},
   550  		{
   551  			name: "JobNotFound",
   552  			pe: &ProwJobEvent{
   553  				Name: "test",
   554  			},
   555  			config:          &config.Config{},
   556  			allowedClusters: []string{"*"},
   557  			err:             "failed to find associated periodic job \"test\"",
   558  		},
   559  		{
   560  			name: "JobNotFoundReportNeeded",
   561  			pe: &ProwJobEvent{
   562  				Name: "test",
   563  				Annotations: map[string]string{
   564  					reporter.PubSubProjectLabel: "project",
   565  					reporter.PubSubRunIDLabel:   "runid",
   566  					reporter.PubSubTopicLabel:   "topic",
   567  				},
   568  			},
   569  			config:          &config.Config{},
   570  			allowedClusters: []string{"*"},
   571  			err:             "failed to find associated periodic job \"test\"",
   572  			reported:        true,
   573  		},
   574  	} {
   575  		t.Run(tc.name, func(t1 *testing.T) {
   576  			fakeProwJobClient := fake.NewSimpleClientset()
   577  			if tc.clientFails {
   578  				fakeProwJobClient.PrependReactor("*", "*", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
   579  					return true, nil, errors.New("failed to create prowjob")
   580  				})
   581  			}
   582  			ca := &config.Agent{}
   583  			tc.config.ProwJobNamespace = "prowjobs"
   584  			ca.Set(tc.config)
   585  			fr := fakeReporter{}
   586  			gitClient, _ := (&flagutil.GitHubOptions{}).GitClientFactory("abc", nil, true, false)
   587  			cache, _ := config.NewInRepoConfigCache(100, ca, gitClient)
   588  			s := Subscriber{
   589  				Metrics:            NewMetrics(),
   590  				ProwJobClient:      fakeProwJobClient.ProwV1().ProwJobs(ca.Config().ProwJobNamespace),
   591  				ConfigAgent:        ca,
   592  				InRepoConfigGetter: cache,
   593  				Reporter:           &fr,
   594  			}
   595  			l := logrus.NewEntry(logrus.New())
   596  
   597  			cjer, err := s.peToCjer(l, tc.pe, PeriodicProwJobEvent, "fakeSubsciprtionName")
   598  			if err != nil {
   599  				t1.Error("programmer error: could not convert ProwJobEvent to CreateJobExecutionRequest")
   600  			}
   601  
   602  			cfgAdapter := gangway.ProwCfgAdapter{Config: s.ConfigAgent.Config()}
   603  			_, err = gangway.HandleProwJob(l, s.getReporterFunc(l), cjer, s.ProwJobClient, &cfgAdapter, s.InRepoConfigGetter, nil, false, tc.allowedClusters)
   604  			if err != nil {
   605  				if err.Error() != tc.err {
   606  					t1.Errorf("Expected error '%v' got '%v'", tc.err, err.Error())
   607  				}
   608  			} else if tc.err == "" {
   609  				var created []*prowapi.ProwJob
   610  				for _, action := range fakeProwJobClient.Fake.Actions() {
   611  					switch action := action.(type) {
   612  					case clienttesting.CreateActionImpl:
   613  						if prowjob, ok := action.Object.(*prowapi.ProwJob); ok {
   614  							created = append(created, prowjob)
   615  							if err := CheckProwJob(tc.pe, prowjob); err != nil {
   616  								t.Error(err)
   617  							}
   618  						}
   619  					}
   620  				}
   621  				if len(created) != 1 {
   622  					t.Errorf("Expected to create 1 ProwJobs, got %d", len(created))
   623  				}
   624  			}
   625  
   626  			if fr.reported != tc.reported {
   627  				t1.Errorf("Expected Reporting: %t, found: %t", tc.reported, fr.reported)
   628  			}
   629  		})
   630  	}
   631  }
   632  
   633  func TestPullServer_RunShutdown(t *testing.T) {
   634  	s := &Subscriber{
   635  		ConfigAgent:   &config.Agent{},
   636  		ProwJobClient: fake.NewSimpleClientset().ProwV1().ProwJobs("prowjobs"),
   637  		Metrics:       NewMetrics(),
   638  	}
   639  	c := &config.Config{}
   640  	s.ConfigAgent.Set(c)
   641  	pullServer := PullServer{
   642  		Subscriber: s,
   643  		Client:     &pubSubTestClient{},
   644  	}
   645  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   646  	errChan := make(chan error)
   647  	go func() {
   648  		errChan <- pullServer.Run(ctx)
   649  	}()
   650  	time.Sleep(10 * time.Millisecond)
   651  	cancel()
   652  	err := <-errChan
   653  	if err != nil {
   654  		if !strings.HasPrefix(err.Error(), "context canceled") {
   655  			t.Errorf("unexpected error: %v", err)
   656  		}
   657  	}
   658  }
   659  
   660  func TestPullServer_RunHandlePullFail(t *testing.T) {
   661  	s := &Subscriber{
   662  		ConfigAgent:   &config.Agent{},
   663  		ProwJobClient: fake.NewSimpleClientset().ProwV1().ProwJobs("prowjobs"),
   664  		Metrics:       NewMetrics(),
   665  	}
   666  	c := &config.Config{
   667  		ProwConfig: config.ProwConfig{
   668  			PubSubTriggers: []config.PubSubTrigger{
   669  				{
   670  					Project:         "project",
   671  					Topics:          []string{"test"},
   672  					AllowedClusters: []string{"*"},
   673  				},
   674  			},
   675  		},
   676  	}
   677  	messageChan := make(chan fakeMessage, 1)
   678  	s.ConfigAgent.Set(c)
   679  	pullServer := PullServer{
   680  		Subscriber: s,
   681  		Client:     &pubSubTestClient{messageChan: messageChan},
   682  	}
   683  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   684  	errChan := make(chan error)
   685  	messageChan <- fakeMessage{
   686  		Attributes: map[string]string{},
   687  		ID:         "test",
   688  	}
   689  	defer cancel()
   690  	go func() {
   691  		errChan <- pullServer.Run(ctx)
   692  	}()
   693  	err := <-errChan
   694  	// Should fail since Pub/Sub cred are not set
   695  	if !strings.HasPrefix(err.Error(), "message processed") {
   696  		t.Errorf("unexpected error: %v", err)
   697  	}
   698  }
   699  
   700  func TestPullServer_RunConfigChange(t *testing.T) {
   701  	s := &Subscriber{
   702  		ConfigAgent:   &config.Agent{},
   703  		ProwJobClient: fake.NewSimpleClientset().ProwV1().ProwJobs("prowjobs"),
   704  		Metrics:       NewMetrics(),
   705  	}
   706  	c := &config.Config{}
   707  	messageChan := make(chan fakeMessage, 1)
   708  	s.ConfigAgent.Set(c)
   709  	pullServer := PullServer{
   710  		Subscriber: s,
   711  		Client:     &pubSubTestClient{messageChan: messageChan},
   712  	}
   713  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   714  	defer cancel()
   715  	errChan := make(chan error)
   716  	go func() {
   717  		errChan <- pullServer.Run(ctx)
   718  	}()
   719  	select {
   720  	case <-errChan:
   721  		t.Error("should not fail")
   722  	case <-time.After(10 * time.Millisecond):
   723  		newConfig := &config.Config{
   724  			ProwConfig: config.ProwConfig{
   725  				PubSubTriggers: []config.PubSubTrigger{
   726  					{
   727  						Project:         "project",
   728  						Topics:          []string{"test"},
   729  						AllowedClusters: []string{"*"},
   730  					},
   731  				},
   732  			},
   733  		}
   734  		s.ConfigAgent.Set(newConfig)
   735  		messageChan <- fakeMessage{
   736  			Attributes: map[string]string{},
   737  			ID:         "test",
   738  		}
   739  		err := <-errChan
   740  		if !strings.HasPrefix(err.Error(), "message processed") {
   741  			t.Errorf("unexpected error: %v", err)
   742  		}
   743  	}
   744  }
   745  
   746  func TestTryGetCloneURIAndHost(t *testing.T) {
   747  	tests := []struct {
   748  		name             string
   749  		pe               ProwJobEvent
   750  		expectedCloneURI string
   751  		expectedHost     string
   752  	}{
   753  		{
   754  			name: "regular",
   755  			pe: ProwJobEvent{
   756  				Refs: &prowapi.Refs{
   757  					Org:  "org",
   758  					Repo: "repo",
   759  				},
   760  			},
   761  			expectedCloneURI: "org/repo",
   762  			expectedHost:     "org",
   763  		},
   764  		{
   765  			name: "empty org",
   766  			pe: ProwJobEvent{
   767  				Refs: &prowapi.Refs{
   768  					Org:  "",
   769  					Repo: "repo",
   770  				},
   771  			},
   772  			expectedCloneURI: "",
   773  			expectedHost:     "",
   774  		},
   775  		{
   776  			name: "empty repo",
   777  			pe: ProwJobEvent{
   778  				Refs: &prowapi.Refs{
   779  					Org:  "org",
   780  					Repo: "",
   781  				},
   782  			},
   783  			expectedCloneURI: "",
   784  			expectedHost:     "",
   785  		},
   786  		{
   787  			name: "empty org and repo",
   788  			pe: ProwJobEvent{
   789  				Refs: &prowapi.Refs{
   790  					Org:  "",
   791  					Repo: "",
   792  				},
   793  			},
   794  			expectedCloneURI: "",
   795  			expectedHost:     "",
   796  		},
   797  		{
   798  			name: "gerrit",
   799  			pe: ProwJobEvent{
   800  				Refs: &prowapi.Refs{
   801  					Org:  "https://org",
   802  					Repo: "repo",
   803  				},
   804  				Labels: map[string]string{
   805  					kube.GerritRevision: "foo",
   806  				},
   807  			},
   808  			expectedCloneURI: "https://org/repo",
   809  			expectedHost:     "https://org",
   810  		},
   811  		{
   812  			name: "nil Refs",
   813  			pe: ProwJobEvent{
   814  				Refs: nil,
   815  			},
   816  			expectedCloneURI: "",
   817  			expectedHost:     "",
   818  		},
   819  		{
   820  			name: "use CloneURI",
   821  			pe: ProwJobEvent{
   822  				Refs: &prowapi.Refs{
   823  					Org:      "http://org",
   824  					Repo:     "repo",
   825  					CloneURI: "some-clone-uri",
   826  				},
   827  			},
   828  			expectedCloneURI: "some-clone-uri",
   829  			expectedHost:     "http://org",
   830  		},
   831  		{
   832  			name: "use ssh-style CloneURI",
   833  			pe: ProwJobEvent{
   834  				Refs: &prowapi.Refs{
   835  					Org:      "git@github.com:kubernetes/test-infra.git",
   836  					Repo:     "repo",
   837  					CloneURI: "some-clone-uri",
   838  				},
   839  			},
   840  			expectedCloneURI: "some-clone-uri",
   841  			expectedHost:     "",
   842  		},
   843  	}
   844  	for _, tc := range tests {
   845  		gotCloneURI, gotHost := tryGetCloneURIAndHost(tc.pe)
   846  		if gotCloneURI != tc.expectedCloneURI {
   847  			t.Errorf("%s: got %q, expected %q", tc.name, gotCloneURI, tc.expectedCloneURI)
   848  		}
   849  		if gotHost != tc.expectedHost {
   850  			t.Errorf("%s: got %q, expected %q", tc.name, gotHost, tc.expectedHost)
   851  		}
   852  	}
   853  }
   854  
   855  func fakeProwYAMLGetter(
   856  	c *config.Config,
   857  	gc git.ClientFactory,
   858  	identifier string,
   859  	baseBranch string,
   860  	baseSHA string,
   861  	headSHAs ...string) (*config.ProwYAML, error) {
   862  
   863  	presubmits := []config.Presubmit{
   864  		{
   865  			JobBase: config.JobBase{
   866  				Name:      "pull-gerrit",
   867  				Spec:      &v1.PodSpec{Containers: []v1.Container{{Name: "always-runs-inRepoConfig", Env: []v1.EnvVar{}}}},
   868  				Namespace: &namespace,
   869  			},
   870  			AlwaysRun: true,
   871  			Reporter: config.Reporter{
   872  				Context:    "pull-gerrit",
   873  				SkipReport: true,
   874  			},
   875  		},
   876  	}
   877  	if err := config.SetPresubmitRegexes(presubmits); err != nil {
   878  		return nil, err
   879  	}
   880  	res := config.ProwYAML{
   881  		Presubmits: presubmits,
   882  	}
   883  	return &res, nil
   884  }