Skip to content

Commit 1287584

Browse files
authored
test: refactor git portforwarder under gitprovider (#521)
This refactors the git port forwarder abstraction to be underneath the git provider. The git port forwarder is only relevant with the in-cluster git server, and thus fits as an implementation detail of the LocalProvider.
1 parent c01f2dd commit 1287584

File tree

8 files changed

+84
-62
lines changed

8 files changed

+84
-62
lines changed

e2e/nomostest/git.go

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2929
"k8s.io/apimachinery/pkg/runtime"
3030
"k8s.io/apimachinery/pkg/types"
31+
"kpt.dev/configsync/e2e/nomostest/gitproviders"
3132
"kpt.dev/configsync/e2e/nomostest/retry"
3233
"kpt.dev/configsync/e2e/nomostest/testing"
3334
"kpt.dev/configsync/e2e/nomostest/testkubeclient"
@@ -96,9 +97,8 @@ type Repository struct {
9697
// For other git providers, it appends a UUID to Name for uniqueness.
9798
RemoteRepoName string
9899

99-
// RemoteURL is the remote URL of the repository.
100-
// It is used to set the url for the remote origin using `git remote add origin <REMOTE_URL>.
101-
RemoteURL string
100+
// GitProvider is the provider that hosts the Git repositories.
101+
GitProvider gitproviders.GitProvider
102102

103103
// Scheme used for encoding and decoding objects.
104104
Scheme *runtime.Scheme
@@ -130,6 +130,7 @@ func NewRepository(nt *NT, repoType RepoType, nn types.NamespacedName, sourceFor
130130
SafetyClusterRolePath: fmt.Sprintf("acme/cluster/cluster-role-%s.yaml", safetyName),
131131
Scheme: nt.Scheme,
132132
Logger: nt.Logger,
133+
GitProvider: nt.GitProvider,
133134
}
134135

135136
repoName, err := nt.GitProvider.CreateRepository(namespacedName)
@@ -139,16 +140,6 @@ func NewRepository(nt *NT, repoType RepoType, nn types.NamespacedName, sourceFor
139140
nt.T.Fatal(err)
140141
}
141142
g.RemoteRepoName = repoName
142-
var port int
143-
// port argument is used for in-cluster git provider with the local port forward.
144-
// the argument is ignored for other providers, e.g. Gitlab/Bitbucket
145-
if nt.gitRepoPortForwarder != nil {
146-
port, err = nt.gitRepoPortForwarder.LocalPort()
147-
if err != nil {
148-
nt.T.Fatal(err)
149-
}
150-
}
151-
g.RemoteURL = nt.GitProvider.RemoteURL(port, repoName)
152143

153144
g.init(nt.gitPrivateKeyPath)
154145
g.initialCommit(sourceFormat)
@@ -162,18 +153,6 @@ func (g *Repository) ReInit(nt *NT, sourceFormat filesystem.SourceFormat) {
162153

163154
// Update test environment
164155
g.T = nt.T
165-
var port int
166-
// port argument is used for in-cluster git provider with the local port forward.
167-
// the argument is ignored for other providers, e.g. Gitlab/Bitbucket
168-
if nt.gitRepoPortForwarder != nil {
169-
var err error
170-
port, err = nt.gitRepoPortForwarder.LocalPort()
171-
if err != nil {
172-
nt.T.Fatal(err)
173-
}
174-
}
175-
// Update URL to use latest port-forward port
176-
g.RemoteURL = nt.GitProvider.RemoteURL(port, g.RemoteRepoName)
177156
// Reset repo contents
178157
g.init(nt.gitPrivateKeyPath)
179158
g.initialCommit(sourceFormat)
@@ -527,9 +506,12 @@ func (g *Repository) Push(refspec string, flags ...string) {
527506
took, err := retry.Retry(1*time.Minute, func() error {
528507
args := []string{"push"}
529508
args = append(args, flags...)
530-
args = append(args, g.RemoteURL, refspec)
509+
remoteURL, err := g.GitProvider.RemoteURL(g.RemoteRepoName)
510+
if err != nil {
511+
return err
512+
}
513+
args = append(args, remoteURL, refspec)
531514
cmd := g.gitCmd(args...)
532-
var err error
533515
out, err = cmd.CombinedOutput()
534516
return err
535517
})
@@ -539,7 +521,11 @@ func (g *Repository) Push(refspec string, flags ...string) {
539521
}
540522
}
541523

542-
func (g *Repository) pushAllToRemote(remote string) {
524+
func (g *Repository) pushAllToRemote() {
525+
remote, err := g.GitProvider.RemoteURL(g.RemoteRepoName)
526+
if err != nil {
527+
g.T.Errorf("failed to get remote URL: %v", err)
528+
}
543529
cmd := g.gitCmd("push", remote, "--all")
544530
out, err := cmd.CombinedOutput()
545531
if err != nil {

e2e/nomostest/gitproviders/bitbucket.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ func (b *BitbucketClient) Type() string {
7171

7272
// RemoteURL returns the Git URL for the Bitbucket repository.
7373
// name refers to the repo name in the format of <NAMESPACE>/<NAME> of RootSync|RepoSync.
74-
func (b *BitbucketClient) RemoteURL(_ int, name string) string {
75-
return b.SyncURL(name)
74+
func (b *BitbucketClient) RemoteURL(name string) (string, error) {
75+
return b.SyncURL(name), nil
7676
}
7777

7878
// SyncURL returns a URL for Config Sync to sync from.

e2e/nomostest/gitproviders/git-provider.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package gitproviders
1616

1717
import (
1818
"kpt.dev/configsync/e2e"
19+
"kpt.dev/configsync/e2e/nomostest/portforwarder"
1920
"kpt.dev/configsync/e2e/nomostest/testing"
2021
)
2122

@@ -33,7 +34,7 @@ type GitProvider interface {
3334
// For the testing git-server, RemoteURL uses localhost and forwarded port, while SyncURL uses the DNS.
3435
// For other git providers, RemoteURL should be the same as SyncURL.
3536
// name refers to the repo name in the format of <NAMESPACE>/<NAME> of RootSync|RepoSync.
36-
RemoteURL(port int, name string) string
37+
RemoteURL(name string) (string, error)
3738

3839
// SyncURL returns the git repository URL for Config Sync to sync from.
3940
// name refers to the repo name in the format of <NAMESPACE>/<NAME> of RootSync|RepoSync.
@@ -43,8 +44,29 @@ type GitProvider interface {
4344
DeleteObsoleteRepos() error
4445
}
4546

47+
// GitProviderOpt is an optional parameter for instantiating a new GitProvider
48+
type GitProviderOpt func(opts *GitProviderOpts)
49+
50+
// GitProviderOpts is the set of optional parameters for instantiating a new GitProvider
51+
type GitProviderOpts struct {
52+
portForwarder *portforwarder.PortForwarder
53+
}
54+
55+
// WithPortForwarder provides a PortForwarder for the GitProvider to use.
56+
// Required for LocalProvider in order to establish a PortForwarder to the in-cluster
57+
// git server.
58+
func WithPortForwarder(portForwarder *portforwarder.PortForwarder) GitProviderOpt {
59+
return func(opts *GitProviderOpts) {
60+
opts.portForwarder = portForwarder
61+
}
62+
}
63+
4664
// NewGitProvider creates a GitProvider for the specific provider type.
47-
func NewGitProvider(t testing.NTB, provider string) GitProvider {
65+
func NewGitProvider(t testing.NTB, provider string, opts ...GitProviderOpt) GitProvider {
66+
options := GitProviderOpts{}
67+
for _, opt := range opts {
68+
opt(&options)
69+
}
4870
switch provider {
4971
case e2e.Bitbucket:
5072
client, err := newBitbucketClient()
@@ -59,6 +81,10 @@ func NewGitProvider(t testing.NTB, provider string) GitProvider {
5981
}
6082
return client
6183
default:
62-
return &LocalProvider{}
84+
client, err := newLocalProvider(options)
85+
if err != nil {
86+
t.Fatal(err)
87+
}
88+
return client
6389
}
6490
}

e2e/nomostest/gitproviders/gitlab.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ func (g *GitlabClient) Type() string {
5656
}
5757

5858
// RemoteURL returns the Git URL for the Gitlab project repository.
59-
func (g *GitlabClient) RemoteURL(_ int, name string) string {
60-
return g.SyncURL(name)
59+
func (g *GitlabClient) RemoteURL(name string) (string, error) {
60+
return g.SyncURL(name), nil
6161
}
6262

6363
// SyncURL returns a URL for Config Sync to sync from.

e2e/nomostest/gitproviders/local.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,23 @@ import (
1818
"fmt"
1919

2020
"kpt.dev/configsync/e2e"
21+
"kpt.dev/configsync/e2e/nomostest/portforwarder"
2122
)
2223

2324
// LocalProvider refers to the test git-server running on the same test cluster.
24-
type LocalProvider struct{}
25+
type LocalProvider struct {
26+
portForwarder *portforwarder.PortForwarder
27+
}
28+
29+
func newLocalProvider(opts GitProviderOpts) (*LocalProvider, error) {
30+
if opts.portForwarder == nil {
31+
return nil, fmt.Errorf("must provide a PortForwarderFactory for LocalProvider")
32+
}
33+
provider := &LocalProvider{
34+
portForwarder: opts.portForwarder,
35+
}
36+
return provider, nil
37+
}
2538

2639
// Type returns the provider type.
2740
func (l *LocalProvider) Type() string {
@@ -30,8 +43,12 @@ func (l *LocalProvider) Type() string {
3043

3144
// RemoteURL returns the Git URL for connecting to the test git-server.
3245
// name refers to the repo name in the format of <NAMESPACE>/<NAME> of RootSync|RepoSync.
33-
func (l *LocalProvider) RemoteURL(port int, name string) string {
34-
return fmt.Sprintf("ssh://git@localhost:%d/git-server/repos/%s", port, name)
46+
func (l *LocalProvider) RemoteURL(name string) (string, error) {
47+
port, err := l.portForwarder.LocalPort()
48+
if err != nil {
49+
return "", err
50+
}
51+
return fmt.Sprintf("ssh://git@localhost:%d/git-server/repos/%s", port, name), nil
3552
}
3653

3754
// SyncURL returns a URL for Config Sync to sync from.

e2e/nomostest/new.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ func SharedTestEnv(t nomostesting.NTB, opts *ntopts.New) *NT {
179179
gitPrivateKeyPath: sharedNt.gitPrivateKeyPath,
180180
caCertPath: sharedNt.caCertPath,
181181
Scheme: sharedNt.Scheme,
182-
GitProvider: sharedNt.GitProvider,
183182
RemoteRepositories: sharedNt.RemoteRepositories,
184183
WebhookDisabled: sharedNt.WebhookDisabled,
185184
}
@@ -257,7 +256,6 @@ func FreshTestEnv(t nomostesting.NTB, opts *ntopts.New) *NT {
257256
NonRootRepos: make(map[types.NamespacedName]*Repository),
258257
MetricsExpectations: testmetrics.NewSyncSetExpectations(t, scheme),
259258
Scheme: scheme,
260-
GitProvider: gitproviders.NewGitProvider(t, *e2e.GitProvider),
261259
RemoteRepositories: make(map[types.NamespacedName]*Repository),
262260
WebhookDisabled: &webhookDisabled,
263261
DefaultMetricsTimeout: 30 * time.Second,
@@ -318,8 +316,7 @@ func FreshTestEnv(t nomostesting.NTB, opts *ntopts.New) *NT {
318316
if err := nt.KubeClient.Create(fake.NamespaceObject(metrics.MonitoringNamespace)); err != nil {
319317
nt.T.Fatal(err)
320318
}
321-
322-
if nt.GitProvider.Type() == e2e.Local {
319+
if *e2e.GitProvider == e2e.Local {
323320
if err := nt.KubeClient.Create(gitNamespace()); err != nil {
324321
nt.T.Fatal(err)
325322
}
@@ -367,10 +364,12 @@ func setupTestCase(nt *NT, opts *ntopts.New) {
367364
allRepos = append(allRepos, repo)
368365
}
369366

370-
if nt.GitProvider.Type() == e2e.Local {
367+
var gitProviderOpts []gitproviders.GitProviderOpt
368+
if *e2e.GitProvider == e2e.Local {
371369
InitGitRepos(nt, allRepos...)
372-
nt.portForwardGitServer()
370+
gitProviderOpts = append(gitProviderOpts, gitproviders.WithPortForwarder(nt.portForwardGitServer()))
373371
}
372+
nt.GitProvider = gitproviders.NewGitProvider(nt.T, *e2e.GitProvider, gitProviderOpts...)
374373

375374
for name := range opts.RootRepos {
376375
nt.RootRepos[name] = resetRepository(nt, RootRepo, RootSyncNN(name), opts.SourceFormat)

e2e/nomostest/nt.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,6 @@ type NT struct {
147147
// caCertPath is the path to the CA cert used for communicating with the Git server.
148148
caCertPath string
149149

150-
// gitRepoPortForwarder is the local port forwarding for the git server deployment.
151-
gitRepoPortForwarder *portforwarder.PortForwarder
152-
153150
// prometheusPortForwarder is the local port forwarding for the prometheus deployment.
154151
prometheusPortForwarder *portforwarder.PortForwarder
155152

@@ -592,11 +589,8 @@ func (nt *NT) portForwardOtelCollector() {
592589
}
593590

594591
// portForwardGitServer forwards the git-server deployment to a port.
595-
func (nt *NT) portForwardGitServer() {
592+
func (nt *NT) portForwardGitServer() *portforwarder.PortForwarder {
596593
nt.T.Helper()
597-
if nt.gitRepoPortForwarder != nil {
598-
nt.T.Fatal("git server port forward already initialized")
599-
}
600594
prevPodName := ""
601595
resetGitRepos := func(newPort int, podName string) {
602596
// pod unchanged, don't reset
@@ -615,14 +609,12 @@ func (nt *NT) portForwardGitServer() {
615609
// re-init all repos
616610
InitGitRepos(nt, allRepos...)
617611
// attempt to recover by re-pushing the local repo states
618-
for nn, remoteRepo := range nt.RemoteRepositories {
619-
remoteURL := nt.GitProvider.RemoteURL(newPort, nn.String())
620-
remoteRepo.pushAllToRemote(remoteURL)
621-
remoteRepo.RemoteURL = remoteURL
612+
for _, remoteRepo := range nt.RemoteRepositories {
613+
remoteRepo.pushAllToRemote()
622614
}
623615
prevPodName = podName
624616
}
625-
nt.gitRepoPortForwarder = nt.newPortForwarder(
617+
return nt.newPortForwarder(
626618
testGitNamespace,
627619
testGitServer,
628620
":22",

e2e/nomostest/portforwarder/port_forwarder.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,19 @@ func (pf *PortForwarder) LocalPort() (int, error) {
118118
}
119119

120120
func (pf *PortForwarder) setPort(cmd *exec.Cmd, port int, pod string, async bool) {
121+
pf.logger.Infof("updating port-forward %s:%d -> %s:%d", pf.pod, pf.localPort, pod, port)
121122
if async {
122123
pf.mux.Lock()
123-
defer pf.mux.Unlock()
124-
}
125-
pf.logger.Infof("updating port-forward %s:%d -> %s:%d", pf.pod, pf.localPort, pod, port)
126-
if pf.setPortCallback != nil {
127-
pf.setPortCallback(port, pod)
128124
}
129125
pf.cmd = cmd
130126
pf.localPort = port
131127
pf.pod = pod
128+
if async {
129+
pf.mux.Unlock()
130+
}
131+
if pf.setPortCallback != nil {
132+
pf.setPortCallback(port, pod)
133+
}
132134
}
133135

134136
// portForwardToPod establishes a port forwarding to the provided pod name. This
@@ -188,7 +190,7 @@ func (pf *PortForwarder) portForwardToDeployment(async bool) error {
188190
// subprocess will be killed with the context, and we get a random port every
189191
// time. However, this cleans up subprocesses in the interim.
190192
if pf.cmd != nil {
191-
pf.logger.Info("stopping port-forward process for %s/%s", pf.ns, pf.deployment)
193+
pf.logger.Infof("stopping port-forward process for %s/%s", pf.ns, pf.deployment)
192194
if err := pf.cmd.Process.Kill(); err != nil && errors.Is(err, os.ErrProcessDone) {
193195
return errors.Wrap(err, "failed to kill port forward process")
194196
}

0 commit comments

Comments
 (0)