Skip to content

Commit 29153ef

Browse files
author
Aaron Schlesinger
committed
fix(pkg/sshd/server_test.go,pkg/sshd/common_test.go): increase concurrency of testing pushes to the same repo
1 parent 1821651 commit 29153ef

2 files changed

Lines changed: 84 additions & 37 deletions

File tree

pkg/sshd/common_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ func waitWithTimeout(wg *sync.WaitGroup, timeout time.Duration) error {
2828
return nil
2929
}
3030
}
31+
32+
// sshSessionOutput is the output from a *(golang.org/x/crypto/ssh).Session's Output() call
33+
type sshSessionOutput struct {
34+
outStr string
35+
err error
36+
}

pkg/sshd/server_test.go

Lines changed: 78 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -94,72 +94,105 @@ func TestReceive(t *testing.T) {
9494
closer <- true
9595
}
9696

97-
func TestPush(t *testing.T) {
98-
const testingServerAddr = "127.0.0.1:2245"
97+
// TestPushInvalidArgsLength tests trying to do a push with only the command, not the repo
98+
func TestPushInvalidArgsLength(t *testing.T) {
99+
const testingServerAddr = "127.0.0.1:2252"
99100
key, err := sshTestingHostKey()
100101
assert.NoErr(t, err)
101102

102-
cfg := ssh.ServerConfig{
103-
NoClientAuth: true,
104-
}
103+
cfg := ssh.ServerConfig{NoClientAuth: true}
105104
cfg.AddHostKey(key)
106105

107106
c := NewCircuit()
108107
pushLock := NewInMemoryRepositoryLock()
109108
cleanerRef := cleaner.NewRef()
110-
runServer(&cfg, c, pushLock, cleanerRef, testingServerAddr, 5*time.Second, t)
109+
runServer(&cfg, c, pushLock, cleanerRef, testingServerAddr, 0*time.Second, t)
111110

112111
// Give server time to initialize.
113112
time.Sleep(200 * time.Millisecond)
114113

115-
if c.State() != ClosedState {
116-
t.Fatalf("circuit was not in closed state")
117-
}
114+
assert.Equal(t, c.State(), ClosedState, "circuit state")
118115

119116
// Connect to the server and issue env var set. This should return true.
120117
client, err := ssh.Dial("tcp", testingServerAddr, &ssh.ClientConfig{})
121-
if err != nil {
122-
t.Fatalf("Failed to connect client to local server: %s", err)
123-
}
124-
sess, err := client.NewSession()
125-
if err != nil {
126-
t.Fatalf("Failed to create client session: %s", err)
127-
}
118+
assert.NoErr(t, err)
128119

129120
// check for invalid length of arguments
121+
sess, err := client.NewSession()
122+
assert.NoErr(t, err)
123+
defer sess.Close()
130124
if out, err := sess.Output("git-upload-pack"); err == nil {
131125
t.Errorf("Expected an error but '%s' was received", out)
132126
} else if string(out) != "" {
133127
t.Errorf("Expected , got '%s'", out)
134128
}
135-
sess.Close()
129+
}
136130

137-
go func() {
138-
sess, err = client.NewSession()
139-
if err != nil {
140-
t.Fatalf("Failed to create client session: %s", err)
141-
}
142-
if out, err := sess.Output("git-upload-pack /demo.git"); err != nil {
143-
t.Errorf("Unexpected error %s, Output '%s'", err, out)
144-
} else if string(out) != "OK" {
145-
t.Errorf("Expected 'OK' got '%s'", out)
146-
}
147-
sess.Close()
148-
}()
131+
// TestConcurrentPushSameRepo tests many concurrent pushes, each to the same repo
132+
func TestConcurrentPushSameRepo(t *testing.T) {
133+
const testingServerAddr = "127.0.0.1:2245"
134+
key, err := sshTestingHostKey()
135+
assert.NoErr(t, err)
149136

150-
time.Sleep(2 * time.Second)
137+
cfg := ssh.ServerConfig{
138+
NoClientAuth: true,
139+
}
140+
cfg.AddHostKey(key)
151141

152-
sess, err = client.NewSession()
153-
if err != nil {
154-
t.Fatalf("Failed to create client session: %s", err)
142+
c := NewCircuit()
143+
pushLock := NewInMemoryRepositoryLock()
144+
cleanerRef := cleaner.NewRef()
145+
runServer(&cfg, c, pushLock, cleanerRef, testingServerAddr, 2*time.Second, t)
146+
147+
// Give server time to initialize.
148+
time.Sleep(200 * time.Millisecond)
149+
150+
assert.Equal(t, c.State(), ClosedState, "circuit state")
151+
152+
// Connect to the server and issue env var set. This should return true.
153+
client, err := ssh.Dial("tcp", testingServerAddr, &ssh.ClientConfig{})
154+
assert.NoErr(t, err)
155+
156+
const numPushers = 10
157+
outCh := make(chan *sshSessionOutput, numPushers)
158+
for i := 0; i < numPushers; i++ {
159+
go func() {
160+
sess, err := client.NewSession()
161+
assert.NoErr(t, err)
162+
defer sess.Close()
163+
out, err := sess.Output("git-upload-pack /demo.git")
164+
outCh <- &sshSessionOutput{outStr: string(out), err: err}
165+
}()
155166
}
156-
if out, err := sess.Output("git-upload-pack /demo.git"); err == nil {
157-
t.Errorf("Expected an error but returned without errors '%s'", out)
167+
168+
foundOK := false
169+
to := 1 * time.Second
170+
multiPushLine, err := gitPktLineStr(multiplePush)
171+
assert.NoErr(t, err)
172+
for i := 0; i < numPushers; i++ {
173+
select {
174+
case sessOut := <-outCh:
175+
if sessOut.outStr != multiPushLine && sessOut.outStr != "OK" {
176+
t.Fatalf("expected 'OK' or '%s', but got '%s' (error '%s')", multiPushLine, sessOut.outStr, sessOut.err)
177+
}
178+
179+
if sessOut.outStr == "OK" && sessOut.err != nil {
180+
t.Fatalf("found 'OK' output with an error %s", err)
181+
}
182+
183+
if !foundOK && sessOut.outStr == "OK" {
184+
foundOK = true
185+
} else if sessOut.outStr == "OK" {
186+
t.Fatalf("found second OK when shouldn't have")
187+
}
188+
case <-time.After(to):
189+
t.Fatalf("didn't receive an output within %s", to)
190+
}
158191
}
159-
sess.Close()
160192
}
161193

162-
func TestManyConcurrentPushes(t *testing.T) {
194+
// TestConcurrentPushDifferentRepo tests many concurrent pushes, each to a different repo
195+
func TestConcurrentPushDifferentRepo(t *testing.T) {
163196
const testingServerAddr = "127.0.0.1:2247"
164197
key, err := sshTestingHostKey()
165198
if err != nil {
@@ -363,6 +396,14 @@ func mockDummyReceive(sleepDur time.Duration) func(cookoo.Context, *cookoo.Param
363396
}
364397
}
365398

399+
func gitPktLineStr(str string) (string, error) {
400+
var buf bytes.Buffer
401+
if err := gitPktLine(&buf, str); err != nil {
402+
return "", err
403+
}
404+
return string(buf.Bytes()), nil
405+
}
406+
366407
// connMetadata mocks ssh.ConnMetadata for authentication.
367408
type connMetadata struct{}
368409

0 commit comments

Comments
 (0)