Ejemplo n.º 1
0
func TestFinder(t *testing.T) {

	Convey("Finder", t, func() {
		test.LoadScenario("paths")
		conn := test.OpenDatabase(test.StellarCoreDatabaseUrl())
		defer conn.Close()

		finder := &Finder{
			Ctx:      test.Context(),
			SqlQuery: db.SqlQuery{conn},
		}

		native := makeAsset(xdr.AssetTypeAssetTypeNative, "", "")
		usd := makeAsset(
			xdr.AssetTypeAssetTypeCreditAlphanum4,
			"USD",
			"GDSBCQO34HWPGUGQSP3QBFEXVTSR2PW46UIGTHVWGWJGQKH3AFNHXHXN")
		eur := makeAsset(
			xdr.AssetTypeAssetTypeCreditAlphanum4,
			"EUR",
			"GDSBCQO34HWPGUGQSP3QBFEXVTSR2PW46UIGTHVWGWJGQKH3AFNHXHXN")

		Convey("Find", func() {
			query := paths.Query{
				DestinationAddress: "GAEDTJ4PPEFVW5XV2S7LUXBEHNQMX5Q2GM562RJGOQG7GVCE5H3HIB4V",
				DestinationAsset:   eur,
				DestinationAmount:  xdr.Int64(200000000),
				SourceAssets:       []xdr.Asset{usd},
			}

			paths, err := finder.Find(query)
			So(err, ShouldBeNil)
			So(len(paths), ShouldEqual, 4)

			query.DestinationAmount = xdr.Int64(200000001)
			paths, err = finder.Find(query)
			So(err, ShouldBeNil)
			So(len(paths), ShouldEqual, 2)

			query.DestinationAmount = xdr.Int64(500000001)
			paths, err = finder.Find(query)
			So(err, ShouldBeNil)
			So(len(paths), ShouldEqual, 0)
		})

		Convey("regression: paths that involve native currencies can be found", func() {

			query := paths.Query{
				DestinationAddress: "GDSBCQO34HWPGUGQSP3QBFEXVTSR2PW46UIGTHVWGWJGQKH3AFNHXHXN",
				DestinationAsset:   native,
				DestinationAmount:  xdr.Int64(1),
				SourceAssets:       []xdr.Asset{usd, native},
			}

			paths, err := finder.Find(query)
			So(err, ShouldBeNil)
			So(len(paths), ShouldEqual, 2)
		})
	})
}
Ejemplo n.º 2
0
func TestQueue(t *testing.T) {
	ctx := test.Context()
	_ = ctx
	Convey("Queue", t, func() {
		queue := NewQueue()

		Convey("Push adds the provided channel on to the priority queue", func() {
			So(queue.Size(), ShouldEqual, 0)

			queue.Push(2)
			So(queue.Size(), ShouldEqual, 1)
			_, s := queue.head()
			So(s, ShouldEqual, 2)

			queue.Push(1)
			So(queue.Size(), ShouldEqual, 2)
			_, s = queue.head()
			So(s, ShouldEqual, 1)
		})

		Convey("Update removes sequences that are submittable or in the past", func() {
			results := []<-chan error{
				queue.Push(1),
				queue.Push(2),
				queue.Push(3),
				queue.Push(4),
			}

			queue.Update(2)

			// the update above signifies that 2 is the accounts current sequence,
			// meaning that 3 is submittable, and so only 4 should still be queued
			So(queue.Size(), ShouldEqual, 1)
			_, s := queue.head()
			So(s, ShouldEqual, 4)

			queue.Update(4)
			So(queue.Size(), ShouldEqual, 0)

			So(<-results[0], ShouldEqual, ErrBadSequence)
			So(<-results[1], ShouldEqual, ErrBadSequence)
			So(<-results[2], ShouldEqual, nil)
			So(<-results[3], ShouldEqual, ErrBadSequence)

		})

		Convey("Update clears the queue if the head has not been released within the time limit", func() {
			queue.timeout = 1 * time.Millisecond
			result := queue.Push(2)
			<-time.After(10 * time.Millisecond)
			queue.Update(0)

			So(queue.Size(), ShouldEqual, 0)
			So(<-result, ShouldEqual, ErrBadSequence)
		})
	})
}
Ejemplo n.º 3
0
func TestMain(m *testing.M) {
	ctx = test.Context()
	core = OpenStellarCoreTestDatabase()
	history = OpenTestDatabase()
	defer core.Close()
	defer history.Close()

	os.Exit(m.Run())

}
Ejemplo n.º 4
0
func TestStreaming(t *testing.T) {
	ctx := test.Context()
	ctx, cancel := context.WithCancel(ctx)
	db := test.OpenDatabase(test.DatabaseUrl())

	Convey("LedgerClosePump", t, func() {

		Convey("can cancel", func() {
			pump := NewLedgerClosePump(ctx, db)
			cancel()
			_, more := <-pump
			So(more, ShouldBeFalse)
		})
	})
}
Ejemplo n.º 5
0
func TestLedgerState(t *testing.T) {
	test.LoadScenario("base")
	horizon := OpenTestDatabase()
	defer horizon.Close()
	core := OpenStellarCoreTestDatabase()
	defer core.Close()

	Convey("db.UpdateLedgerState", t, func() {
		So(horizonLedgerGauge.Value(), ShouldEqual, 0)
		So(stellarCoreLedgerGauge.Value(), ShouldEqual, 0)

		UpdateLedgerState(test.Context(), SqlQuery{horizon}, SqlQuery{core})

		So(horizonLedgerGauge.Value(), ShouldEqual, 3)
		So(stellarCoreLedgerGauge.Value(), ShouldEqual, 3)
	})
}
Ejemplo n.º 6
0
func ShouldBeProblem(a interface{}, options ...interface{}) string {
	body := a.(*bytes.Buffer)
	expected := options[0].(problem.P)

	problem.Inflate(test.Context(), &expected)

	var actual problem.P
	err := json.Unmarshal(body.Bytes(), &actual)

	if err != nil {
		return fmt.Sprintf("Could not unmarshal json into problem struct:\n%s\n", body.String())
	}

	if expected.Type != "" && actual.Type != expected.Type {
		return fmt.Sprintf("Mismatched problem type: %s expected, got %s", expected.Type, actual.Type)
	}

	if expected.Status != 0 && actual.Status != expected.Status {
		return fmt.Sprintf("Mismatched problem status: %s expected, got %s", expected.Status, actual.Status)
	}

	return ""
}
Ejemplo n.º 7
0
func TestApp(t *testing.T) {
	Convey("NewApp establishes the app in its context", t, func() {
		app, err := NewApp(NewTestConfig())
		So(err, ShouldBeNil)
		defer app.Close()

		found, ok := AppFromContext(app.ctx)
		So(ok, ShouldBeTrue)
		So(found, ShouldEqual, app)
	})

	Convey("NewApp panics if the provided config's SentryDSN is invalid", t, func() {
		config := NewTestConfig()
		config.SentryDSN = "Not a url"

		So(func() {
			app, _ := NewApp(config)
			app.Close()
		}, ShouldPanic)
	})

	Convey("CORS support", t, func() {
		app := NewTestApp()
		defer app.Close()
		rh := NewRequestHelper(app)

		w := rh.Get("/", test.RequestHelperNoop)

		So(w.Code, ShouldEqual, 200)
		So(w.HeaderMap.Get("Access-Control-Allow-Origin"), ShouldEqual, "")

		w = rh.Get("/", func(r *http.Request) {
			r.Header.Set("Origin", "somewhere.com")
		})

		So(w.Code, ShouldEqual, 200)
		So(w.HeaderMap.Get("Access-Control-Allow-Origin"), ShouldEqual, "somewhere.com")

	})

	Convey("Trailing slash causes redirect", t, func() {
		test.LoadScenario("base")
		app := NewTestApp()
		defer app.Close()
		rh := NewRequestHelper(app)

		w := rh.Get("/accounts", test.RequestHelperNoop)
		So(w.Code, ShouldEqual, 200)

		w = rh.Get("/accounts/", test.RequestHelperNoop)
		So(w.Code, ShouldEqual, 200)

	})

	Convey("app.UpdateMetrics", t, func() {
		test.LoadScenario("base")
		app := NewTestApp()
		defer app.Close()
		So(app.horizonLedgerGauge.Value(), ShouldEqual, 0)
		So(app.stellarCoreLedgerGauge.Value(), ShouldEqual, 0)

		app.UpdateMetrics(test.Context())

		So(app.horizonLedgerGauge.Value(), ShouldEqual, 3)
		So(app.stellarCoreLedgerGauge.Value(), ShouldEqual, 3)
	})
}
Ejemplo n.º 8
0
func TestDefaultSubmitter(t *testing.T) {
	ctx := test.Context()

	Convey("submitter (The default Submitter implementation)", t, func() {

		Convey("submits to the configured stellar-core instance correctly", func() {
			server := test.NewStaticMockServer(`{
				"status": "PENDING",
				"error": null
				}`)
			defer server.Close()

			s := NewDefaultSubmitter(http.DefaultClient, server.URL)
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldBeNil)
			So(sr.Duration, ShouldBeGreaterThan, 0)
			So(server.LastRequest.URL.Query().Get("blob"), ShouldEqual, "hello")
		})

		Convey("succeeds when the stellar-core responds with DUPLICATE status", func() {
			server := test.NewStaticMockServer(`{
				"status": "DUPLICATE",
				"error": null
				}`)
			defer server.Close()

			s := NewDefaultSubmitter(http.DefaultClient, server.URL)
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldBeNil)
		})

		Convey("errors when the stellar-core url is empty", func() {
			s := NewDefaultSubmitter(http.DefaultClient, "")
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldNotBeNil)
		})

		Convey("errors when the stellar-core url is not parseable", func() {
			s := NewDefaultSubmitter(http.DefaultClient, "http://Not a url")
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldNotBeNil)
		})

		Convey("errors when the stellar-core url is not reachable", func() {
			s := NewDefaultSubmitter(http.DefaultClient, "http://127.0.0.1:65535")
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldNotBeNil)
		})

		Convey("errors when the stellar-core returns an unparseable response", func() {
			server := test.NewStaticMockServer(`{`)
			defer server.Close()

			s := NewDefaultSubmitter(http.DefaultClient, server.URL)
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldNotBeNil)
		})

		Convey("errors when the stellar-core returns an exception response", func() {
			server := test.NewStaticMockServer(`{"exception": "Invalid XDR"}`)
			defer server.Close()

			s := NewDefaultSubmitter(http.DefaultClient, server.URL)
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldNotBeNil)
			So(sr.Err.Error(), ShouldContainSubstring, "Invalid XDR")
		})

		Convey("errors when the stellar-core returns an unrecognized status", func() {
			server := test.NewStaticMockServer(`{"status": "NOTREAL"}`)
			defer server.Close()

			s := NewDefaultSubmitter(http.DefaultClient, server.URL)
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldNotBeNil)
			So(sr.Err.Error(), ShouldContainSubstring, "NOTREAL")
		})

		Convey("errors when the stellar-core returns an error response", func() {
			server := test.NewStaticMockServer(`{"status": "ERROR", "error": "1234"}`)
			defer server.Close()

			s := NewDefaultSubmitter(http.DefaultClient, server.URL)
			sr := s.Submit(ctx, "hello")
			So(sr.Err, ShouldHaveSameTypeAs, &FailedTransactionError{})
			ferr := sr.Err.(*FailedTransactionError)
			So(ferr.ResultXDR, ShouldEqual, "1234")
		})
	})
}
Ejemplo n.º 9
0
func TestDefaultSubmissionList(t *testing.T) {
	ctx := test.Context()

	Convey("submissionList (The default OpenSubmissionList implementation)", t, func() {
		list := NewDefaultSubmissionList()
		realList := list.(*submissionList)
		hashes := []string{
			"0000000000000000000000000000000000000000000000000000000000000000",
			"0000000000000000000000000000000000000000000000000000000000000001",
		}

		listeners := []chan Result{
			make(chan Result, 1),
			make(chan Result, 1),
		}

		Convey("Add()", func() {
			Convey("adds an entry to the submission list when a new hash is used", func() {
				list.Add(ctx, hashes[0], listeners[0])
				sub := realList.submissions[hashes[0]]
				So(sub.Hash, ShouldEqual, hashes[0])
				So(sub.SubmittedAt, ShouldHappenWithin, 1*time.Second, time.Now())

				// drop the send side of the channel by casting to listener
				var l Listener = listeners[0]
				So(sub.Listeners[0], ShouldEqual, l)
			})

			Convey("adds an listener to an existing entry when a hash is used with a new listener", func() {
				list.Add(ctx, hashes[0], listeners[0])
				sub := realList.submissions[hashes[0]]
				st := sub.SubmittedAt
				<-time.After(20 * time.Millisecond)
				list.Add(ctx, hashes[0], listeners[1])

				// increases the size of the listener
				So(len(sub.Listeners), ShouldEqual, 2)
				// doesn't update the submitted at time
				So(st == sub.SubmittedAt, ShouldEqual, true)
			})

			Convey("panics when the listener is not buffered", func() {
				So(func() { list.Add(ctx, hashes[0], make(Listener)) }, ShouldPanic)
			})

			Convey("errors when the provided hash is not 64-bytes", func() {
				err := list.Add(ctx, "123", listeners[0])
				So(err, ShouldNotBeNil)
			})
		})

		Convey("Finish()", func() {
			list.Add(ctx, hashes[0], listeners[0])
			list.Add(ctx, hashes[0], listeners[1])
			r := Result{
				Hash: hashes[0],
			}
			list.Finish(ctx, r)

			Convey("writes to every listener", func() {
				r1, ok1 := <-listeners[0]
				So(r1, ShouldResemble, r)
				So(ok1, ShouldBeTrue)

				r2, ok2 := <-listeners[1]
				So(r2, ShouldResemble, r)
				So(ok2, ShouldBeTrue)
			})

			Convey("removes the entry", func() {
				_, ok := realList.submissions[hashes[0]]
				So(ok, ShouldBeFalse)
			})

			Convey("closes every listener", func() {
				_, _ = <-listeners[0]
				_, more := <-listeners[0]
				So(more, ShouldBeFalse)

				_, _ = <-listeners[1]
				_, more = <-listeners[1]
				So(more, ShouldBeFalse)
			})

			Convey("works when the noone is waiting for the result", func() {
				err := list.Finish(ctx, r)
				So(err, ShouldBeNil)
			})

		})

		Convey("Clean()", func() {
			list.Add(ctx, hashes[0], listeners[0])
			<-time.After(200 * time.Millisecond)
			list.Add(ctx, hashes[1], listeners[1])
			left, err := list.Clean(ctx, 200*time.Millisecond)

			So(err, ShouldBeNil)
			So(left, ShouldEqual, 1)

			Convey("removes submissions older than the maxAge provided", func() {
				_, ok := realList.submissions[hashes[0]]
				So(ok, ShouldBeFalse)
			})

			Convey("leaves submissions that are younger than the maxAge provided", func() {
				_, ok := realList.submissions[hashes[1]]
				So(ok, ShouldBeTrue)
			})

			Convey("closes any cleaned listeners", func() {
				select {
				case _, stillOpen := <-listeners[0]:
					So(stillOpen, ShouldBeFalse)
				default:
					panic("cleaned listener is still open")
				}
			})
		})

		Convey("Pending() works as expected", func() {
			So(len(list.Pending(ctx)), ShouldEqual, 0)
			list.Add(ctx, hashes[0], listeners[0])
			So(len(list.Pending(ctx)), ShouldEqual, 1)
			list.Add(ctx, hashes[1], listeners[1])
			So(len(list.Pending(ctx)), ShouldEqual, 2)
		})
	})
}
Ejemplo n.º 10
0
func TestHelpers(t *testing.T) {
	Convey("Action Helpers", t, func() {
		r, _ := http.NewRequest("GET", "/?limit=2&cursor=hello", nil)

		action := &Base{
			Ctx: test.Context(),
			GojiCtx: web.C{
				URLParams: map[string]string{
					"blank":       "",
					"zero":        "0",
					"two":         "2",
					"32min":       fmt.Sprint(math.MinInt32),
					"32max":       fmt.Sprint(math.MaxInt32),
					"64min":       fmt.Sprint(math.MinInt64),
					"64max":       fmt.Sprint(math.MaxInt64),
					"native_type": "native",
					"4_type":      "credit_alphanum4",
					"12_type":     "credit_alphanum12",
				},
				Env: map[interface{}]interface{}{},
			},
			R: r,
		}

		Convey("GetInt32", func() {
			result := action.GetInt32("blank")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 0)

			result = action.GetInt32("zero")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 0)

			result = action.GetInt32("two")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 2)

			result = action.GetInt32("32max")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, math.MaxInt32)

			result = action.GetInt32("32min")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, math.MinInt32)

			result = action.GetInt32("limit")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 2)

			result = action.GetInt32("64max")
			So(action.Err, ShouldNotBeNil)

			result = action.GetInt32("64min")
			So(action.Err, ShouldNotBeNil)

		})

		Convey("GetInt64", func() {
			result := action.GetInt64("blank")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 0)

			result = action.GetInt64("zero")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 0)

			result = action.GetInt64("two")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 2)

			result = action.GetInt64("64max")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, math.MaxInt64)

			result = action.GetInt64("64min")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, math.MinInt64)
		})

		Convey("GetPagingParams", func() {
			cursor, order, limit := action.GetPagingParams()
			So(cursor, ShouldEqual, "hello")
			So(limit, ShouldEqual, 2)
			So(order, ShouldEqual, "")
		})

		Convey("GetAssetType", func() {
			t := action.GetAssetType("native_type")
			So(t, ShouldEqual, xdr.AssetTypeAssetTypeNative)

			t = action.GetAssetType("4_type")
			So(t, ShouldEqual, xdr.AssetTypeAssetTypeCreditAlphanum4)

			t = action.GetAssetType("12_type")
			So(t, ShouldEqual, xdr.AssetTypeAssetTypeCreditAlphanum12)

			So(action.Err, ShouldBeNil)
			action.GetAssetType("cursor")
			So(action.Err, ShouldNotBeNil)
		})

		Convey("Last-Event-ID overrides cursor", func() {
			action.R.Header.Set("Last-Event-ID", "from_header")
			cursor, _, _ := action.GetPagingParams()
			So(cursor, ShouldEqual, "from_header")
		})

		Convey("Form values override query values", func() {
			So(action.GetString("cursor"), ShouldEqual, "hello")

			action.R.Form = url.Values{
				"cursor": {"goodbye"},
			}
			So(action.GetString("cursor"), ShouldEqual, "goodbye")
		})

		Convey("regression: GetPagQuery does not overwrite err", func() {
			r, _ := http.NewRequest("GET", "/?limit=foo", nil)
			action.R = r
			_, _, _ = action.GetPagingParams()

			So(action.Err, ShouldNotBeNil)
			_ = action.GetPageQuery()
			So(action.Err, ShouldNotBeNil)
		})

		Convey("Path() return the action's http path", func() {
			r, _ := http.NewRequest("GET", "/foo-bar/blah?limit=foo", nil)
			action.R = r
			So(action.Path(), ShouldEqual, "/foo-bar/blah")
		})
	})
}
Ejemplo n.º 11
0
func TestTxsub(t *testing.T) {
	Convey("txsub.System", t, func() {
		ctx := test.Context()
		submitter := &MockSubmitter{}
		results := &MockResultProvider{}

		system := &System{
			Pending:           NewDefaultSubmissionList(),
			Submitter:         submitter,
			Results:           results,
			NetworkPassphrase: build.TestNetwork.Passphrase,
		}

		noResults := Result{Err: ErrNoResults}
		successTx := Result{
			Hash:           "c492d87c4642815dfb3c7dcce01af4effd162b031064098a0d786b6e0a00fd74",
			LedgerSequence: 2,
			EnvelopeXDR:    "AAAAAGL8HQvQkbK2HA3WVjRrKmjX00fG8sLI7m0ERwJW/AX3AAAACgAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAArqN6LeOagjxMaUP96Bzfs9e0corNZXzBWJkFoK7kvkwAAAAAO5rKAAAAAAAAAAABVvwF9wAAAEAKZ7IPj/46PuWU6ZOtyMosctNAkXRNX9WCAI5RnfRk+AyxDLoDZP/9l3NvsxQtWj9juQOuoBlFLnWu8intgxQA",
			ResultXDR:      "xJLYfEZCgV37PH3M4Br07/0WKwMQZAmKDXhrbgoA/XQAAAAAAAAACgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA==",
		}

		badSeq := SubmissionResult{
			Err: &FailedTransactionError{"AAAAAAAAAAD////7AAAAAA=="},
		}

		Convey("Submit", func() {
			Convey("returns the result provided by the ResultProvider", func() {
				results.Results = []Result{successTx}
				r := <-system.Submit(ctx, successTx.EnvelopeXDR)

				So(r.Err, ShouldBeNil)
				So(r.Hash, ShouldEqual, successTx.Hash)
				So(submitter.WasSubmittedTo, ShouldBeFalse)
			})

			Convey("returns the error from submission if no result is found by hash and the submitter returns an error", func() {
				submitter.R.Err = errors.New("busted for some reason")
				r := <-system.Submit(ctx, successTx.EnvelopeXDR)

				So(r.Err, ShouldNotBeNil)
				So(submitter.WasSubmittedTo, ShouldBeTrue)
				So(system.Metrics.SuccessfulSubmissionsMeter.Count(), ShouldEqual, 0)
				So(system.Metrics.FailedSubmissionsMeter.Count(), ShouldEqual, 1)
				So(system.Metrics.SubmissionTimer.Count(), ShouldEqual, 1)
			})

			Convey("if the error is bad_seq and the result at the transaction's sequence number is for the same hash, return result", func() {
				submitter.R = badSeq
				results.Results = []Result{noResults, successTx}

				r := <-system.Submit(ctx, successTx.EnvelopeXDR)

				So(r.Err, ShouldBeNil)
				So(r.Hash, ShouldEqual, successTx.Hash)
				So(submitter.WasSubmittedTo, ShouldBeTrue)
			})

			Convey("if error is bad_seq and no result is found, return error", func() {
				submitter.R = badSeq
				r := <-system.Submit(ctx, successTx.EnvelopeXDR)

				So(r.Err, ShouldNotBeNil)
				So(submitter.WasSubmittedTo, ShouldBeTrue)
			})

			Convey("if no result found and no error submitting, add to open transaction list", func() {
				_ = system.Submit(ctx, successTx.EnvelopeXDR)
				pending := system.Pending.Pending(ctx)
				So(len(pending), ShouldEqual, 1)
				So(pending[0], ShouldEqual, successTx.Hash)
				So(system.Metrics.SuccessfulSubmissionsMeter.Count(), ShouldEqual, 1)
				So(system.Metrics.FailedSubmissionsMeter.Count(), ShouldEqual, 0)
				So(system.Metrics.SubmissionTimer.Count(), ShouldEqual, 1)
			})
		})

		Convey("Tick", func() {

			Convey("no-ops if there are no open submissions", func() {
				system.Tick(ctx)
			})

			Convey("finishes any available transactions", func() {
				l := make(chan Result, 1)
				system.Pending.Add(ctx, successTx.Hash, l)
				system.Tick(ctx)
				So(len(l), ShouldEqual, 0)
				So(len(system.Pending.Pending(ctx)), ShouldEqual, 1)

				results.Results = []Result{successTx}
				system.Tick(ctx)

				So(len(l), ShouldEqual, 1)
				So(len(system.Pending.Pending(ctx)), ShouldEqual, 0)
			})

			Convey("removes old submissions that have timed out", func() {
				l := make(chan Result, 1)
				system.SubmissionTimeout = 100 * time.Millisecond
				system.Pending.Add(ctx, successTx.Hash, l)
				<-time.After(101 * time.Millisecond)
				system.Tick(ctx)

				So(len(system.Pending.Pending(ctx)), ShouldEqual, 0)

				select {
				case _, stillOpen := <-l:
					So(stillOpen, ShouldBeFalse)
				default:
					panic("could not read from listener")
				}

			})
		})

	})
}
Ejemplo n.º 12
0
func TestHelpers(t *testing.T) {
	Convey("Action Helpers", t, func() {
		r, _ := http.NewRequest("GET", "/?limit=2&cursor=hello", nil)

		action := &Base{
			Ctx: test.Context(),
			GojiCtx: web.C{
				URLParams: map[string]string{
					"blank":             "",
					"zero":              "0",
					"two":               "2",
					"32min":             fmt.Sprint(math.MinInt32),
					"32max":             fmt.Sprint(math.MaxInt32),
					"64min":             fmt.Sprint(math.MinInt64),
					"64max":             fmt.Sprint(math.MaxInt64),
					"native_asset_type": "native",
					"4_asset_type":      "credit_alphanum4",
					"4_asset_code":      "USD",
					"4_asset_issuer":    "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H",
					"12_asset_type":     "credit_alphanum12",
					"12_asset_code":     "USD",
					"12_asset_issuer":   "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H",
				},
				Env: map[interface{}]interface{}{},
			},
			R: r,
		}

		Convey("GetInt32", func() {
			result := action.GetInt32("blank")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 0)

			result = action.GetInt32("zero")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 0)

			result = action.GetInt32("two")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 2)

			result = action.GetInt32("32max")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, math.MaxInt32)

			result = action.GetInt32("32min")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, math.MinInt32)

			result = action.GetInt32("limit")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 2)

			result = action.GetInt32("64max")
			So(action.Err, ShouldHaveSameTypeAs, &problem.P{})
			p := action.Err.(*problem.P)
			So(p.Type, ShouldEqual, "bad_request")
			So(p.Extras["invalid_field"], ShouldEqual, "64max")
			action.Err = nil

			result = action.GetInt32("64min")
			So(action.Err, ShouldHaveSameTypeAs, &problem.P{})
			p = action.Err.(*problem.P)
			So(p.Type, ShouldEqual, "bad_request")
			So(p.Extras["invalid_field"], ShouldEqual, "64min")
			action.Err = nil

		})

		Convey("GetInt64", func() {
			result := action.GetInt64("blank")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 0)

			result = action.GetInt64("zero")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 0)

			result = action.GetInt64("two")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, 2)

			result = action.GetInt64("64max")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, math.MaxInt64)

			result = action.GetInt64("64min")
			So(action.Err, ShouldBeNil)
			So(result, ShouldEqual, math.MinInt64)
		})

		Convey("GetPagingParams", func() {
			cursor, order, limit := action.GetPagingParams()
			So(cursor, ShouldEqual, "hello")
			So(limit, ShouldEqual, 2)
			So(order, ShouldEqual, "")
		})

		Convey("GetAccountID", func() {
			_ = action.GetAccountID("4_asset_issuer")
			So(action.Err, ShouldBeNil)
		})

		Convey("GetAsset", func() {
			ts := action.GetAsset("native_")
			So(action.Err, ShouldBeNil)
			So(ts.Type, ShouldEqual, xdr.AssetTypeAssetTypeNative)

			ts = action.GetAsset("4_")
			So(action.Err, ShouldBeNil)
			So(ts.Type, ShouldEqual, xdr.AssetTypeAssetTypeCreditAlphanum4)

			ts = action.GetAsset("12_")
			So(action.Err, ShouldBeNil)
			So(ts.Type, ShouldEqual, xdr.AssetTypeAssetTypeCreditAlphanum12)

			So(action.Err, ShouldBeNil)
			action.GetAsset("cursor")
			So(action.Err, ShouldNotBeNil)
		})

		Convey("GetAssetType", func() {
			t := action.GetAssetType("native_asset_type")
			So(t, ShouldEqual, xdr.AssetTypeAssetTypeNative)

			t = action.GetAssetType("4_asset_type")
			So(t, ShouldEqual, xdr.AssetTypeAssetTypeCreditAlphanum4)

			t = action.GetAssetType("12_asset_type")
			So(t, ShouldEqual, xdr.AssetTypeAssetTypeCreditAlphanum12)

			So(action.Err, ShouldBeNil)
			action.GetAssetType("cursor")
			So(action.Err, ShouldNotBeNil)
		})

		Convey("Last-Event-ID overrides cursor", func() {
			action.R.Header.Set("Last-Event-ID", "from_header")
			cursor, _, _ := action.GetPagingParams()
			So(cursor, ShouldEqual, "from_header")
		})

		Convey("Form values override query values", func() {
			So(action.GetString("cursor"), ShouldEqual, "hello")

			action.R.Form = url.Values{
				"cursor": {"goodbye"},
			}
			So(action.GetString("cursor"), ShouldEqual, "goodbye")
		})

		Convey("regression: GetPagQuery does not overwrite err", func() {
			r, _ := http.NewRequest("GET", "/?limit=foo", nil)
			action.R = r
			_, _, _ = action.GetPagingParams()

			So(action.Err, ShouldNotBeNil)
			_ = action.GetPageQuery()
			So(action.Err, ShouldNotBeNil)
		})

		Convey("Path() return the action's http path", func() {
			r, _ := http.NewRequest("GET", "/foo-bar/blah?limit=foo", nil)
			action.R = r
			So(action.Path(), ShouldEqual, "/foo-bar/blah")
		})
	})
}
Ejemplo n.º 13
0
func TestTxsub(t *testing.T) {
	Convey("txsub.System", t, func() {
		ctx := test.Context()
		submitter := &MockSubmitter{}
		results := &MockResultProvider{}
		sequences := &MockSequenceProvider{}

		system := &System{
			Pending:           NewDefaultSubmissionList(),
			Submitter:         submitter,
			Results:           results,
			Sequences:         sequences,
			SubmissionQueue:   sequence.NewManager(),
			NetworkPassphrase: build.TestNetwork.Passphrase,
		}

		noResults := Result{Err: ErrNoResults}
		successTx := Result{
			Hash:           "2374e99349b9ef7dba9a5db3339b78fda8f34777b1af33ba468ad5c0df946d4d",
			LedgerSequence: 2,
			EnvelopeXDR:    "AAAAAGL8HQvQkbK2HA3WVjRrKmjX00fG8sLI7m0ERwJW/AX3AAAAZAAAAAAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAArqN6LeOagjxMaUP96Bzfs9e0corNZXzBWJkFoK7kvkwAAAAAO5rKAAAAAAAAAAABVvwF9wAAAECDzqvkQBQoNAJifPRXDoLhvtycT3lFPCQ51gkdsFHaBNWw05S/VhW0Xgkr0CBPE4NaFV2Kmcs3ZwLmib4TRrML",
			ResultXDR:      "I3Tpk0m57326ml2zM5t4/ajzR3exrzO6RorVwN+UbU0AAAAAAAAAZAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAA==",
		}

		badSeq := SubmissionResult{
			Err: ErrBadSequence,
		}

		sequences.Results = map[string]uint64{
			"GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H": 0,
		}

		Convey("Submit", func() {
			Convey("returns the result provided by the ResultProvider", func() {
				results.Results = []Result{successTx}
				r := <-system.Submit(ctx, successTx.EnvelopeXDR)

				So(r.Err, ShouldBeNil)
				So(r.Hash, ShouldEqual, successTx.Hash)
				So(submitter.WasSubmittedTo, ShouldBeFalse)
			})

			Convey("returns the error from submission if no result is found by hash and the submitter returns an error", func() {
				submitter.R.Err = errors.New("busted for some reason")
				r := <-system.Submit(ctx, successTx.EnvelopeXDR)

				So(r.Err, ShouldNotBeNil)
				So(submitter.WasSubmittedTo, ShouldBeTrue)
				So(system.Metrics.SuccessfulSubmissionsMeter.Count(), ShouldEqual, 0)
				So(system.Metrics.FailedSubmissionsMeter.Count(), ShouldEqual, 1)
				So(system.Metrics.SubmissionTimer.Count(), ShouldEqual, 1)
			})

			Convey("if the error is bad_seq and the result at the transaction's sequence number is for the same hash, return result", func() {
				submitter.R = badSeq
				results.Results = []Result{noResults, successTx}

				r := <-system.Submit(ctx, successTx.EnvelopeXDR)

				So(r.Err, ShouldBeNil)
				So(r.Hash, ShouldEqual, successTx.Hash)
				So(submitter.WasSubmittedTo, ShouldBeTrue)
			})

			Convey("if error is bad_seq and no result is found, return error", func() {
				submitter.R = badSeq
				r := <-system.Submit(ctx, successTx.EnvelopeXDR)

				So(r.Err, ShouldNotBeNil)
				So(submitter.WasSubmittedTo, ShouldBeTrue)
			})

			Convey("if no result found and no error submitting, add to open transaction list", func() {
				_ = system.Submit(ctx, successTx.EnvelopeXDR)
				pending := system.Pending.Pending(ctx)
				So(len(pending), ShouldEqual, 1)
				So(pending[0], ShouldEqual, successTx.Hash)
				So(system.Metrics.SuccessfulSubmissionsMeter.Count(), ShouldEqual, 1)
				So(system.Metrics.FailedSubmissionsMeter.Count(), ShouldEqual, 0)
				So(system.Metrics.SubmissionTimer.Count(), ShouldEqual, 1)
			})
		})

		Convey("Tick", func() {

			Convey("no-ops if there are no open submissions", func() {
				system.Tick(ctx)
			})

			Convey("finishes any available transactions", func() {
				l := make(chan Result, 1)
				system.Pending.Add(ctx, successTx.Hash, l)
				system.Tick(ctx)
				So(len(l), ShouldEqual, 0)
				So(len(system.Pending.Pending(ctx)), ShouldEqual, 1)

				results.Results = []Result{successTx}
				system.Tick(ctx)

				So(len(l), ShouldEqual, 1)
				So(len(system.Pending.Pending(ctx)), ShouldEqual, 0)
			})

			Convey("removes old submissions that have timed out", func() {
				l := make(chan Result, 1)
				system.SubmissionTimeout = 100 * time.Millisecond
				system.Pending.Add(ctx, successTx.Hash, l)
				<-time.After(101 * time.Millisecond)
				system.Tick(ctx)

				So(len(system.Pending.Pending(ctx)), ShouldEqual, 0)
				So(len(l), ShouldEqual, 1)
				<-l
				select {
				case _, stillOpen := <-l:
					So(stillOpen, ShouldBeFalse)
				default:
					panic("could not read from listener")
				}

			})
		})

	})
}