Ejemplo n.º 1
0
func TestSimpleTokenRequest(t *testing.T) {
	tm := newTokenManager("acc", "rfr", 1800)

	// access token req
	tr := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}
	go tm.tokenRequest(tr)

	tokenResp := <-tr.tokenResponses
	test.Refute(t, tokenResp, nil)
	test.Expect(t, tokenResp.isAccessToken, true)
	test.Expect(t, tokenResp.token, "acc")

	// refresh token req
	tr = &tokenRequest{
		purpose:        refreshNeeded,
		tokenResponses: make(chan *tokenResponse),
	}
	go tm.tokenRequest(tr)

	tokenResp = <-tr.tokenResponses
	test.Refute(t, tokenResp, nil)
	test.Expect(t, tokenResp.isAccessToken, false)
	test.Expect(t, tokenResp.token, "rfr")
}
Ejemplo n.º 2
0
func TestApplicationRegisterSuccess(t *testing.T) {
	client := getValidApplicationClient(t)
	sessionInfo := client.Info()
	test.Expect(t, sessionInfo["access_token"], "good_access_token")
	test.Expect(t, sessionInfo["client_id"], "good_client_id")
	test.Expect(t, sessionInfo["client_secret"], "good_client_secret")
}
Ejemplo n.º 3
0
func TestDeviceRegisterSuccess(t *testing.T) {
	client := getValidDeviceClient(t)
	sessionInfo := client.Info()
	test.Expect(t, sessionInfo["access_token"], "good_access_token")
	test.Expect(t, sessionInfo["refresh_token"], "good_refresh_token")
	test.Expect(t, sessionInfo["device_id"], "device_id")
	test.Expect(t, sessionInfo["client_id"], "good_client_id")
}
Ejemplo n.º 4
0
func TestDeviceConcurrentTokenExpirationWaitingAtRefreshStep(t *testing.T) {
	dc := getValidDeviceClient(t)
	dc.setExpiresAt(-100)

	bt, gt := testConcurrentRefresh(t, dc, "refresh_token", "", "good_refresh_token", false, false)
	test.Expect(t, bt, 0)
	test.Expect(t, gt, 4)
}
Ejemplo n.º 5
0
func TestApplicationRecoveryFromErrorDuringTokenExpirationWaitingForRefresh(t *testing.T) {
	ac := getValidApplicationClient(t)
	ac.setExpiresAt(-100)

	bt, gt := testConcurrentRefresh(t, ac, "client_credentials", "good_client_secret", "", false, true)
	test.Expect(t, bt, 0)
	test.Expect(t, gt, 3)
}
Ejemplo n.º 6
0
func TestApplicationConcurrentTokenExpirationWaitingAtRefreshStep(t *testing.T) {
	ac := getValidApplicationClient(t)
	ac.setExpiresAt(-100)

	bt, gt := testConcurrentRefresh(t, ac, "client_credentials", "good_client_secret", "", false, false)
	test.Expect(t, bt, 0)
	test.Expect(t, gt, 4)
}
Ejemplo n.º 7
0
func TestDeviceRecoveryFromErrorDuringTokenExpirationWaitingForRefresh(t *testing.T) {
	dc := getValidDeviceClient(t)
	dc.setExpiresAt(-100)

	bt, gt := testConcurrentRefresh(t, dc, "refresh_token", "", "good_refresh_token", false, true)
	test.Expect(t, bt, 0)
	test.Expect(t, gt, 3)
}
Ejemplo n.º 8
0
func TestNewTokenManager(t *testing.T) {
	tm := newTokenManager("acc", "rfr", 1800)
	test.Refute(t, tm, nil)
	test.Expect(t, tm.getAccessToken(), "acc")
	test.Expect(t, tm.getRefreshToken(), "rfr")

	tm.setAccessToken("merp")
	test.Expect(t, tm.getAccessToken(), "merp")
}
Ejemplo n.º 9
0
func TestClientWithExistingDevice(t *testing.T) {
	// a test server to represent the geotrigger server
	gtServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/some/route")
		test.Expect(t, r.Header.Get("Content-Type"), "application/json")
		test.Expect(t, r.Header.Get("X-GT-Client-Name"), "geotrigger-go")
		test.Expect(t, r.Header.Get("X-GT-Client-Version"), version)
		accessToken := r.Header.Get("Authorization")
		test.Expect(t, strings.Index(accessToken, "Bearer "), 0)
		accessToken = strings.Split(accessToken, " ")[1]
		test.Expect(t, accessToken, "good_access_token")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		var params map[string]interface{}
		_ = json.Unmarshal(contents, &params)
		test.Expect(t, len(params), 1)
		test.Expect(t, params["tags"], "derp")
		fmt.Fprintln(res, `{}`)
	}))
	defer gtServer.Close()

	client := ExistingDevice("good_client_id", "device_id", "good_access_token", 1800, "good_refresh_token")
	client.session.setEnv(testEnv(gtServer.URL, ""))

	params := map[string]interface{}{
		"tags": "derp",
	}
	var responseJSON map[string]interface{}

	err := client.Request("/some/route", params, &responseJSON)
	test.Expect(t, err, nil)
}
Ejemplo n.º 10
0
func TestDeviceConcurrentRefreshWaitingAtAccessStep(t *testing.T) {
	// This will spawn 4 go routines making requests with bad tokens.
	// The first routine will fire away immediately, get the invalid token response
	// from the geotrigger server, ask for permission to refresh, and start refreshing the token.
	// After a delay, the other 3 routines will ask to use the access token,
	// and end up waiting because a refresh is in progress.
	// After the first routine successfully refreshes the token, the waiting
	// routines will be give the message to continue by using the new access token.
	bt, gt := testConcurrentRefresh(t, getValidDeviceClient(t), "refresh_token", "", "good_refresh_token", true, false)
	test.Expect(t, bt, 1)
	test.Expect(t, gt, 4)
}
Ejemplo n.º 11
0
func TestErrorCheck(t *testing.T) {
	resp := []byte(`["array", "root", "element"]`)
	errResponse := errorCheck(resp)
	test.Expect(t, errResponse, nil)

	resp = []byte(`{"object":"doesnt match", "derp":["dorp", "morp"]}`)
	errResponse = errorCheck(resp)
	test.Expect(t, errResponse, nil)

	resp = []byte(`{"error":{"code":400,"message":"Invalid token."}}`)
	errResponse = errorCheck(resp)
	test.Refute(t, errResponse, nil)
}
Ejemplo n.º 12
0
func TestClientWithNewApplication(t *testing.T) {
	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/sharing/oauth2/token")
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))
		test.Expect(t, len(vals), 4)
		test.Expect(t, vals.Get("client_id"), "good_client_id")
		test.Expect(t, vals.Get("f"), "json")
		test.Expect(t, vals.Get("grant_type"), "client_credentials")
		test.Expect(t, vals.Get("client_secret"), "good_client_secret")
		fmt.Fprintln(res, `{"access_token":"good_access_token","expires_in":7200}`)
	}))
	defer agoServer.Close()

	// set the ago url to the url of our test server so we aren't hitting prod
	agoURLRestorer, err := test.Patch(defEnv, *testEnv("", agoServer.URL))
	if err != nil {
		t.Error("Error during test setup: %s", err)
	}
	defer agoURLRestorer.Restore()

	client, err := NewApplication("good_client_id", "good_client_secret")
	test.Expect(t, err, nil)
	test.Refute(t, client, nil)
}
Ejemplo n.º 13
0
func getValidApplicationClient(t *testing.T) *Client {
	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/sharing/oauth2/token")
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))
		test.Expect(t, len(vals), 4)
		test.Expect(t, vals.Get("client_id"), "good_client_id")
		test.Expect(t, vals.Get("f"), "json")
		test.Expect(t, vals.Get("grant_type"), "client_credentials")
		test.Expect(t, vals.Get("client_secret"), "good_client_secret")
		fmt.Fprintln(res, `{"access_token":"good_access_token","expires_in":7200}`)
	}))
	defer agoServer.Close()

	application := &application{
		clientID:     "good_client_id",
		clientSecret: "good_client_secret",
		env:          testEnv("", agoServer.URL),
	}
	err := application.requestAccess()
	test.Expect(t, err, nil)

	return &Client{application}
}
Ejemplo n.º 14
0
func TestConcurrentTokenAccess(t *testing.T) {
	tm := newTokenManager("acc", "rfr", 1800)

	tr1 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr2 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr3 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr4 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	go tm.tokenRequest(tr1)
	go tm.tokenRequest(tr2)
	go tm.tokenRequest(tr3)
	go tm.tokenRequest(tr4)

	var w sync.WaitGroup
	w.Add(4)
	go func() {
		tokenResp := <-tr1.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "acc")
		w.Done()
	}()
	go func() {
		tokenResp := <-tr2.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "acc")
		w.Done()
	}()
	go func() {
		tokenResp := <-tr3.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "acc")
		w.Done()
	}()
	go func() {
		tokenResp := <-tr4.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "acc")
		w.Done()
	}()
	w.Wait()
}
Ejemplo n.º 15
0
func TestApplicationAccessRequestFail(t *testing.T) {
	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/sharing/oauth2/token")
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))
		test.Expect(t, len(vals), 4)
		test.Expect(t, vals.Get("client_id"), "bad_client_id")
		test.Expect(t, vals.Get("f"), "json")
		test.Expect(t, vals.Get("grant_type"), "client_credentials")
		test.Expect(t, vals.Get("client_secret"), "bad_client_secret")
		fmt.Fprintln(res, `{"error":{"code":999,"error":"invalid_request","error_description":"Invalid client_id","message":"invalid_request","details":[]}}`)
	}))
	defer agoServer.Close()

	application := &application{
		clientID:     "bad_client_id",
		clientSecret: "bad_client_secret",
		env:          testEnv("", agoServer.URL),
	}

	expectedErrorMessage := "Error from /sharing/oauth2/token, code: 999. Message: invalid_request"
	err := application.requestAccess()
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), expectedErrorMessage)
}
Ejemplo n.º 16
0
func TestDeviceRecoveryFromErrorDuringRefreshWithRoutinesWaitingForAccess(t *testing.T) {
	// This will spawn 4 go routines making requests with bad tokens.
	// The first routine will fire away immediately, get the invalid token response
	// from the geotrigger server, ask for permission to refresh, and start refreshing the token.
	// After a delay, the other 3 routines will ask to use the access token,
	// and end up waiting because a refresh is in progress.
	// The first routine will get an error while refreshing, which it will report.
	// The token manager routine will then promote the next routine in line to continue
	// with its actions, prompting another refresh which this time will succeed.
	// That refresh will be communicated to the remaining routines waiting for a token,
	// and they will go ahead and finish.
	bt, gt := testConcurrentRefresh(t, getValidDeviceClient(t), "refresh_token", "", "good_refresh_token", true, true)
	test.Expect(t, bt, 1)
	test.Expect(t, gt, 3)
}
Ejemplo n.º 17
0
func TestDeviceConcurrentRefreshWaitingAtRefreshStep(t *testing.T) {
	// This will spawn 4 go routines making requests with bad tokens.
	// Each routine will get permissions to present the access token to
	// the geotrigger server.
	// Whichever routine arrives first will receive the invalid token response will then ask for
	// permission to refresh the token, and be granted that permission.
	// The other 3 routines will also ask for permission to refresh, and instead
	// end up waiting for a reply to that request.
	// After the first routine successfully refreshes the token, the waiting
	// routines will be give the message to continue, but not refresh, and
	// instead use the new access token.
	bt, gt := testConcurrentRefresh(t, getValidDeviceClient(t), "refresh_token", "", "good_refresh_token", false, false)
	test.Expect(t, bt, 4)
	test.Expect(t, gt, 4)
}
Ejemplo n.º 18
0
func TestDeviceRecoveryFromErrorDuringRefreshWithRoutinesWaitingForRefresh(t *testing.T) {
	// This will spawn 4 go routines making requests with bad tokens.
	// Each routine will get permissions to present the access token to
	// the geotrigger server.
	// Whichever routine arrive first will receive the invalid token response will then ask for
	// permission to refresh the token, and be granted that permission.
	// The other 3 routines will also ask for permission to refresh, and instead
	// end up waiting for a reply to that request.
	// The first routine will get an error while refreshing, which it will report.
	// The token manager routine will then promote the next routine in line to continue
	// with its actions, prompting another refresh which this time will succeed.
	// That refresh will be communicated to the remaining routines waiting for a token,
	// and they will go ahead and finish.
	bt, gt := testConcurrentRefresh(t, getValidDeviceClient(t), "refresh_token", "", "good_refresh_token", false, true)
	test.Expect(t, bt, 4)
	test.Expect(t, gt, 3)
}
Ejemplo n.º 19
0
func TestUnknownPurposeInt(t *testing.T) {
	tm := newTokenManager("acc", "rfr", 1800)

	tr := &tokenRequest{
		purpose:        39846,
		tokenResponses: make(chan *tokenResponse),
	}
	go tm.tokenRequest(tr)

	tokenResp := <-tr.tokenResponses
	test.Expect(t, tokenResp, nil)
}
Ejemplo n.º 20
0
func TestDeviceRegisterFail(t *testing.T) {
	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/sharing/oauth2/registerDevice")
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))
		test.Expect(t, len(vals), 2)
		test.Expect(t, vals.Get("client_id"), "bad_client_id")
		test.Expect(t, vals.Get("f"), "json")
		fmt.Fprintln(res, `{"error":{"code":999,"message":"Unable to register device.","details":["'client_id' invalid"]}}`)
	}))
	defer agoServer.Close()

	device := &device{
		clientID: "bad_client_id",
		env:      testEnv("", agoServer.URL),
	}
	expectedErrorMessage := "Error from /sharing/oauth2/registerDevice, code: 999. Message: Unable to register device."
	err := device.register()

	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), expectedErrorMessage)
}
Ejemplo n.º 21
0
func TestClientWithNewDevice(t *testing.T) {
	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/sharing/oauth2/registerDevice")
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))
		test.Expect(t, len(vals), 2)
		test.Expect(t, vals.Get("client_id"), "good_client_id")
		test.Expect(t, vals.Get("f"), "json")
		fmt.Fprintln(res, `{"device":{"deviceID":"device_id","client_id":"good_client_id","apnsProdToken":null,"apnsSandboxToken":null,"gcmRegistrationId":null,"registered":1389531528000,"lastAccessed":1389531528000},"deviceToken":{"access_token":"good_access_token","expires_in":1799,"refresh_token":"good_refresh_token"}}`)
	}))
	defer agoServer.Close()

	// set the ago url to the url of our test server so we aren't hitting prod
	agoURLRestorer, err := test.Patch(defEnv, *testEnv("", agoServer.URL))
	if err != nil {
		t.Error("Error during test setup: %s", err)
	}
	defer agoURLRestorer.Restore()

	client, err := NewDevice("good_client_id")
	test.Expect(t, err, nil)
	test.Refute(t, client, nil)
}
Ejemplo n.º 22
0
func getValidDeviceClient(t *testing.T) *Client {
	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/sharing/oauth2/registerDevice")
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))
		test.Expect(t, len(vals), 2)
		test.Expect(t, vals.Get("client_id"), "good_client_id")
		test.Expect(t, vals.Get("f"), "json")
		fmt.Fprintln(res, `{"device":{"deviceID":"device_id","client_id":"good_client_id","apnsProdToken":null,"apnsSandboxToken":null,"gcmRegistrationId":null,"registered":1389531528000,"lastAccessed":1389531528000},"deviceToken":{"access_token":"good_access_token","expires_in":1799,"refresh_token":"good_refresh_token"}}`)
	}))
	defer agoServer.Close()

	device := &device{
		clientID: "good_client_id",
		env:      testEnv("", agoServer.URL),
	}
	err := device.register()
	test.Expect(t, err, nil)

	return &Client{device}
}
Ejemplo n.º 23
0
func TestValueGetters(t *testing.T) {
	var responseJSON map[string]interface{}
	err := json.Unmarshal(triggerListData, &responseJSON)
	test.Expect(t, err, nil)

	// test GetValueFromJSONObject and GetValueFromJSONArray a bit
	var triggers []interface{}
	err = GetValueFromJSONObject(responseJSON, "triggers", &triggers)
	test.Expect(t, err, nil)

	var trigger map[string]interface{}
	err = GetValueFromJSONArray(triggers, 0, &trigger)
	test.Expect(t, err, nil)

	var tags []interface{}
	err = GetValueFromJSONObject(trigger, "tags", &tags)
	test.Expect(t, err, nil)
	test.Expect(t, tags[0], "foodcarts")

	var action map[string]interface{}
	err = GetValueFromJSONObject(trigger, "action", &action)
	test.Expect(t, err, nil)

	var callback string
	err = GetValueFromJSONObject(action, "callback", &callback)
	test.Expect(t, err, nil)

	test.Expect(t, callback, "http://pdx.gov/welcome")

	// works with empty interface
	var emptyInterface interface{}
	err = GetValueFromJSONObject(trigger, "triggerId", &emptyInterface)
	test.Expect(t, err, nil)
	test.Expect(t, emptyInterface, "6fd01180fa1a012f27f1705681b27197")

	// provide nil array/object
	var failureInterface interface{}
	err = GetValueFromJSONObject(nil, "derp", &failureInterface)
	test.Expect(t, failureInterface, nil)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Attempt to get value from a nil JSON object.")

	err = GetValueFromJSONArray(nil, 1, &failureInterface)
	test.Expect(t, failureInterface, nil)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Attempt to get value from a nil JSON aray.")

	// empty key
	err = GetValueFromJSONObject(responseJSON, "", &failureInterface)
	test.Expect(t, failureInterface, nil)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Attempt to pull value for empty key from JSON object.")

	// no matching value in map
	err = GetValueFromJSONObject(responseJSON, "horse with hands", &failureInterface)
	test.Expect(t, failureInterface, nil)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "No value found for key: horse with hands")

	// index out of range
	err = GetValueFromJSONArray(triggers, -3, &failureInterface)
	test.Expect(t, failureInterface, nil)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Provided index -3 was out of range.")

	err = GetValueFromJSONArray(triggers, 17, &failureInterface)
	test.Expect(t, failureInterface, nil)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Provided index 17 was out of range.")

	// not a pointer
	err = GetValueFromJSONArray(triggers, 0, failureInterface)
	test.Expect(t, failureInterface, nil)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Provided value is of invalid type (must be pointer).")

	var notAPointer2 Trigger
	err = GetValueFromJSONArray(triggers, 0, notAPointer2)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Provided value is of invalid type (must be pointer).")
	test.Expect(t, len(notAPointer2.Tags), 0)
	test.Expect(t, notAPointer2.Condition.Geo.DriveTime, 0)

	var notAPointer3 BoundingBox
	err = GetValueFromJSONObject(responseJSON, "boundingBox", notAPointer3)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Provided value is of invalid type (must be pointer).")
	test.Expect(t, notAPointer3.Ymin, float64(0))

	// wrong value type!
	var wrongType1 BoundingBox
	err = GetValueFromJSONObject(responseJSON, "triggers", &wrongType1)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Provided reference is to a value of type geotrigger.BoundingBox that cannot be assigned to type found in JSON: []interface {}.")
	test.Expect(t, notAPointer3.Xmin, float64(0))

	var wrongType2 []interface{}
	err = GetValueFromJSONArray(triggers, 0, &wrongType2)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Provided reference is to a value of type []interface {} that cannot be assigned to type found in JSON: map[string]interface {}.")
	test.Expect(t, notAPointer3.Xmin, float64(0))
}
Ejemplo n.º 24
0
func TestRefreshWithMultipleRoutinesNeedAccessToken(t *testing.T) {
	tm := newTokenManager("acc", "rfr", 1800)

	// refresh succeeds first
	tr1 := &tokenRequest{
		purpose:        refreshNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr2 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr3 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr4 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	go tm.tokenRequest(tr1)
	time.Sleep(20 * time.Millisecond) // pause to ensure tr1 arrives first
	go tm.tokenRequest(tr2)
	go tm.tokenRequest(tr3)
	go tm.tokenRequest(tr4)

	var w sync.WaitGroup
	w.Add(4)
	go func() {
		tokenResp := <-tr2.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "new acc")
		w.Done()
	}()
	go func() {
		tokenResp := <-tr3.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "new acc")
		w.Done()
	}()
	go func() {
		tokenResp := <-tr4.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "new acc")
		w.Done()
	}()
	go func() {
		tokenResp := <-tr1.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, false)
		test.Expect(t, tokenResp.token, "rfr")

		tm.setAccessToken("new acc")
		rc := &tokenRequest{
			purpose:        refreshComplete,
			tokenResponses: nil,
		}
		go tm.tokenRequest(rc)
		w.Done()
	}()
	w.Wait()

	// refresh fails first
	tr5 := &tokenRequest{
		purpose:        refreshNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr6 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr7 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	tr8 := &tokenRequest{
		purpose:        accessNeeded,
		tokenResponses: make(chan *tokenResponse),
	}

	go tm.tokenRequest(tr5)
	time.Sleep(20 * time.Millisecond) // pause to ensure tr5 arrives first
	go tm.tokenRequest(tr6)
	time.Sleep(20 * time.Millisecond) // pause to ensure tr6 arrives second
	go tm.tokenRequest(tr7)
	go tm.tokenRequest(tr8)

	w.Add(4)
	go func() {
		tokenResp := <-tr7.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "new acc")
		w.Done()
	}()
	go func() {
		tokenResp := <-tr8.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, true)
		test.Expect(t, tokenResp.token, "new acc")
		w.Done()
	}()
	go func() {
		tokenResp := <-tr6.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, false)
		test.Expect(t, tokenResp.token, "rfr")

		tm.setAccessToken("new acc")
		rc := &tokenRequest{
			purpose:        refreshComplete,
			tokenResponses: nil,
		}
		go tm.tokenRequest(rc)
		w.Done()
	}()
	go func() {
		tokenResp := <-tr5.tokenResponses
		test.Refute(t, tokenResp, nil)
		test.Expect(t, tokenResp.isAccessToken, false)
		test.Expect(t, tokenResp.token, "rfr")

		rc := &tokenRequest{
			purpose:        refreshFailed,
			tokenResponses: nil,
		}
		go tm.tokenRequest(rc)
		w.Done()
	}()
	w.Wait()
}
Ejemplo n.º 25
0
func TestDeviceTokenRefresh(t *testing.T) {
	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/sharing/oauth2/token")
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))
		test.Expect(t, len(vals), 4)
		test.Expect(t, vals.Get("client_id"), "good_client_id")
		test.Expect(t, vals.Get("f"), "json")
		test.Expect(t, vals.Get("grant_type"), "refresh_token")
		test.Expect(t, vals.Get("refresh_token"), "good_refresh_token")
		fmt.Fprintln(res, `{"access_token":"refreshed_access_token","expires_in":1800}`)
	}))
	defer agoServer.Close()

	testDevice := &device{
		tokenManager: newTokenManager("old_access_token", "good_refresh_token", 1800),
		clientID:     "good_client_id",
		deviceID:     "device_id",
		env:          testEnv("", agoServer.URL),
	}
	expiresAt := time.Now().Unix() + 1800 - 60

	err := testDevice.refresh("good_refresh_token")
	test.Expect(t, err, nil)
	test.Expect(t, testDevice.getExpiresAt(), expiresAt)
	test.Expect(t, testDevice.getAccessToken(), "refreshed_access_token")
	test.Expect(t, testDevice.clientID, "good_client_id")
	test.Expect(t, testDevice.getRefreshToken(), "good_refresh_token")
}
Ejemplo n.º 26
0
// A big ugly func that gets called many times for tests. Separated out to avoid duplicating it.
func testConcurrentRefresh(t *testing.T, client *Client, grantType string, clientSecret string,
	refreshToken string, pauseAfterFirstReq bool, errorOnFirstRefresh bool) (int, int) {
	var refreshCount int
	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		refreshCount++

		if !errorOnFirstRefresh && refreshCount > 1 {
			t.Error("Too many refresh attempts! Should have only been 1.")
		} else if errorOnFirstRefresh && refreshCount > 2 {
			t.Error("Too many refresh attempts! Should have only been 2.")
		}

		test.Refute(t, r, nil)
		time.Sleep(80 * time.Millisecond)
		test.Expect(t, r.URL.Path, ago_token_route)
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))
		test.Expect(t, len(vals), 4)
		test.Expect(t, vals.Get("client_id"), "good_client_id")
		test.Expect(t, vals.Get("f"), "json")
		test.Expect(t, vals.Get("grant_type"), grantType)
		test.Expect(t, vals.Get("client_secret"), clientSecret)
		test.Expect(t, vals.Get("refresh_token"), refreshToken)
		if refreshCount == 1 && errorOnFirstRefresh {
			fmt.Fprintln(res, `{"error":{"code":498,"message":"Invalid token."}}`)
		} else {
			fmt.Fprintln(res, `{"access_token":"refreshed_access_token","expires_in":1800}`)
		}
	}))
	defer agoServer.Close()

	var oldAccessTokenUse, refreshedAccessTokenUse int
	// a test server to represent the geotrigger server
	gtServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/some/route")
		test.Expect(t, r.Header.Get("Content-Type"), "application/json")
		test.Expect(t, r.Header.Get("X-GT-Client-Name"), "geotrigger-go")
		test.Expect(t, r.Header.Get("X-GT-Client-Version"), version)
		accessToken := r.Header.Get("Authorization")
		test.Expect(t, strings.Index(accessToken, "Bearer "), 0)
		accessToken = strings.Split(accessToken, " ")[1]
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		var params map[string]interface{}
		_ = json.Unmarshal(contents, &params)
		test.Expect(t, len(params), 1)
		test.Expect(t, params["tags"], "derp")

		if accessToken == "good_access_token" {
			oldAccessTokenUse++
			fmt.Fprintln(res, `{"error":{"type":"invalidHeader","message":"invalid header or header value","headers":{"Authorization":[{"type":"invalid","message":"Invalid token."}]},"code":498}}`)
		} else if accessToken == "refreshed_access_token" {
			refreshedAccessTokenUse++
			fmt.Fprintln(res, `{"triggers":[{"triggerId":"6fd01180fa1a012f27f1705681b27197","condition":{"direction":"enter","geo":{"geocode":"920 SW 3rd Ave, Portland, OR","driveTime":600,"context":{"locality":"Portland","region":"Oregon","country":"USA","zipcode":"97204"}}},"action":{"message":"Welcome to Portland - The Mayor","callback":"http://pdx.gov/welcome"},"tags":["foodcarts","citygreetings"]}],"boundingBox":{"xmin":-122.68,"ymin":45.53,"xmax":-122.45,"ymax":45.6}}`)
		} else {
			t.Error(fmt.Sprintf("Unexpected access token: %s", accessToken))
		}
	}))
	defer gtServer.Close()

	client.session.setEnv(testEnv(gtServer.URL, agoServer.URL))

	params1 := map[string]interface{}{
		"tags": "derp",
	}
	var responseJSON1 map[string]interface{}
	params2 := &TriggerListTest{
		"derp",
	}
	var responseJSON2 map[string]interface{}
	params3 := map[string]interface{}{
		"tags": "derp",
	}
	var responseJSON3 map[string]interface{}
	params4 := &TriggerListTest{
		"derp",
	}
	var responseJSON4 map[string]interface{}

	var w sync.WaitGroup
	var errorCount int
	w.Add(4)
	go func() {
		err := client.Request("/some/route", params1, &responseJSON1)
		if err != nil {
			errorCount++
		}
		w.Done()
	}()
	if pauseAfterFirstReq {
		time.Sleep(20 * time.Millisecond)
	}
	go func() {
		err := client.Request("/some/route", params2, &responseJSON2)
		if err != nil {
			errorCount++
		}
		w.Done()
	}()
	go func() {
		err := client.Request("/some/route", params3, &responseJSON3)
		if err != nil {
			errorCount++
		}
		w.Done()
	}()
	go func() {
		err := client.Request("/some/route", params4, &responseJSON4)
		if err != nil {
			errorCount++
		}
		w.Done()
	}()
	w.Wait()

	if errorOnFirstRefresh {
		test.Expect(t, errorCount, 1)
	} else {
		test.Expect(t, errorCount, 0)
	}

	return oldAccessTokenUse, refreshedAccessTokenUse
}
Ejemplo n.º 27
0
func TestParseJSONResponse(t *testing.T) {
	var responseJSON TriggerList
	err := parseJSONResponse(triggerListData, &responseJSON)
	test.Expect(t, err, nil)

	test.Expect(t, responseJSON.BoundingBox.Xmax, -122.45)
	test.Expect(t, len(responseJSON.Triggers), 1)
	test.Expect(t, responseJSON.Triggers[0].Condition.Geo.Context.Zipcode, "97204")

	var partialJSON TriggerList
	err = parseJSONResponse(partialTriggerListData, &partialJSON)
	test.Expect(t, err, nil)

	// xmax is missing, will be set to zero value
	test.Expect(t, partialJSON.BoundingBox.Xmax, float64(0))
	test.Expect(t, len(partialJSON.Triggers), 1)
	test.Expect(t, partialJSON.Triggers[0].Condition.Geo.Context.Zipcode, "97204")
	// tags are missing, should be nil
	test.Expect(t, partialJSON.Triggers[0].Tags, nil)
	test.Expect(t, partialJSON.Triggers[0].Condition.Geo.Context.Region, "")

	var wrongJSON WrongJSON
	err = parseJSONResponse(triggerListData, &wrongJSON)
	test.Expect(t, err, nil)
	test.Expect(t, wrongJSON.Action.Message, "")
	test.Expect(t, wrongJSON.Derp, nil)
	test.Expect(t, wrongJSON.Dorp, 0)

	var arbitraryJSON map[string]interface{}
	err = parseJSONResponse(triggerListData, &arbitraryJSON)
	test.Expect(t, err, nil)

	var badArray []interface{}
	expectedError := `Error parsing response: {"triggers":[{"triggerId":"6fd01180fa1a012f27f1705681b27197","condition":{"direction":"enter","geo":{"geocode":"920 SW 3rd Ave, Portland, OR","driveTime":600,"context":{"locality":"Portland","region":"Oregon","country":"USA","zipcode":"97204"}}},"action":{"message":"Welcome to Portland - The Mayor","callback":"http://pdx.gov/welcome"},"tags":["foodcarts","citygreetings"]}],"boundingBox":{"xmin":-122.68,"ymin":45.53,"xmax":-122.45,"ymax":45.6}}  Error: json: cannot unmarshal object into Go value of type []interface {}`
	err = parseJSONResponse(triggerListData, &badArray)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), expectedError)
	test.Expect(t, badArray, nil)

	var goodArray []interface{}
	err = parseJSONResponse(jsonArrayData, &goodArray)
	test.Expect(t, err, nil)
	test.Expect(t, len(goodArray), 3)

	var badJSON TriggerList
	expectedError = `Error parsing response: ["herp", "derp", "dorp"]  Error: json: cannot unmarshal array into Go value of type geotrigger.TriggerList`
	err = parseJSONResponse(jsonArrayData, &badJSON)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), expectedError)
	test.Expect(t, len(badJSON.Triggers), 0)
	test.Expect(t, badJSON.BoundingBox.Xmin, float64(0))

	var notAPointer TriggerList
	err = parseJSONResponse(triggerListData, notAPointer)
	test.Refute(t, err, nil)
	test.Expect(t, err.Error(), "Provided responseJSON interface should be a pointer (to struct or map).")
	test.Expect(t, len(notAPointer.Triggers), 0)
	test.Expect(t, notAPointer.BoundingBox.Xmin, float64(0))

	var notAPointer2 interface{}
	err = parseJSONResponse(triggerListData, notAPointer2)
	test.Refute(t, err, nil)
	test.Expect(t, notAPointer2, nil)
	test.Expect(t, err.Error(), "Provided responseJSON interface should be a pointer (to struct or map).")
}
Ejemplo n.º 28
0
func TestDeviceFullWorkflowWithRefresh(t *testing.T) {
	// a test server to represent the geotrigger server
	gtServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.URL.Path, "/some/route")
		test.Expect(t, r.Header.Get("Content-Type"), "application/json")
		test.Expect(t, r.Header.Get("X-GT-Client-Name"), "geotrigger-go")
		test.Expect(t, r.Header.Get("X-GT-Client-Version"), version)
		accessToken := r.Header.Get("Authorization")
		test.Expect(t, strings.Index(accessToken, "Bearer "), 0)
		accessToken = strings.Split(accessToken, " ")[1]
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		var params map[string]interface{}
		_ = json.Unmarshal(contents, &params)
		test.Expect(t, len(params), 1)
		test.Expect(t, params["tags"], "derp")

		if accessToken == "old_access_token" {
			fmt.Fprintln(res, `{"error":{"type":"invalidHeader","message":"invalid header or header value","headers":{"Authorization":[{"type":"invalid","message":"Invalid token."}]},"code":498}}`)
		} else if accessToken == "refreshed_access_token" {
			fmt.Fprintln(res, `{"triggers":[{"triggerId":"6fd01180fa1a012f27f1705681b27197","condition":{"direction":"enter","geo":{"geocode":"920 SW 3rd Ave, Portland, OR","driveTime":600,"context":{"locality":"Portland","region":"Oregon","country":"USA","zipcode":"97204"}}},"action":{"message":"Welcome to Portland - The Mayor","callback":"http://pdx.gov/welcome"},"tags":["foodcarts","citygreetings"]}],"boundingBox":{"xmin":-122.68,"ymin":45.53,"xmax":-122.45,"ymax":45.6}}`)
		} else {
			t.Error(fmt.Sprintf("Unexpected access token: %s", accessToken))
		}
	}))
	defer gtServer.Close()

	// a test server to represent AGO
	agoServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, r *http.Request) {
		test.Refute(t, r, nil)
		test.Expect(t, r.Header.Get("Content-Type"), "application/x-www-form-urlencoded")
		contents, _ := ioutil.ReadAll(r.Body)
		test.Refute(t, len(contents), 0)
		vals, _ := url.ParseQuery(string(contents))

		if r.URL.Path == ago_register_route {
			test.Expect(t, len(vals), 2)
			test.Expect(t, vals.Get("client_id"), "good_client_id")
			test.Expect(t, vals.Get("f"), "json")
			fmt.Fprintln(res, `{"device":{"deviceID":"device_id","client_id":"good_client_id","apnsProdToken":null,"apnsSandboxToken":null,"gcmRegistrationId":null,"registered":1389531528000,"lastAccessed":1389531528000},"deviceToken":{"access_token":"old_access_token","expires_in":1799,"refresh_token":"good_refresh_token"}}`)
		} else if r.URL.Path == ago_token_route {
			test.Expect(t, len(vals), 4)
			test.Expect(t, vals.Get("client_id"), "good_client_id")
			test.Expect(t, vals.Get("f"), "json")
			test.Expect(t, vals.Get("grant_type"), "refresh_token")
			test.Expect(t, vals.Get("refresh_token"), "good_refresh_token")
			fmt.Fprintln(res, `{"access_token":"refreshed_access_token","expires_in":1800}`)
		} else {
			t.Error(fmt.Sprintf("Unexpected ago request to route: %s", r.URL.Path))
		}
	}))
	defer agoServer.Close()

	device := &device{
		clientID: "good_client_id",
		env:      testEnv(gtServer.URL, agoServer.URL),
	}
	err := device.register()
	test.Expect(t, err, nil)

	client := &Client{device}

	params := map[string]interface{}{
		"tags": "derp",
	}
	var responseJSON map[string]interface{}

	err = client.Request("/some/route", params, &responseJSON)
	test.Expect(t, err, nil)
	test.Expect(t, responseJSON["triggers"].([]interface{})[0].(map[string]interface{})["triggerId"], "6fd01180fa1a012f27f1705681b27197")
	test.Expect(t, responseJSON["boundingBox"].(map[string]interface{})["xmax"], -122.45)
}
Ejemplo n.º 29
0
func TestRouteConcat(t *testing.T) {
	expectedOutput := "derp.com/horse/pants"
	test.Expect(t, routeConcat("derp.com", "horse/pants"), expectedOutput)
	test.Expect(t, routeConcat("derp.com", "/horse/pants"), expectedOutput)
}