// handle various http responses (404, 200 etc.) func TestMarkitChartAPIIntegration(t *testing.T) { // run test cases testdata := testhelpers.MarkitTestData for _, test := range testdata { // initialize request request, err := stock.NewMarkitChartAPIRequest( stock.NewStock(test.Sym), test.StartDate, test.EndDate) if err != nil { t.Errorf("Could not create a MarkitChartAPIRequest: %v", err) } actualUrl := request.Url // save the actualUrl for the request // start test server with success status tsParams := testhelpers.TestServer{ Status: http.StatusOK, RequestUrl: actualUrl, TestData: testdata, T: t, } ts := httptest.NewServer(&tsParams) request.Url = ts.URL // override request URL to hit test server // test five most common error responses var errorCodes = []int{500, 404, 403, 400, 401} for _, errorCode := range errorCodes { tsParams = testhelpers.TestServer{ Status: errorCode, RequestUrl: actualUrl, TestData: testdata, T: t, } response, err := request.Request() if err == nil { t.Errorf("Expected an error and got success (!?), response:\n%v", response) } else if !strings.Contains(err.Error(), strconv.Itoa(errorCode)) { t.Errorf("Expected %d, got... something else: %v", errorCode, err) } } // switch test server to success response and make request tsParams = testhelpers.TestServer{ Status: http.StatusOK, RequestUrl: actualUrl, TestData: testdata, T: t, } response, err := request.Request() if test.ExpectError && err == nil { t.Errorf("Expected error response but got success: %v", response) } else if !test.ExpectError && err != nil { t.Errorf("Expected successful response but got error: %v", err) } else if !test.ExpectError { // expected success and got a response // compare response with expected if !CompareMarkitChartAPIResponses(&test.ExpectedMarkitResponse, response) { t.Errorf("Response from Markit differs from expected, expected:\n%v\ngot:\n%v\n", test.ExpectedMarkitResponse, response) } } t.Logf("Test complete: %s, %s to %s", test.Sym, test.StartDate.String(), test.EndDate.String()) } }
func TestInsert(t *testing.T) { var tests = []struct { symbol string span stock.Span }{ {"GOOG", testSpan1}, } // create test db connection tdb := stock.DB.Setup(stock.TestLocal) // record the changes we make so they can be reversed, all measures in span will be inserted td := testhelpers.TearDown{} for _, test := range tests { td = td.TrackSpanInsert(test.symbol, &test.span, tdb, t) } defer func() { err := td.TearDown(tdb, t) if err != nil { t.Error(err) } }() for _, test := range tests { // do the DB.Insert() err := tdb.Insert(stock.NewStock(test.symbol), &test.span) if err != nil { t.Error(err) } // query for all data for test.symbol and compare against provided span // use a direct Queryx here, we'll test GetRange separately rows, err := tdb.Queryx(`SELECT Time, Value FROM Measures where Symbol = $1`, test.symbol) if err != nil { t.Error(err) } spanToCheck := *new(stock.Span) for rows.Next() { m := new(stock.Measure) err = rows.StructScan(m) if err != nil { t.Error(err) } spanToCheck = append(spanToCheck, *m) } // compare retrieved and expected spans if !test.span.Equal(spanToCheck) { t.Errorf("Error on DB.Insert(), database did not respond with expected number of results after insert -\nexpected:\n%+v\ngot:\n%+v\n", test.span, spanToCheck) } } }
// test getting data after DB.Insert(), same as above but we use the GetRange() // method where we talked directly to the database before func TestGetRange(t *testing.T) { var tests = []struct { symbol string span stock.Span }{ {"GOOG", testSpan1}, } // create test db connection tdb := stock.DB.Setup(stock.TestLocal) // record the changes we make so they can be reversed, all measures in span will be inserted td := testhelpers.TearDown{} for _, test := range tests { td = td.TrackSpanInsert(test.symbol, &test.span, tdb, t) } defer func() { err := td.TearDown(tdb, t) if err != nil { t.Error(err) } }() for _, test := range tests { s := stock.NewStock(test.symbol) // do the DB.Insert() err := tdb.Insert(s, &test.span) if err != nil { t.Error(err) } // now get the range we just inserted sort.Sort(testSpan1) startDate := testSpan1[0].Time endDate := testSpan1[len(testSpan1)-1].Time span, err := tdb.GetRange(s, startDate, endDate) if err != nil { t.Error(err) } // compare retrieved and expected spans if !test.span.Equal(span) { t.Errorf("Error on DB.GetRange(), database did not respond with expected number of results after insert -\nexpected:\n%+v\ngot:\n%+v\n", test.span, span) } } }
func TestStockConstruction(t *testing.T) { t.Parallel() var tests = []struct { sym string }{ {"GOOG"}, {"AAPL"}, {"FB"}, {"AMZN"}, {"MSFT"}, } for _, test := range tests { stock := stock.NewStock(test.sym) if stock.Symbol != test.sym { t.Errorf("Improperly constructed stock: %+v vs %+v", stock, test) } } }
// ensure the responses returned from Markit are in the expected format func TestMarkitChartAPIResponse(t *testing.T) { t.Skip("Skipping MarkitChartAPI confirmation to avoid network delays") for _, test := range testhelpers.MarkitTestData { request, err := stock.NewMarkitChartAPIRequest( stock.NewStock(test.Sym), test.StartDate, test.EndDate) if err != nil { t.Errorf("Could not create a MarkitChartAPIRequest: %v", err) } time.Sleep(1500 * time.Millisecond) // don't overload the Markit server // don't use request.Request() so that we can look at the response body r, err := http.Get(request.Url) if err != nil { t.Errorf("Request to MarkitChartAPI failed: %v", err) } defer r.Body.Close() if r.StatusCode != http.StatusOK { t.Errorf("Request to MarkitChartAPI failed (Status-%d)", r.StatusCode) } // compare the response body to the expected value contents, err := ioutil.ReadAll(r.Body) if err != nil { t.Errorf("Could not validate MarkitChartAPI response body: %v", err) } if string(contents) != test.ExpectedResponseBody { t.Errorf("Formatting change in MarkitResponse expected:\n%s\ngot:\n%s\n", test.ExpectedResponseBody, string(contents)) } t.Logf("Test complete: %s, %s to %s", test.Sym, test.StartDate.String(), test.EndDate.String()) } }
func TestGetStockIntegration(t *testing.T) { // start a new server so we can access it's ServeHTTP method trueVal := true ts := NewTrendyServer(Flags{Local: &trueVal}) // test has db impact, setup test db tdb := stock.DB.Setup(stock.TestLocal) // run default test set for Markit testdata := testhelpers.MarkitTestData for _, test := range testdata { // .../stock/<test.Sym>?start=<test.StartDate>&end=<test.EndDate>, dates as YYYY-MM-DD path := strings.Join([]string{`/stock/`, test.Sym, `?start=`, test.StartDate.Format("2006-01-02"), `&end=`, test.EndDate.Format("2006-01-02")}, "") t.Logf("path: `%s`\n", path) // first try without auth parameters, this should be rejected r, _ := http.NewRequest("GET", path, nil) w := httptest.NewRecorder() ts.ServeHTTP(w, r) b := w.Body.String() if w.Code != http.StatusUnauthorized || !strings.Contains(b, "No Key Or Secret") { t.Errorf("Attempted access without key/secret succeeded. Invalid access granted.\n>> Status:%d for %s", w.Code, path) } // try request again with key and secret set correctly r, _ = http.NewRequest("GET", path, nil) r.Header.Set("X-Auth-Key", "key") r.Header.Set("X-Auth-Secret", "secret") w = httptest.NewRecorder() ts.ServeHTTP(w, r) if !test.ExpectError { // expect success if w.Code != http.StatusOK { t.Errorf("Attempted access with key/secret but failed, expected success.\n>> Status:%d for %s", w.Code, path) } // record the changes we make so they can be reversed, all measures in span will be inserted td := testhelpers.TearDown{} expectedSpan := test.ExpectedMarkitResponse.GetSpan() td = td.TrackSpanInsert(test.Sym, &expectedSpan, tdb, t) expectedStock := stock.NewStock(test.Sym) expectedStock.Span = expectedSpan expectedJson, err := json.Marshal(expectedStock) if err != nil { t.Errorf("Error generating JSON response for expected stock [%s]", test.Sym) } expectedStr := strings.Replace(string(expectedJson), "T12:", "T00:", -1) // expectation is at T12, returned at T00, this is a quick hacky fix if b = w.Body.String(); b != expectedStr { t.Errorf("(%d) Got unexpected response from server, expected:\n%s\ngot:\n%s\n", w.Code, expectedJson, b) } // teardown changes err = td.TearDown(tdb, t) if err != nil { t.Error(err) } } else { // expect error if w.Code == http.StatusOK { t.Errorf("Attempted access expecting failure but got success.\n>> Status:%d for %s", w.Code, path) } } } }
func TestRangeIntegration(t *testing.T) { // test has db impact, setup test db tdb := stock.DB.Setup(stock.TestLocal) // run default test set for Markit testdata := testhelpers.MarkitTestData for _, test := range testdata { s := stock.NewStock(test.Sym) // initialize a request to get the URL so that we can inform the test server // of the target url, this request is not used otherwise. unusedRequest, err := stock.NewMarkitChartAPIRequest(s, test.StartDate, test.EndDate) if err != nil { t.Errorf("Could not create a MarkitChartAPIRequest: %v", err) } targetUrl := unusedRequest.Url // save the targetUrl for the request // start test server with success status tsParams := testhelpers.TestServer{ Status: http.StatusOK, RequestUrl: targetUrl, TestData: testdata, T: t, } ts := httptest.NewServer(&tsParams) // make sure database and memory are empty for stock checkMemoryAndDatabase(s, &stock.Span{}, tdb, t) // test five most common error responses var errorCodes = []int{500, 404, 403, 400, 401} for _, errorCode := range errorCodes { tsParams = testhelpers.TestServer{ Status: errorCode, RequestUrl: targetUrl, TestData: testdata, T: t, } span, err := s.ActualRange(test.StartDate, test.EndDate, ts.URL) if err == nil || len(span) > 0 { t.Errorf("Expected an error but got success: %+v\n", span) } } // make sure database and memory are still empty checkMemoryAndDatabase(s, &stock.Span{}, tdb, t) // change server to success status tsParams = testhelpers.TestServer{ Status: http.StatusOK, RequestUrl: targetUrl, TestData: testdata, T: t, } // get the span here span, err := s.ActualRange(test.StartDate, test.EndDate, ts.URL) if test.ExpectError { if err == nil { t.Errorf("Expected error but got success") } else { // checkMemoryAndDatabase are empty and then continue, no teardown checkMemoryAndDatabase(s, &stock.Span{}, tdb, t) t.Logf("Test complete: %s, %s to %s", test.Sym, test.StartDate.String(), test.EndDate.String()) continue } } else if err != nil { t.Error(err) } // record the changes we make so they can be reversed, all measures in span will be inserted td := testhelpers.TearDown{} td = td.TrackSpanInsert(s.Symbol, &span, tdb, t) // ensure that the returned span equals the expected expectedSpan := test.ExpectedMarkitResponse.GetSpan() if !span.Equal(expectedSpan) { t.Errorf("Error - stock.Range() did not return expected span\nexpected:\n%+v\ngot:\n%+v\n", expectedSpan, span) } // make sure database and memory also reflect the expected checkMemoryAndDatabase(s, &expectedSpan, tdb, t) // teardown changes (not deferred because we want to do for each loop - not sure that's necessary though) err = td.TearDown(tdb, t) if err != nil { t.Error(err) } t.Logf("Test complete: %s, %s to %s", test.Sym, test.StartDate.String(), test.EndDate.String()) } }