| // Copyright 2012 Google Inc. All rights reserved. | |
| // Use of this source code is governed by the Apache 2.0 | |
| // license that can be found in the LICENSE file. | |
| package runtime | |
| import ( | |
| "context" | |
| "fmt" | |
| "net/http" | |
| "net/http/httptest" | |
| "testing" | |
| "time" | |
| "github.com/golang/protobuf/proto" | |
| "google.golang.org/appengine/internal/aetesting" | |
| pb "google.golang.org/appengine/internal/system" | |
| ) | |
| func TestRunInBackgroundSendFirst(t *testing.T) { testRunInBackground(t, true) } | |
| func TestRunInBackgroundRecvFirst(t *testing.T) { testRunInBackground(t, false) } | |
| func testRunInBackground(t *testing.T, sendFirst bool) { | |
| srv := httptest.NewServer(nil) | |
| defer srv.Close() | |
| const id = "f00bar" | |
| sendWait, recvWait := make(chan bool), make(chan bool) | |
| sbr := make(chan bool) // strobed when system.StartBackgroundRequest has started | |
| calls := 0 | |
| c := aetesting.FakeSingleContext(t, "system", "StartBackgroundRequest", func(req *pb.StartBackgroundRequestRequest, res *pb.StartBackgroundRequestResponse) error { | |
| calls++ | |
| if calls > 1 { | |
| t.Errorf("Too many calls to system.StartBackgroundRequest") | |
| } | |
| sbr <- true | |
| res.RequestId = proto.String(id) | |
| <-sendWait | |
| return nil | |
| }) | |
| var c2 context.Context // a fake | |
| newContext = func(*http.Request) context.Context { | |
| return c2 | |
| } | |
| var fRun int | |
| f := func(c3 context.Context) { | |
| fRun++ | |
| if c3 != c2 { | |
| t.Errorf("f got a different context than expected") | |
| } | |
| } | |
| ribErrc := make(chan error) | |
| go func() { | |
| ribErrc <- RunInBackground(c, f) | |
| }() | |
| brErrc := make(chan error) | |
| go func() { | |
| <-sbr | |
| req, err := http.NewRequest("GET", srv.URL+"/_ah/background", nil) | |
| if err != nil { | |
| brErrc <- fmt.Errorf("http.NewRequest: %v", err) | |
| return | |
| } | |
| req.Header.Set("X-AppEngine-BackgroundRequest", id) | |
| client := &http.Client{ | |
| Transport: &http.Transport{ | |
| Proxy: http.ProxyFromEnvironment, | |
| }, | |
| } | |
| <-recvWait | |
| _, err = client.Do(req) | |
| brErrc <- err | |
| }() | |
| // Send and receive are both waiting at this point. | |
| waits := [2]chan bool{sendWait, recvWait} | |
| if !sendFirst { | |
| waits[0], waits[1] = waits[1], waits[0] | |
| } | |
| waits[0] <- true | |
| time.Sleep(100 * time.Millisecond) | |
| waits[1] <- true | |
| if err := <-ribErrc; err != nil { | |
| t.Fatalf("RunInBackground: %v", err) | |
| } | |
| if err := <-brErrc; err != nil { | |
| t.Fatalf("background request: %v", err) | |
| } | |
| if fRun != 1 { | |
| t.Errorf("Got %d runs of f, want 1", fRun) | |
| } | |
| } |