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, ¶ms) 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) }
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) }
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) }
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) }
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() }
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} }
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") }
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") }
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) }
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} }
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") }
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) }
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, ¶ms) 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) }
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() }
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).") }
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)) }
// 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, ¶ms) 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 }