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) } } }
// Confirm that DB.Setup completes with a functioning db and tables to populate func TestSetup(t *testing.T) { var tests = []struct { table string // the name for each table that should be created in Setup }{ {"measures"}, } // test that a new db can be created, panics if fails tdb := stock.DB.Setup(stock.TestLocal) // record the changes we make so they can be reversed td := testhelpers.TearDown{} for _, test := range tests { td = append(td, (testhelpers.Change{Table: test.table, Action: testhelpers.CREATE})) } defer func() { err := td.TearDown(tdb, t) if err != nil { t.Error(err) } }() // and ensure it has all the tables that we expect for _, test := range tests { testQuery := strings.Join([]string{"SELECT * FROM ", test.table}, "") rows, err := tdb.Query(testQuery) if err != nil { // if the table does not exist we'll get an error t.Error(err) } else { // we'll get rows if the table exists, but won't be able to access any data hasNext := rows.Next() if hasNext { // if we have data something is wrong t.Errorf("Expected empty table but got results with query `%s`", testQuery) } } } }
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()) } }