1// Copyright 2012 Google Inc. All rights reserved.
2// Use of this source code is governed by the Apache 2.0
3// license that can be found in the LICENSE file.
4
5package runtime
6
7import (
8	"fmt"
9	"net/http"
10	"net/http/httptest"
11	"testing"
12	"time"
13
14	"github.com/golang/protobuf/proto"
15	"golang.org/x/net/context"
16
17	"google.golang.org/appengine/internal/aetesting"
18	pb "google.golang.org/appengine/internal/system"
19)
20
21func TestRunInBackgroundSendFirst(t *testing.T) { testRunInBackground(t, true) }
22func TestRunInBackgroundRecvFirst(t *testing.T) { testRunInBackground(t, false) }
23
24func testRunInBackground(t *testing.T, sendFirst bool) {
25	srv := httptest.NewServer(nil)
26	defer srv.Close()
27
28	const id = "f00bar"
29	sendWait, recvWait := make(chan bool), make(chan bool)
30	sbr := make(chan bool) // strobed when system.StartBackgroundRequest has started
31
32	calls := 0
33	c := aetesting.FakeSingleContext(t, "system", "StartBackgroundRequest", func(req *pb.StartBackgroundRequestRequest, res *pb.StartBackgroundRequestResponse) error {
34		calls++
35		if calls > 1 {
36			t.Errorf("Too many calls to system.StartBackgroundRequest")
37		}
38		sbr <- true
39		res.RequestId = proto.String(id)
40		<-sendWait
41		return nil
42	})
43
44	var c2 context.Context // a fake
45	newContext = func(*http.Request) context.Context {
46		return c2
47	}
48
49	var fRun int
50	f := func(c3 context.Context) {
51		fRun++
52		if c3 != c2 {
53			t.Errorf("f got a different context than expected")
54		}
55	}
56
57	ribErrc := make(chan error)
58	go func() {
59		ribErrc <- RunInBackground(c, f)
60	}()
61
62	brErrc := make(chan error)
63	go func() {
64		<-sbr
65		req, err := http.NewRequest("GET", srv.URL+"/_ah/background", nil)
66		if err != nil {
67			brErrc <- fmt.Errorf("http.NewRequest: %v", err)
68			return
69		}
70		req.Header.Set("X-AppEngine-BackgroundRequest", id)
71		client := &http.Client{
72			Transport: &http.Transport{
73				Proxy: http.ProxyFromEnvironment,
74			},
75		}
76
77		<-recvWait
78		_, err = client.Do(req)
79		brErrc <- err
80	}()
81
82	// Send and receive are both waiting at this point.
83	waits := [2]chan bool{sendWait, recvWait}
84	if !sendFirst {
85		waits[0], waits[1] = waits[1], waits[0]
86	}
87	waits[0] <- true
88	time.Sleep(100 * time.Millisecond)
89	waits[1] <- true
90
91	if err := <-ribErrc; err != nil {
92		t.Fatalf("RunInBackground: %v", err)
93	}
94	if err := <-brErrc; err != nil {
95		t.Fatalf("background request: %v", err)
96	}
97
98	if fRun != 1 {
99		t.Errorf("Got %d runs of f, want 1", fRun)
100	}
101}
102