@@ -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.
367408type connMetadata struct {}
368409
0 commit comments