func TestControllerEngineUnavailable(t *testing.T) { c := core.NewTestConfig(t) c.IbGws = []string{"127.0.0.0:0000"} ctx, err := core.NewContext(c) if err != nil { t.Fatal(err) } defer ctx.Close() tcff := NewTestControllerFeedFactory(func(ctf *TestControllerFeed) { t.Fatal("Should never have opened feed") }) ffs := []FeedFactory{tcff} gatewayController, err := NewGatewayController(ffs, ctx.DB, ctx.N, ctx.DL, c.IbGws, c.IbClientId) if err != nil { t.Fatal(err) } defer gatewayController.Close() failAt := time.Now().Add(1 * time.Second) for gatewayController.Restarts() <= 5 { if time.Now().After(failAt) { t.Fatal("GatewayController failed to restart before timeout") } } }
func TestAccountHandlerGetAllRefresh(t *testing.T) { ctx, handler := NewTestHandler(t) defer ctx.Close() c := core.NewTestConfig(t) var ff gateway.FeedFactory = &gateway.AccountFeedFactory{AccountRefresh: c.AccountRefresh} WaitForFeed(t, ctx, &ff, 15*time.Second) nc := make(chan *core.Notification) ctx.N.Subscribe(nc) defer ctx.N.Unsubscribe(nc) go func() { req := test.MakeSimpleRequest("GET", "http://1.2.3.4/v1/accounts", nil) req.Header.Add("Cache-Control", "private; max-age=0") test.RunRequest(t, handler, req) // NB: This request will not return data, as there's no feed running. // Long timeouts avoided as the ctx.Close() closes the Notifier, // which in turn closes the RefreshIfNeeded listener. }() outer: for { select { case msg := <-nc: if msg.Type == core.NtAccountRefresh { // controller requested an account refresh, like it should have break outer } case <-time.After(15 * time.Second): t.Fatal("controller didn't request update before timeout") } } }
func TestServiceCloseCanExecuteTwiceWithoutIssues(t *testing.T) { c := core.NewTestConfig(t) ctx, err := core.NewContext(c) if err != nil { t.Fatal(err) } defer ctx.Close() terminate := make(chan struct{}) errs := make(chan GatewayError) go func() { for { select { case <-errs: case <-terminate: return } } }() ffs := FeedFactories(c) ibGw := "127.0.0.0:0123" service := NewGatewayService(errs, ffs, ctx.DB, ctx.N, ibGw, c.IbClientId) service.Close() service.Close() close(terminate) }
// NewTestFeedContext provides a simple way of producing a FeedContext for tests. func NewTestFeedContext(t *testing.T) *TestFeedContext { c := core.NewTestConfig(t) ctx, err := core.NewContext(c) if err != nil { t.Fatal(err) } engine, err := ib.NewEngine(ib.NewEngineOptions{Gateway: c.IbGws[0]}) if err != nil { t.Fatal(err) } fc := &FeedContext{ Errors: make(chan FeedError), DB: ctx.DB, N: ctx.N, Eng: engine, } return &TestFeedContext{ ctx: ctx, FC: fc, } }
func TestAccountHandlerGetAll(t *testing.T) { ctx, handler := NewTestHandler(t) defer ctx.Close() c := core.NewTestConfig(t) var ff gateway.FeedFactory = &gateway.AccountFeedFactory{AccountRefresh: c.AccountRefresh} WaitForFeed(t, ctx, &ff, 15*time.Second) recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://1.2.3.4/v1/accounts", nil)) recorded.CodeIs(http.StatusOK) recorded.ContentTypeIsJson() recorded.HeaderIs("Cache-Control", "private, max-age=60") }
// runGatewayController executes the GatewayController, expecting the // TestControllerFeed to be created and closed the specified number of times // prior to the GatewayController being closed. func runGatewayController(t *testing.T, tcff *TestControllerFeedFactory, expectedOpens int, expectedCloses int) { c := core.NewTestConfig(t) ctx, err := core.NewContext(c) if err != nil { t.Fatal(err) } defer ctx.Close() ffs := []FeedFactory{tcff} gatewayController, err := NewGatewayController(ffs, ctx.DB, ctx.N, ctx.DL, c.IbGws, c.IbClientId) if err != nil { t.Fatal(err) } defer gatewayController.Close() terminating := false for { select { case ct := <-tcff.openClose: if ct[0] < expectedOpens { continue } if ct[1] < expectedCloses { continue } if !terminating && ct[0] > expectedOpens { t.Fatalf("too many opens (saw %d, expected %d)", ct[0], expectedOpens) } if !terminating && ct[1] > expectedCloses { t.Fatalf("too many closes (saw %d, expected %d)", ct[1], expectedCloses) } if !terminating { terminating = true gatewayController.Close() } if ct[0] == ct[1] { // enough events seen, and everything closed return } case <-time.After(1 * time.Second): t.Fatalf("timeout after %d opens (expected %d) and %d closes (expected %dd)", tcff.opened, expectedOpens, tcff.closed, expectedCloses) return } } }
// runGenericFeedTest returns any error reported to the error channel. It fails // the test if the expected count is not reached within one second of loading. func runGenericFeedTest(t *testing.T, fun func(*FeedContext), cronRefresh *cronexpr.Expression, waitTime time.Duration, expectedCount int) error { c := core.NewTestConfig(t) ctx, err := core.NewContext(c) if err != nil { t.Fatal(err) } defer ctx.Close() errors := make(chan FeedError) var lastError error terminateErrors := make(chan struct{}) defer close(terminateErrors) go func() { for { select { case e := <-errors: lastError = e.Error case <-terminateErrors: return } } }() var engine *ib.Engine fc := &FeedContext{errors, ctx.DB, ctx.N, engine} gft := newTestGenericFeed(t, fc, fun, cronRefresh) defer gft.Close() killAt := time.Now().Add(waitTime) for gft.counter < expectedCount { if lastError != nil { return lastError } if time.Now().After(killAt) { t.Fatal("Insufficient callbacks (%d) before timeout", gft.counter) } } gft.Close() return lastError }
func TestErrorHandlerInternalServerError(t *testing.T) { c := core.NewTestConfig(t) ctx, err := core.NewContext(c) if err != nil { t.Fatal(err) } defer ctx.Close() handler := Handler(true, ctx.DB, ctx.N) var ff gateway.FeedFactory = &gateway.AccountFeedFactory{AccountRefresh: c.AccountRefresh} WaitForFeed(t, ctx, &ff, 5*time.Second) ctx.DB.Close() // this will cause an internal server error recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://1.2.3.4/v1/accounts", nil)) recorded.CodeIs(http.StatusInternalServerError) recorded.ContentTypeIsJson() }
func TestAccountHandlerGetLatest(t *testing.T) { ctx, handler := NewTestHandler(t) defer ctx.Close() c := core.NewTestConfig(t) var ff gateway.FeedFactory = &gateway.AccountFeedFactory{AccountRefresh: c.AccountRefresh} WaitForFeed(t, ctx, &ff, 15*time.Second) accountCode := "" row := ctx.DB.QueryRow("SELECT account_code FROM account LIMIT 1") if err := row.Scan(&accountCode); err != nil { t.Fatal(err) } url := fmt.Sprintf("http://1.2.3.4/v1/accounts/%s", accountCode) recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", url, nil)) recorded.CodeIs(http.StatusSeeOther) target := recorded.Recorder.Header().Get("Location") recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", target, nil)) recorded.CodeIs(http.StatusOK) recorded.ContentTypeIsJson() recorded.HeaderIs("Cache-Control", "private, max-age=31556926") }
func TestAccountFeedInsertsDataOnStartup(t *testing.T) { c := core.NewTestConfig(t) var ff FeedFactory = &AccountFeedFactory{c.AccountRefresh} TestSimpleFeedInsertsDataOnStartup(t, &ff, "account_snapshot", 15*time.Second) }
func TestAccountFeedPublishesDoneMessage(t *testing.T) { c := core.NewTestConfig(t) var ff FeedFactory = &AccountFeedFactory{c.AccountRefresh} TestSimpleFeedPublishesDoneMessage(t, &ff, 15*time.Second) }
func TestAccountFeedHandlesNoEngine(t *testing.T) { c := core.NewTestConfig(t) var ff FeedFactory = &AccountFeedFactory{c.AccountRefresh} TestSimpleFeedHandlesNoEngine(t, &ff) }
func TestAccountFeedHandlesEngineTermination(t *testing.T) { c := core.NewTestConfig(t) var ff FeedFactory = &AccountFeedFactory{c.AccountRefresh} TestSimpleFeedHandlesEngineTermination(t, &ff, 15*time.Second) }