func TestRequestHandlerAuth(t *testing.T) {
	c := &config.Config{
		NetworkPassphrase: "Test SDF Network ; September 2015",
		Keys: config.Keys{
			// GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB
			SigningSeed: "SDWTLFPALQSP225BSMX7HPZ7ZEAYSUYNDLJ5QI3YGVBNRUIIELWH3XUV",
		},
	}

	mockHTTPClient := new(mocks.MockHTTPClient)
	mockEntityManager := new(mocks.MockEntityManager)
	mockRepository := new(mocks.MockRepository)
	mockFederationResolver := new(mocks.MockFederationResolver)
	mockSignerVerifier := new(mocks.MockSignerVerifier)
	mockStellartomlResolver := new(mocks.MockStellartomlResolver)
	requestHandler := RequestHandler{}

	// Inject mocks
	var g inject.Graph

	err := g.Provide(
		&inject.Object{Value: &requestHandler},
		&inject.Object{Value: c},
		&inject.Object{Value: mockHTTPClient},
		&inject.Object{Value: mockEntityManager},
		&inject.Object{Value: mockRepository},
		&inject.Object{Value: mockFederationResolver},
		&inject.Object{Value: mockSignerVerifier},
		&inject.Object{Value: mockStellartomlResolver},
	)
	if err != nil {
		panic(err)
	}

	if err := g.Populate(); err != nil {
		panic(err)
	}

	httpHandle := func(w http.ResponseWriter, r *http.Request) {
		requestHandler.HandlerAuth(web.C{}, w, r)
	}

	testServer := httptest.NewServer(http.HandlerFunc(httpHandle))
	defer testServer.Close()

	Convey("Given auth request (no sanctions check)", t, func() {
		Convey("When data param is missing", func() {
			statusCode, response := net.GetResponse(testServer, url.Values{})
			responseString := strings.TrimSpace(string(response))
			assert.Equal(t, 400, statusCode)
			expected := test.StringToJSONMap(`{
  "code": "missing_parameter",
  "message": "Required parameter is missing.",
  "data": {
    "name": "data"
  }
}`)
			assert.Equal(t, expected, test.StringToJSONMap(responseString))
		})

		Convey("When data is invalid", func() {
			params := url.Values{
				"data": {"hello world"},
				"sig":  {"bad sig"},
			}

			statusCode, response := net.GetResponse(testServer, params)
			responseString := strings.TrimSpace(string(response))
			assert.Equal(t, 400, statusCode)
			expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "data"
  }
}`)
			assert.Equal(t, expected, test.StringToJSONMap(responseString))
		})

		Convey("When sender's stellar.toml does not contain signing key", func() {
			mockStellartomlResolver.On(
				"GetStellarTomlByAddress",
				"alice*stellar.org",
			).Return(stellartoml.StellarToml{}, nil).Once()

			params := url.Values{
				"data": {"{\"sender\":\"alice*stellar.org\",\"need_info\":false,\"tx\":\"AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAAO5TSe5k00+CKUuUtfafav6xITv43pTgO6QiPes4u/N6QAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=\",\"memo\":\"hello world\"}"},
				"sig":  {"bad sig"},
			}

			statusCode, response := net.GetResponse(testServer, params)
			responseString := strings.TrimSpace(string(response))
			assert.Equal(t, 400, statusCode)
			expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "data.sender"
  }
}`)
			assert.Equal(t, expected, test.StringToJSONMap(responseString))
		})

		Convey("When signature is invalid", func() {
			mockStellartomlResolver.On(
				"GetStellarTomlByAddress",
				"alice*stellar.org",
			).Return(stellartoml.StellarToml{
				SigningKey: "GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB",
			}, nil).Once()

			params := url.Values{
				"data": {"{\"sender\":\"alice*stellar.org\",\"need_info\":false,\"tx\":\"AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAAO5TSe5k00+CKUuUtfafav6xITv43pTgO6QiPes4u/N6QAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=\",\"memo\":\"hello world\"}"},
				"sig":  {"ACamNqa0dF8gf97URhFVKWSD7fmvZKc5At+8dCLM5ySR0HsHySF3G2WuwYP2nKjeqjKmu3U9Z3+u1P10w1KBCA=="},
			}

			mockSignerVerifier.On(
				"Verify",
				"GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB",
				mock.AnythingOfType("[]uint8"),
				mock.AnythingOfType("[]uint8"),
			).Return(errors.New("Verify error")).Once()

			statusCode, response := net.GetResponse(testServer, params)
			responseString := strings.TrimSpace(string(response))
			assert.Equal(t, 400, statusCode)
			expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "sig"
  }
}`)
			assert.Equal(t, expected, test.StringToJSONMap(responseString))
		})

		Convey("When all params are valid", func() {
			params := url.Values{
				"data": {"{\"sender\":\"alice*stellar.org\",\"need_info\":false,\"tx\":\"AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANEE2+jVbNnihFGrRb36GSelPtPwh/nfoMQwGD2HKr/igAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=\",\"memo\":\"{}\"}"},
				"sig":  {"ACamNqa0dF8gf97URhFVKWSD7fmvZKc5At+8dCLM5ySR0HsHySF3G2WuwYP2nKjeqjKmu3U9Z3+u1P10w1KBCA=="},
			}

			mockStellartomlResolver.On(
				"GetStellarTomlByAddress",
				"alice*stellar.org",
			).Return(stellartoml.StellarToml{
				SigningKey: "GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB",
			}, nil).Once()

			mockSignerVerifier.On(
				"Verify",
				"GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB",
				mock.AnythingOfType("[]uint8"),
				mock.AnythingOfType("[]uint8"),
			).Return(nil).Once()

			Convey("it returns AuthResponse", func() {
				authorizedTransaction := &entities.AuthorizedTransaction{
					TransactionID:  "29ec92f95b00dd8e8bbb0d2a2fc90db8ed5b26c396c44ac978bb13ccd8d25524",
					Memo:           "RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=",
					TransactionXdr: "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANEE2+jVbNnihFGrRb36GSelPtPwh/nfoMQwGD2HKr/igAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=",
					Data:           params["data"][0],
				}

				mockEntityManager.On(
					"Persist",
					mock.AnythingOfType("*entities.AuthorizedTransaction"),
				).Run(func(args mock.Arguments) {
					value := args.Get(0).(*entities.AuthorizedTransaction)
					assert.Equal(t, authorizedTransaction.TransactionID, value.TransactionID)
					assert.Equal(t, authorizedTransaction.Memo, value.Memo)
					assert.Equal(t, authorizedTransaction.TransactionXdr, value.TransactionXdr)
					assert.WithinDuration(t, time.Now(), value.AuthorizedAt, 2*time.Second)
					assert.Equal(t, authorizedTransaction.Data, value.Data)
				}).Return(nil).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "info_status": "ok",
  "tx_status": "ok"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})
	})

	Convey("Given auth request (sanctions check)", t, func() {
		c.Callbacks = config.Callbacks{
			Sanctions: "http://sanctions",
			AskUser:   "******",
			FetchInfo: "http://fetch_info",
		}

		memoPreimage := memo.Memo{
			Transaction: memo.Transaction{
				Route:      "bob*acme.com",
				Note:       "Happy birthday",
				SenderInfo: "senderInfoJson",
				Extra:      "extra",
			},
		}

		Convey("When all params are valid (NeedInfo = `false`)", func() {
			authData := compliance.AuthData{
				Sender:   "alice*stellar.org",
				NeedInfo: false,
				Tx:       "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANeCnOi6ZSpMNIMFUUVIfbBc5OA5kpzDbg+AJ6X8/WynAAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=",
				Memo:     string(memoPreimage.Marshal()),
			}

			params := url.Values{
				"data": {string(authData.Marshal())},
				"sig":  {"Q2cQVOn/A+aOxrLLeUPwHmBm3LMvlfXN8tDHo4Oi6SxWWueMTDfRkC4XvRX4emLij+Npo7/GfrZ82CnT5yB5Dg=="},
			}

			mockStellartomlResolver.On(
				"GetStellarTomlByAddress",
				"alice*stellar.org",
			).Return(stellartoml.StellarToml{
				SigningKey: "GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB",
			}, nil).Once()

			mockSignerVerifier.On(
				"Verify",
				"GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB",
				mock.AnythingOfType("[]uint8"),
				mock.AnythingOfType("[]uint8"),
			).Return(nil).Once()

			Convey("when sanctions server returns forbidden it returns tx_status `denied`", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://sanctions",
					url.Values{"sender": {memoPreimage.Transaction.SenderInfo}},
				).Return(
					net.BuildHTTPResponse(403, "forbidden"),
					nil,
				).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
		  "info_status": "ok",
		  "tx_status": "denied"
		}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("when sanctions server returns accepted it returns tx_status `pending`", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://sanctions",
					url.Values{"sender": {memoPreimage.Transaction.SenderInfo}},
				).Return(
					net.BuildHTTPResponse(202, "pending"),
					nil,
				).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "info_status": "ok",
  "tx_status": "pending",
  "pending": 600
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("when sanctions server returns ok it returns tx_status `ok` and persists transaction", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://sanctions",
					url.Values{"sender": {memoPreimage.Transaction.SenderInfo}},
				).Return(
					net.BuildHTTPResponse(200, "ok"),
					nil,
				).Once()

				authorizedTransaction := &entities.AuthorizedTransaction{
					TransactionID:  "f62589932eb9fcf0bf28fe95510bf614caf3169c67a85e75475a390a79b5ecc9",
					Memo:           "XgpzoumUqTDSDBVFFSH2wXOTgOZKcw24PgCel/P1spw=",
					TransactionXdr: "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANeCnOi6ZSpMNIMFUUVIfbBc5OA5kpzDbg+AJ6X8/WynAAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=",
					Data:           params["data"][0],
				}

				mockEntityManager.On(
					"Persist",
					mock.AnythingOfType("*entities.AuthorizedTransaction"),
				).Run(func(args mock.Arguments) {
					value := args.Get(0).(*entities.AuthorizedTransaction)
					assert.Equal(t, authorizedTransaction.TransactionID, value.TransactionID)
					assert.Equal(t, authorizedTransaction.Memo, value.Memo)
					assert.Equal(t, authorizedTransaction.TransactionXdr, value.TransactionXdr)
					assert.WithinDuration(t, time.Now(), value.AuthorizedAt, 2*time.Second)
					assert.Equal(t, authorizedTransaction.Data, value.Data)
				}).Return(nil).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "info_status": "ok",
  "tx_status": "ok"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("When all params are valid (NeedInfo = `true`)", func() {
			authData := compliance.AuthData{
				Sender:   "alice*stellar.org",
				NeedInfo: true,
				Tx:       "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANeCnOi6ZSpMNIMFUUVIfbBc5OA5kpzDbg+AJ6X8/WynAAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=",
				Memo:     string(memoPreimage.Marshal()),
			}

			params := url.Values{
				"data": {string(authData.Marshal())},
				"sig":  {"Q2cQVOn/A+aOxrLLeUPwHmBm3LMvlfXN8tDHo4Oi6SxWWueMTDfRkC4XvRX4emLij+Npo7/GfrZ82CnT5yB5Dg=="},
			}

			mockStellartomlResolver.On(
				"GetStellarTomlByAddress",
				"alice*stellar.org",
			).Return(stellartoml.StellarToml{
				SigningKey: "GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB",
			}, nil).Once()

			mockSignerVerifier.On(
				"Verify",
				"GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB",
				mock.AnythingOfType("[]uint8"),
				mock.AnythingOfType("[]uint8"),
			).Return(nil).Once()

			// Make sanctions checks successful (tested in the previous test case)
			mockHTTPClient.On(
				"PostForm",
				"http://sanctions",
				url.Values{
					"sender": {memoPreimage.Transaction.SenderInfo},
				},
			).Return(
				net.BuildHTTPResponse(200, "ok"),
				nil,
			).Once()

			Convey("when ask_user server returns forbidden it returns info_status `denied`", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://ask_user",
					url.Values{
						"sender":       {memoPreimage.Transaction.SenderInfo},
						"note":         {memoPreimage.Transaction.Note},
						"amount":       {"20.0000000"},
						"asset_code":   {"USD"},
						"asset_issuer": {"GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE"},
					},
				).Return(
					net.BuildHTTPResponse(403, "forbidden"),
					nil,
				).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "info_status": "denied",
  "tx_status": "ok"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("when ask_user server returns pending it returns info_status `pending`", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://ask_user",
					url.Values{
						"sender":       {memoPreimage.Transaction.SenderInfo},
						"note":         {memoPreimage.Transaction.Note},
						"amount":       {"20.0000000"},
						"asset_code":   {"USD"},
						"asset_issuer": {"GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE"},
					},
				).Return(
					net.BuildHTTPResponse(202, "{\"pending\": 300}"),
					nil,
				).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "info_status": "pending",
  "tx_status": "ok",
  "pending": 300
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("when ask_user server returns pending but invalid response body it returns info_status `pending` (600 seconds)", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://ask_user",
					url.Values{
						"sender":       {memoPreimage.Transaction.SenderInfo},
						"note":         {memoPreimage.Transaction.Note},
						"amount":       {"20.0000000"},
						"asset_code":   {"USD"},
						"asset_issuer": {"GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE"},
					},
				).Return(
					net.BuildHTTPResponse(202, "pending"),
					nil,
				).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "info_status": "pending",
  "tx_status": "ok",
  "pending": 600
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("when ask_user server returns ok it returns info_status `ok` and DestInfo and persists transaction", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://ask_user",
					url.Values{
						"sender":       {memoPreimage.Transaction.SenderInfo},
						"note":         {memoPreimage.Transaction.Note},
						"amount":       {"20.0000000"},
						"asset_code":   {"USD"},
						"asset_issuer": {"GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE"},
					},
				).Return(
					net.BuildHTTPResponse(200, "ok"),
					nil,
				).Once()

				mockHTTPClient.On(
					"PostForm",
					"http://fetch_info",
					url.Values{"address": {"bob*acme.com"}},
				).Return(
					net.BuildHTTPResponse(200, "user data"),
					nil,
				).Once()

				authorizedTransaction := &entities.AuthorizedTransaction{
					TransactionID:  "f62589932eb9fcf0bf28fe95510bf614caf3169c67a85e75475a390a79b5ecc9",
					Memo:           "XgpzoumUqTDSDBVFFSH2wXOTgOZKcw24PgCel/P1spw=",
					TransactionXdr: "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANeCnOi6ZSpMNIMFUUVIfbBc5OA5kpzDbg+AJ6X8/WynAAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=",
					Data:           params["data"][0],
				}

				mockEntityManager.On(
					"Persist",
					mock.AnythingOfType("*entities.AuthorizedTransaction"),
				).Run(func(args mock.Arguments) {
					value := args.Get(0).(*entities.AuthorizedTransaction)
					assert.Equal(t, authorizedTransaction.TransactionID, value.TransactionID)
					assert.Equal(t, authorizedTransaction.Memo, value.Memo)
					assert.Equal(t, authorizedTransaction.TransactionXdr, value.TransactionXdr)
					assert.WithinDuration(t, time.Now(), value.AuthorizedAt, 2*time.Second)
					assert.Equal(t, authorizedTransaction.Data, value.Data)
				}).Return(nil).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "info_status": "ok",
  "tx_status": "ok",
  "dest_info": "user data"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("When no callbacks.ask_user server", func() {
				c.Callbacks.AskUser = ""

				Convey("when FI allowed it returns info_status = `ok` and DestInfo and persists transaction", func() {
					mockRepository.On(
						"GetAllowedFiByDomain",
						"stellar.org", // sender = `alice*stellar.org`
					).Return(
						&entities.AllowedFi{}, // It just returns existing record
						nil,
					).Once()

					mockHTTPClient.On(
						"PostForm",
						"http://fetch_info",
						url.Values{"address": {"bob*acme.com"}},
					).Return(
						net.BuildHTTPResponse(200, "user data"),
						nil,
					).Once()

					authorizedTransaction := &entities.AuthorizedTransaction{
						TransactionID:  "f62589932eb9fcf0bf28fe95510bf614caf3169c67a85e75475a390a79b5ecc9",
						Memo:           "XgpzoumUqTDSDBVFFSH2wXOTgOZKcw24PgCel/P1spw=",
						TransactionXdr: "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANeCnOi6ZSpMNIMFUUVIfbBc5OA5kpzDbg+AJ6X8/WynAAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=",
						Data:           params["data"][0],
					}

					mockEntityManager.On(
						"Persist",
						mock.AnythingOfType("*entities.AuthorizedTransaction"),
					).Run(func(args mock.Arguments) {
						value := args.Get(0).(*entities.AuthorizedTransaction)
						assert.Equal(t, authorizedTransaction.TransactionID, value.TransactionID)
						assert.Equal(t, authorizedTransaction.Memo, value.Memo)
						assert.Equal(t, authorizedTransaction.TransactionXdr, value.TransactionXdr)
						assert.WithinDuration(t, time.Now(), value.AuthorizedAt, 2*time.Second)
						assert.Equal(t, authorizedTransaction.Data, value.Data)
					}).Return(nil).Once()

					statusCode, response := net.GetResponse(testServer, params)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
  "info_status": "ok",
  "tx_status": "ok",
  "dest_info": "user data"
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})

				Convey("when FI not allowed but User is allowed it returns info_status = `ok` and DestInfo and persists transaction", func() {
					mockRepository.On(
						"GetAllowedFiByDomain",
						"stellar.org", // sender = `alice*stellar.org`
					).Return(
						nil,
						nil,
					).Once()

					mockRepository.On(
						"GetAllowedUserByDomainAndUserID",
						"stellar.org", // sender = `alice*stellar.org`
						"alice",
					).Return(
						&entities.AllowedUser{},
						nil,
					).Once()

					mockHTTPClient.On(
						"PostForm",
						"http://fetch_info",
						url.Values{"address": {"bob*acme.com"}},
					).Return(
						net.BuildHTTPResponse(200, "user data"),
						nil,
					).Once()

					authorizedTransaction := &entities.AuthorizedTransaction{
						TransactionID:  "f62589932eb9fcf0bf28fe95510bf614caf3169c67a85e75475a390a79b5ecc9",
						Memo:           "XgpzoumUqTDSDBVFFSH2wXOTgOZKcw24PgCel/P1spw=",
						TransactionXdr: "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANeCnOi6ZSpMNIMFUUVIfbBc5OA5kpzDbg+AJ6X8/WynAAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA=",
						Data:           params["data"][0],
					}

					mockEntityManager.On(
						"Persist",
						mock.AnythingOfType("*entities.AuthorizedTransaction"),
					).Run(func(args mock.Arguments) {
						value := args.Get(0).(*entities.AuthorizedTransaction)
						assert.Equal(t, authorizedTransaction.TransactionID, value.TransactionID)
						assert.Equal(t, authorizedTransaction.Memo, value.Memo)
						assert.Equal(t, authorizedTransaction.TransactionXdr, value.TransactionXdr)
						assert.WithinDuration(t, time.Now(), value.AuthorizedAt, 2*time.Second)
						assert.Equal(t, authorizedTransaction.Data, value.Data)
					}).Return(nil).Once()

					statusCode, response := net.GetResponse(testServer, params)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
  "info_status": "ok",
  "tx_status": "ok",
  "dest_info": "user data"
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})

				Convey("when neither FI nor User is allowed it returns info_status = `denied`", func() {
					mockRepository.On(
						"GetAllowedFiByDomain",
						"stellar.org", // sender = `alice*stellar.org`
					).Return(
						nil,
						nil,
					).Once()

					mockRepository.On(
						"GetAllowedUserByDomainAndUserID",
						"stellar.org", // sender = `alice*stellar.org`
						"alice",
					).Return(
						nil,
						nil,
					).Once()

					statusCode, response := net.GetResponse(testServer, params)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
  "info_status": "denied",
  "tx_status": "ok"
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})
		})
	})
}
func TestRequestHandlerPayment(t *testing.T) {
	c := &config.Config{
		NetworkPassphrase: "Test SDF Network ; September 2015",
		Compliance:        "http://compliance",
	}
	mockHorizon := new(mocks.MockHorizon)
	mockHTTPClient := new(mocks.MockHTTPClient)
	mockTransactionSubmitter := new(mocks.MockTransactionSubmitter)
	mockFederationResolver := new(mocks.MockFederationResolver)
	mockStellartomlResolver := new(mocks.MockStellartomlResolver)
	requestHandler := RequestHandler{}

	// Inject mocks
	var g inject.Graph

	err := g.Provide(
		&inject.Object{Value: &requestHandler},
		&inject.Object{Value: c},
		&inject.Object{Value: mockHorizon},
		&inject.Object{Value: mockHTTPClient},
		&inject.Object{Value: mockTransactionSubmitter},
		&inject.Object{Value: mockFederationResolver},
		&inject.Object{Value: mockStellartomlResolver},
	)
	if err != nil {
		panic(err)
	}

	if err := g.Populate(); err != nil {
		panic(err)
	}

	testServer := httptest.NewServer(http.HandlerFunc(requestHandler.Payment))
	defer testServer.Close()

	Convey("Given payment request", t, func() {
		Convey("When source is invalid", func() {
			params := url.Values{
				"source":      {"SDRAS7XIQNX25UDCCX725R4EYGBFYGJE4HJ2A3DFCWJIHMRSMS7CXX43"},
				"destination": {"GBABZMS7MEDWKWSHOMUKAWGIOE5UA4XLVPUHRHVMUW2DUVEZXLH5OIET"},
				"amount":      {"20.0"},
			}

			Convey("it should return error", func() {
				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 400, statusCode)
				expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "source"
  }
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("When destination is invalid", func() {
			params := url.Values{
				"source":      {"SDRAS7XIQNX25UDCCX725R4EYGBFYGJE4HJ2A3DFCWJIHMRSMS7CXX42"},
				"destination": {"GD3YBOYIUVLU"},
				"amount":      {"20.0"},
			}

			mockFederationResolver.On(
				"Resolve",
				"GD3YBOYIUVLU",
			).Return(
				federation.Response{AccountID: "GD3YBOYIUVLU"},
				stellartoml.StellarToml{},
				nil,
			).Once()

			Convey("it should return error", func() {
				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 400, statusCode)
				expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "destination"
  }
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("When destination is a Stellar address", func() {
			params := url.Values{
				"source":      {"SDRAS7XIQNX25UDCCX725R4EYGBFYGJE4HJ2A3DFCWJIHMRSMS7CXX42"},
				"destination": {"bob*stellar.org"},
				"amount":      {"20.0"},
			}

			Convey("When FederationResolver returns error", func() {
				mockFederationResolver.On(
					"Resolve",
					"bob*stellar.org",
				).Return(
					federation.Response{},
					stellartoml.StellarToml{},
					errors.New("stellar.toml response status code indicates error"),
				).Once()

				Convey("it should return error", func() {
					statusCode, response := net.GetResponse(testServer, params)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 400, statusCode)
					expected := test.StringToJSONMap(`{
  "code": "cannot_resolve_destination",
  "message": "Cannot resolve federated Stellar address."
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})

			Convey("When federation response is correct (no memo)", func() {
				validParams := url.Values{
					// GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ
					"source":      {"SDWLS4G3XCNIYPKXJWWGGJT6UDY63WV6PEFTWP7JZMQB4RE7EUJQN5XM"},
					"destination": {"bob*stellar.org"},
					"amount":      {"20"},
				}

				mockFederationResolver.On(
					"Resolve",
					"bob*stellar.org",
				).Return(
					federation.Response{AccountID: "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
					stellartoml.StellarToml{},
					nil,
				).Once()

				// Checking if destination account exists
				mockHorizon.On(
					"LoadAccount",
					"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
				).Return(horizon.AccountResponse{}, nil).Once()

				// Loading sequence number
				mockHorizon.On(
					"LoadAccount",
					"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
				).Return(
					horizon.AccountResponse{
						SequenceNumber: "100",
					},
					nil,
				).Once()

				var ledger uint64
				ledger = 1988728
				horizonResponse := horizon.SubmitTransactionResponse{
					Hash:   "6a0049b44e0d0341bd52f131c74383e6ccd2b74b92c829c990994d24bbfcfa7a",
					Ledger: &ledger,
					Extras: nil,
				}

				mockHorizon.On(
					"SubmitTransaction",
					"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAA5IVbm6A8mbgc/apAizxmBf4zZmqbedR3Ke+MTa7pjVYAAAAAAAAAAAvrwgAAAAAAAAAAAfwmKjcAAABAh3M6y9LXiWD0GB1KCkgNS5H1Lnyr1wS1BsfzoM1/v0muzobwNkJinV+RcWyC8VfeKqOjKBOANJnEusl+sHkcAg==",
				).Return(horizonResponse, nil).Once()

				Convey("it should return success", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "6a0049b44e0d0341bd52f131c74383e6ccd2b74b92c829c990994d24bbfcfa7a",
					  "ledger": 1988728
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})

			Convey("When federation response is correct (with memo)", func() {
				validParams := url.Values{
					// GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ
					"source":      {"SDWLS4G3XCNIYPKXJWWGGJT6UDY63WV6PEFTWP7JZMQB4RE7EUJQN5XM"},
					"destination": {"bob*stellar.org"},
					"amount":      {"20"},
				}

				mockFederationResolver.On(
					"Resolve",
					"bob*stellar.org",
				).Return(
					federation.Response{
						AccountID: "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
						MemoType:  "text",
						Memo:      "125",
					},
					stellartoml.StellarToml{},
					nil,
				).Once()

				// Checking if destination account exists
				mockHorizon.On(
					"LoadAccount",
					"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
				).Return(horizon.AccountResponse{}, nil).Once()

				// Loading sequence number
				mockHorizon.On(
					"LoadAccount",
					"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
				).Return(
					horizon.AccountResponse{
						SequenceNumber: "100",
					},
					nil,
				).Once()

				var ledger uint64
				ledger = 1988728
				horizonResponse := horizon.SubmitTransactionResponse{
					Hash:   "ad71fc31bfae25b0bd14add4cc5306661edf84cdd73f1353d2906363899167e1",
					Ledger: &ledger,
					Extras: nil,
				}

				mockHorizon.On(
					"SubmitTransaction",
					"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAEAAAADMTI1AAAAAAEAAAAAAAAAAQAAAADkhVuboDyZuBz9qkCLPGYF/jNmapt51Hcp74xNrumNVgAAAAAAAAAAC+vCAAAAAAAAAAAB/CYqNwAAAEAjnc8Wf31VxgBXXhEmZfLo6c4YJtROVy5MTLsWFSx7TCkoQzCskBVcC30DrjQq7Vzm0zwg+mBmSGI5wFbctKgB",
				).Return(horizonResponse, nil).Once()

				Convey("it should return success", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "ad71fc31bfae25b0bd14add4cc5306661edf84cdd73f1353d2906363899167e1",
					  "ledger": 1988728
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})
		})

		Convey("When asset_issuer is invalid", func() {
			params := url.Values{
				"source":       {"SDRAS7XIQNX25UDCCX725R4EYGBFYGJE4HJ2A3DFCWJIHMRSMS7CXX42"},
				"destination":  {"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				"asset_code":   {"USD"},
				"asset_issuer": {"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN631"},
				"amount":       {"100.0"},
			}

			mockFederationResolver.On(
				"Resolve",
				"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
			).Return(
				federation.Response{AccountID: "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				stellartoml.StellarToml{},
				nil,
			).Once()

			Convey("it should return error", func() {
				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 400, statusCode)
				expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "asset_issuer"
  }
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("When assetCode is invalid", func() {
			// GBKGH7QZVCZ2ZA5OUGZSTHFNXTBHL3MPCKSCBJUAQODGPMWP7OMMRKDW
			source := "SDRAS7XIQNX25UDCCX725R4EYGBFYGJE4HJ2A3DFCWJIHMRSMS7CXX42"
			destination := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"
			amount := "20"
			assetCode := "1234567890123"
			assetIssuer := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"

			mockFederationResolver.On(
				"Resolve",
				"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
			).Return(
				federation.Response{AccountID: "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				stellartoml.StellarToml{},
				nil,
			).Once()

			Convey("it should return error", func() {
				mockHorizon.On(
					"LoadAccount",
					"GBKGH7QZVCZ2ZA5OUGZSTHFNXTBHL3MPCKSCBJUAQODGPMWP7OMMRKDW",
				).Return(
					horizon.AccountResponse{
						SequenceNumber: "100",
					},
					nil,
				).Once()

				statusCode, response := net.GetResponse(
					testServer,
					url.Values{
						"source":       {source},
						"destination":  {destination},
						"amount":       {amount},
						"asset_code":   {assetCode},
						"asset_issuer": {assetIssuer},
					},
				)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 400, statusCode)
				expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "asset_code"
  }
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("When amount is invalid", func() {
			// GBKGH7QZVCZ2ZA5OUGZSTHFNXTBHL3MPCKSCBJUAQODGPMWP7OMMRKDW
			source := "SDRAS7XIQNX25UDCCX725R4EYGBFYGJE4HJ2A3DFCWJIHMRSMS7CXX42"
			destination := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"
			amount := "test"
			assetCode := "USD"
			assetIssuer := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"

			mockFederationResolver.On(
				"Resolve",
				"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
			).Return(
				federation.Response{AccountID: "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				stellartoml.StellarToml{},
				nil,
			).Once()

			mockHorizon.On(
				"LoadAccount",
				"GBKGH7QZVCZ2ZA5OUGZSTHFNXTBHL3MPCKSCBJUAQODGPMWP7OMMRKDW",
			).Return(
				horizon.AccountResponse{
					SequenceNumber: "100",
				},
				nil,
			).Once()

			Convey("it should return error", func() {
				statusCode, response := net.GetResponse(
					testServer,
					url.Values{
						"source":       {source},
						"destination":  {destination},
						"amount":       {amount},
						"asset_code":   {assetCode},
						"asset_issuer": {assetIssuer},
					},
				)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 400, statusCode)
				expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "amount"
  }
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("When params are valid (payment operation)", func() {
			validParams := url.Values{
				// GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ
				"source":       {"SDWLS4G3XCNIYPKXJWWGGJT6UDY63WV6PEFTWP7JZMQB4RE7EUJQN5XM"},
				"destination":  {"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				"amount":       {"20"},
				"asset_code":   {"USD"},
				"asset_issuer": {"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
			}

			mockFederationResolver.On(
				"Resolve",
				"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
			).Return(
				federation.Response{AccountID: "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				stellartoml.StellarToml{},
				nil,
			).Once()

			Convey("When memo is set", func() {
				Convey("only `memo` param is set", func() {
					validParams.Add("memo", "test")
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 400, statusCode)
					expected := test.StringToJSONMap(`{
  "code": "missing_parameter",
  "message": "Required parameter is missing.",
  "data": {
    "name": "memo_type"
  }
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})

				Convey("only `memo_type` param is set", func() {
					validParams.Add("memo_type", "id")
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 400, statusCode)
					expected := test.StringToJSONMap(`{
  "code": "missing_parameter",
  "message": "Required parameter is missing.",
  "data": {
    "name": "memo"
  }
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})

				Convey("memo_type=hash to long", func() {
					validParams.Add("memo_type", "hash")
					validParams.Add("memo", "012345678901234567890123456789012345678901234567890123456789012")
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 400, statusCode)
					expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "memo"
  }
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})

				Convey("unsupported memo_type", func() {
					validParams.Add("memo_type", "return_hash")
					validParams.Add("memo", "0123456789")
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 400, statusCode)
					expected := test.StringToJSONMap(`{
  "code": "invalid_parameter",
  "message": "Invalid parameter.",
  "data": {
    "name": "memo"
  }
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})

				Convey("memo is attached to the transaction", func() {
					mockHorizon.On(
						"LoadAccount",
						"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
					).Return(
						horizon.AccountResponse{
							SequenceNumber: "100",
						},
						nil,
					).Once()

					var ledger uint64
					ledger = 1988727
					horizonResponse := horizon.SubmitTransactionResponse{
						Hash:   "f16040c1c6ee29eb4cc6f797651901750ff48a203985eea74f94353502f6629d",
						Ledger: &ledger,
						Extras: nil,
					}

					mockHorizon.On(
						"SubmitTransaction",
						"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAIAAAAAAAAAewAAAAEAAAAAAAAAAQAAAADkhVuboDyZuBz9qkCLPGYF/jNmapt51Hcp74xNrumNVgAAAAFVU0QAAAAAAOSFW5ugPJm4HP2qQIs8ZgX+M2Zqm3nUdynvjE2u6Y1WAAAAAAvrwgAAAAAAAAAAAfwmKjcAAABADsRVwB27jfr3OthAWlRMSrxAIDPENw1dOfga5/cahnIneJQ5NPS5g96Rp8Y5xTsOU3Y9JmBDKB8g8lXFCXdwCA==",
					).Return(horizonResponse, nil).Once()

					validParams.Add("memo_type", "id")
					validParams.Add("memo", "123")
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "f16040c1c6ee29eb4cc6f797651901750ff48a203985eea74f94353502f6629d",
					  "ledger": 1988727
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})

				Convey("memo hash is attached to the transaction", func() {
					mockHorizon.On(
						"LoadAccount",
						"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
					).Return(
						horizon.AccountResponse{
							SequenceNumber: "100",
						},
						nil,
					).Once()

					var ledger uint64
					ledger = 1988727
					horizonResponse := horizon.SubmitTransactionResponse{
						Hash:   "b6802ab06786c923d7180236a84470c03b37ec71912bfe335d0cb57ebc534881",
						Ledger: &ledger,
						Extras: nil,
					}

					mockHorizon.On(
						"SubmitTransaction",
						"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAMCADrUIHRM3rjlJN62XzjLUJXTDQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAADkhVuboDyZuBz9qkCLPGYF/jNmapt51Hcp74xNrumNVgAAAAFVU0QAAAAAAOSFW5ugPJm4HP2qQIs8ZgX+M2Zqm3nUdynvjE2u6Y1WAAAAAAvrwgAAAAAAAAAAAfwmKjcAAABAEV6Lzok4i4C1jJA3PVVARGx2+yfVw8odprnnnG0hqkUUwKnvVQcd59UJwbfzTG7oxR5DvxflV4aQ6RmZsIcmDQ==",
					).Return(horizonResponse, nil).Once()

					validParams.Add("memo_type", "hash")
					validParams.Add("memo", "02003AD420744CDEB8E524DEB65F38CB5095D30D000000000000000000000000")
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "b6802ab06786c923d7180236a84470c03b37ec71912bfe335d0cb57ebc534881",
					  "ledger": 1988727
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})

			Convey("source account does not exist", func() {
				mockHorizon.On(
					"LoadAccount",
					"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
				).Return(horizon.AccountResponse{}, errors.New("Not found")).Once()

				Convey("it should return error", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 400, statusCode)
					expected := test.StringToJSONMap(`{
  "code": "source_not_exist",
  "message": "Source account does not exist."
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})

			Convey("transaction failed in horizon", func() {
				mockHorizon.On(
					"LoadAccount",
					"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
				).Return(
					horizon.AccountResponse{
						SequenceNumber: "100",
					},
					nil,
				).Once()

				horizonResponse := horizon.SubmitTransactionResponse{
					Ledger: nil,
					Extras: &horizon.SubmitTransactionResponseExtras{
						EnvelopeXdr: "envelope",
						ResultXdr:   "AAAAAAAAAAD////7AAAAAA==", // tx_bad_seq
					},
				}

				mockHorizon.On(
					"SubmitTransaction",
					mock.AnythingOfType("string"),
				).Return(horizonResponse, nil).Once()

				Convey("it should return error", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 400, statusCode)
					expected := test.StringToJSONMap(`{
  "code": "transaction_bad_seq",
  "message": "Bad Sequence. Please, try again."
}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})

			Convey("transaction success (native)", func() {
				validParams := url.Values{
					// GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ
					"source":      {"SDWLS4G3XCNIYPKXJWWGGJT6UDY63WV6PEFTWP7JZMQB4RE7EUJQN5XM"},
					"destination": {"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
					"amount":      {"20"},
				}

				// Checking if destination exists
				mockHorizon.On(
					"LoadAccount",
					"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
				).Return(horizon.AccountResponse{}, nil).Once()

				// Loading sequence number
				mockHorizon.On(
					"LoadAccount",
					"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
				).Return(
					horizon.AccountResponse{
						SequenceNumber: "100",
					},
					nil,
				).Once()

				var ledger uint64
				ledger = 1988727
				horizonResponse := horizon.SubmitTransactionResponse{
					Hash:   "6a0049b44e0d0341bd52f131c74383e6ccd2b74b92c829c990994d24bbfcfa7a",
					Ledger: &ledger,
					Extras: nil,
				}

				mockHorizon.On(
					"SubmitTransaction",
					"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAA5IVbm6A8mbgc/apAizxmBf4zZmqbedR3Ke+MTa7pjVYAAAAAAAAAAAvrwgAAAAAAAAAAAfwmKjcAAABAh3M6y9LXiWD0GB1KCkgNS5H1Lnyr1wS1BsfzoM1/v0muzobwNkJinV+RcWyC8VfeKqOjKBOANJnEusl+sHkcAg==",
				).Return(horizonResponse, nil).Once()

				Convey("it should return success", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "6a0049b44e0d0341bd52f131c74383e6ccd2b74b92c829c990994d24bbfcfa7a",
					  "ledger": 1988727
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})

			Convey("transaction success (credit)", func() {
				mockHorizon.On(
					"LoadAccount",
					"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
				).Return(
					horizon.AccountResponse{
						SequenceNumber: "100",
					},
					nil,
				).Once()

				var ledger uint64
				ledger = 1988727
				horizonResponse := horizon.SubmitTransactionResponse{
					Hash:   "4c8ddbc990381d5f7fe5142be0ac70fb282e7c54347734cdd7f19716fa18930b",
					Ledger: &ledger,
					Extras: nil,
				}

				mockHorizon.On(
					"SubmitTransaction",
					"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAAAAAABAAAAAAAAAAEAAAAA5IVbm6A8mbgc/apAizxmBf4zZmqbedR3Ke+MTa7pjVYAAAABVVNEAAAAAADkhVuboDyZuBz9qkCLPGYF/jNmapt51Hcp74xNrumNVgAAAAAL68IAAAAAAAAAAAH8Jio3AAAAQHbXpCBe/lDG5rWhwNpdH+DnrkYKONvMyPJDFik5mC/gcIL9xHx3FfB+u1Ik7N9gJxi8AlRRqXo+/yCyOoQQ3Ac=",
				).Return(horizonResponse, nil).Once()

				Convey("it should return success", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "4c8ddbc990381d5f7fe5142be0ac70fb282e7c54347734cdd7f19716fa18930b",
					  "ledger": 1988727
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})
		})

		Convey("When params are valid (path payment operation)", func() {
			validParams := url.Values{
				// GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ
				"source":       {"SDWLS4G3XCNIYPKXJWWGGJT6UDY63WV6PEFTWP7JZMQB4RE7EUJQN5XM"},
				"destination":  {"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				"amount":       {"20"},
				"asset_code":   {"USD"},
				"asset_issuer": {"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				"send_max":     {"100"},
			}

			// Source
			mockHorizon.On(
				"LoadAccount",
				"GCF3WVYTHF75PEG6622G5G6KU26GOSDQPDHSCJ3DQD7VONH4EYVDOGKJ",
			).Return(
				horizon.AccountResponse{
					SequenceNumber: "100",
				},
				nil,
			).Once()

			// Destination
			mockFederationResolver.On(
				"Resolve",
				"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
			).Return(
				federation.Response{AccountID: "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"},
				stellartoml.StellarToml{},
				nil,
			).Once()

			mockHorizon.On(
				"LoadAccount",
				"GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632",
			).Return(
				horizon.AccountResponse{
					SequenceNumber: "100",
				},
				nil,
			).Once()

			Convey("transaction success (send native)", func() {
				var ledger uint64
				ledger = 1988727
				horizonResponse := horizon.SubmitTransactionResponse{
					Hash:   "88214f536658717d5a7d96e449d2fbd96277ce16f3d88dea023e5f20bd37325d",
					Ledger: &ledger,
					Extras: nil,
				}

				mockHorizon.On(
					"SubmitTransaction",
					"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAAAAAABAAAAAAAAAAIAAAAAAAAAADuaygAAAAAA5IVbm6A8mbgc/apAizxmBf4zZmqbedR3Ke+MTa7pjVYAAAABVVNEAAAAAADkhVuboDyZuBz9qkCLPGYF/jNmapt51Hcp74xNrumNVgAAAAAL68IAAAAAAAAAAAAAAAAB/CYqNwAAAECx9I76SOIjCL3pgwZdmFj9KWFzvNL82dt3+Laokh6Zm2v0o1UNq1mQsrqrv0mXM6uNcA96NbkfbogtXauHmwML",
				).Return(horizonResponse, nil).Once()

				Convey("it should return success", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "88214f536658717d5a7d96e449d2fbd96277ce16f3d88dea023e5f20bd37325d",
					  "ledger": 1988727
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})

			Convey("transaction success (send credit)", func() {
				validParams["send_asset_code"] = []string{"USD"}
				validParams["send_asset_issuer"] = []string{"GBDOSO3K4JTGSWJSIHXAOFIBMAABVM3YK3FI6VJPKIHHM56XAFIUCGD6"}

				var ledger uint64
				ledger = 1988727
				horizonResponse := horizon.SubmitTransactionResponse{
					Hash:   "8d143f846c2e0ce20364be737c2ebdbcd0da307b4952ec8e91ffcbbc6f51f5ce",
					Ledger: &ledger,
					Extras: nil,
				}

				mockHorizon.On(
					"SubmitTransaction",
					"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAAAAAABAAAAAAAAAAIAAAABVVNEAAAAAABG6Ttq4mZpWTJB7gcVAWAAGrN4VsqPVS9SDnZ31wFRQQAAAAA7msoAAAAAAOSFW5ugPJm4HP2qQIs8ZgX+M2Zqm3nUdynvjE2u6Y1WAAAAAVVTRAAAAAAA5IVbm6A8mbgc/apAizxmBf4zZmqbedR3Ke+MTa7pjVYAAAAAC+vCAAAAAAAAAAAAAAAAAfwmKjcAAABA3rQOu+r9DvUhGDSOVaD05RWgzvzMJt49opYNfGLLOSo7/29rUkPIyw5PgV/1arrTwj90HRnzmVjHJK2xy+MfBQ==",
				).Return(horizonResponse, nil).Once()

				Convey("it should return success", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "8d143f846c2e0ce20364be737c2ebdbcd0da307b4952ec8e91ffcbbc6f51f5ce",
					  "ledger": 1988727
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})

			Convey("transaction success (path)", func() {
				validParams["send_asset_code"] = []string{"USD"}
				validParams["send_asset_issuer"] = []string{"GBDOSO3K4JTGSWJSIHXAOFIBMAABVM3YK3FI6VJPKIHHM56XAFIUCGD6"}

				// Native
				validParams["path[0][asset_code]"] = []string{""}
				validParams["path[0][asset_issuer]"] = []string{""}
				// Credit
				validParams["path[1][asset_code]"] = []string{"EUR"}
				validParams["path[1][asset_issuer]"] = []string{"GAF3PBFQLH57KPECN4GRGHU5NUZ3XXKYYWLOTBIRJMBYHPUBWANIUCZU"}

				var ledger uint64
				ledger = 1988727
				resultXdr := "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAACAAAAAAAAAAEAAAAAC8RjSvPMPWeQWzLq8JEM0BQNo0TfJQN/RwkCeJ+rT+YAAAAAAAAAAwAAAAFaQVIAAAAAAGDBYXf7bGrEkzodp+6aowtAynuEqzKzZRZKO2ftxMtDAAAAAa9EDYAAAAABVVNEAAAAAABstavC6cvn5h86pWOK5996Ape9k8mMM+Fgzqdp6J+9BwAAAAAeMEigAAAAAOj2P+n5SvD0Amrc4BYc6Zo8n6i6idQPeJdfwuvX+FVbAAAAAVpBUgAAAAAAYMFhd/tsasSTOh2n7pqjC0DKe4SrMrNlFko7Z+3Ey0MAAAABr0QNgAAAAAA="
				horizonResponse := horizon.SubmitTransactionResponse{
					Hash:      "be2765c309ab6911fe3938de0053672ef541290333a59dfb750f07919e9d6fec",
					Ledger:    &ledger,
					ResultXdr: &resultXdr,
					Extras:    nil,
				}

				mockHorizon.On(
					"SubmitTransaction",
					"AAAAAIu7VxM5f9eQ3va0bpvKprxnSHB4zyEnY4D/VzT8Jio3AAAAZAAAAAAAAABlAAAAAAAAAAAAAAABAAAAAAAAAAIAAAABVVNEAAAAAABG6Ttq4mZpWTJB7gcVAWAAGrN4VsqPVS9SDnZ31wFRQQAAAAA7msoAAAAAAOSFW5ugPJm4HP2qQIs8ZgX+M2Zqm3nUdynvjE2u6Y1WAAAAAVVTRAAAAAAA5IVbm6A8mbgc/apAizxmBf4zZmqbedR3Ke+MTa7pjVYAAAAAC+vCAAAAAAIAAAAAAAAAAUVVUgAAAAAAC7eEsFn79TyCbw0THp1tM7vdWMWW6YURSwODvoGwGooAAAAAAAAAAfwmKjcAAABAyO0YxnfaIdY51J9BaPyZYNxsBY2AhWCZpK6FRlaE+ZbdmznZ9cio2G7+fJgl3hWZUrQknQHElmzAZdgsqNnZAQ==",
				).Return(horizonResponse, nil).Once()

				Convey("it should return success", func() {
					statusCode, response := net.GetResponse(testServer, validParams)
					responseString := strings.TrimSpace(string(response))

					assert.Equal(t, 200, statusCode)
					expected := test.StringToJSONMap(`{
					  "hash": "be2765c309ab6911fe3938de0053672ef541290333a59dfb750f07919e9d6fec",
					  "ledger": 1988727,
					  "send_amount": "50.6480800",
					  "result_xdr": "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAACAAAAAAAAAAEAAAAAC8RjSvPMPWeQWzLq8JEM0BQNo0TfJQN/RwkCeJ+rT+YAAAAAAAAAAwAAAAFaQVIAAAAAAGDBYXf7bGrEkzodp+6aowtAynuEqzKzZRZKO2ftxMtDAAAAAa9EDYAAAAABVVNEAAAAAABstavC6cvn5h86pWOK5996Ape9k8mMM+Fgzqdp6J+9BwAAAAAeMEigAAAAAOj2P+n5SvD0Amrc4BYc6Zo8n6i6idQPeJdfwuvX+FVbAAAAAVpBUgAAAAAAYMFhd/tsasSTOh2n7pqjC0DKe4SrMrNlFko7Z+3Ey0MAAAABr0QNgAAAAAA="
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))
				})
			})
		})
	})

	Convey("Given payment compliance request", t, func() {
		Convey("When params are valid", func() {
			params := url.Values{
				// GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD
				"source":       {"SARMR3N465GTEHQLR3TSHDD7FHFC2I22ECFLYCHAZDEJWBVED66RW7FQ"},
				"sender":       {"alice*stellar.org"}, // GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD
				"destination":  {"bob*stellar.org"},   // GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE
				"amount":       {"20"},
				"asset_code":   {"USD"},
				"asset_issuer": {"GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE"},
				"extra_memo":   {"hello world"},
			}

			Convey("it should return error when compliance server returns error", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://compliance/send",
					mock.AnythingOfType("url.Values"),
				).Return(
					net.BuildHTTPResponse(400, "error"),
					nil,
				).Run(func(args mock.Arguments) {
					values := args.Get(1).(url.Values)
					// bridge server does not send source seed to compliance
					assert.Equal(t, []string{"GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD"}, values["source"])
					values.Del("source")
					params.Del("source")
					assert.Equal(t, values.Encode(), params.Encode())
				}).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 500, statusCode)
				expected := test.StringToJSONMap(`{
  "code": "internal_server_error",
  "message": "Internal Server Error, please try again."
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("it should return denied when compliance server returns denied", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://compliance/send",
					mock.AnythingOfType("url.Values"),
				).Return(
					net.BuildHTTPResponse(200, "{\"auth_response\": {\"tx_status\": \"denied\"}}"),
					nil,
				).Run(func(args mock.Arguments) {
					values := args.Get(1).(url.Values)
					// bridge server does not send source seed to compliance
					assert.Equal(t, []string{"GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD"}, values["source"])
					values.Del("source")
					params.Del("source")
					assert.Equal(t, values.Encode(), params.Encode())
				}).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 403, statusCode)
				expected := test.StringToJSONMap(`{
  "code": "denied",
  "message": "Transaction denied by destination."
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("it should return pending when compliance server returns pending", func() {
				mockHTTPClient.On(
					"PostForm",
					"http://compliance/send",
					mock.AnythingOfType("url.Values"),
				).Return(
					net.BuildHTTPResponse(200, "{\"auth_response\": {\"info_status\": \"pending\", \"pending\": 3600}}"),
					nil,
				).Run(func(args mock.Arguments) {
					values := args.Get(1).(url.Values)
					// bridge server does not send source seed to compliance
					assert.Equal(t, []string{"GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD"}, values["source"])
					values.Del("source")
					params.Del("source")
					assert.Equal(t, values.Encode(), params.Encode())
				}).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 202, statusCode)
				expected := test.StringToJSONMap(`{
  "code": "pending",
  "message": "Transaction pending. Repeat your request after given time.",
  "data": {
    "pending": 3600
  }
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("it should submit transaction when compliance server returns success", func() {
				memoBytes, _ := hex.DecodeString("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9")
				var hashXdr xdr.Hash
				copy(hashXdr[:], memoBytes[:])
				memo, _ := xdr.NewMemo(xdr.MemoTypeMemoHash, hashXdr)

				sourceBytes, _ := hex.DecodeString("2dffe7c67daf270d2e617abe8597f559831131551a116859feba99c32e8abfc3")
				var sourceXdr xdr.Uint256
				copy(sourceXdr[:], sourceBytes[:])

				destinationBytes, _ := hex.DecodeString("1952fcdc3245c07d2c2a6cba008809603ec67b1883d18bb348c8a8042014389c")
				var destinationXdr xdr.Uint256
				copy(destinationXdr[:], destinationBytes[:])

				issuerBytes, _ := hex.DecodeString("1952fcdc3245c07d2c2a6cba008809603ec67b1883d18bb348c8a8042014389c")
				var issuerXdr xdr.Uint256
				copy(issuerXdr[:], issuerBytes[:])

				expectedTx := &xdr.Transaction{
					SourceAccount: xdr.AccountId{
						Type:    xdr.CryptoKeyTypeKeyTypeEd25519,
						Ed25519: &sourceXdr,
					},
					Fee:    100,
					SeqNum: 0,
					Memo:   memo,
					Operations: []xdr.Operation{
						{
							Body: xdr.OperationBody{
								Type: xdr.OperationTypePayment,
								PaymentOp: &xdr.PaymentOp{
									Destination: xdr.AccountId{
										Type:    xdr.CryptoKeyTypeKeyTypeEd25519,
										Ed25519: &destinationXdr,
									},
									Amount: 200000000,
									Asset: xdr.Asset{
										Type: xdr.AssetTypeAssetTypeCreditAlphanum4,
										AlphaNum4: &xdr.AssetAlphaNum4{
											AssetCode: [4]byte{'U', 'S', 'D', 0},
											Issuer: xdr.AccountId{
												Type:    xdr.CryptoKeyTypeKeyTypeEd25519,
												Ed25519: &issuerXdr,
											},
										},
									},
								},
							},
						},
					},
				}

				complianceResponse := compliance.SendResponse{
					TransactionXdr: "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAAO5TSe5k00+CKUuUtfafav6xITv43pTgO6QiPes4u/N6QAAAAEAAAAAAAAAAQAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAFVU0QAAAAAABlS/NwyRcB9LCpsugCICWA+xnsYg9GLs0jIqAQgFDicAAAAAAvrwgAAAAAA",
				}

				mockHTTPClient.On(
					"PostForm",
					"http://compliance/send",
					mock.AnythingOfType("url.Values"),
				).Return(
					net.BuildHTTPResponse(200, string(complianceResponse.Marshal())),
					nil,
				).Run(func(args mock.Arguments) {
					values := args.Get(1).(url.Values)
					assert.Equal(t, []string{"GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD"}, values["source"])
					values.Del("source")
					params.Del("source")
					assert.Equal(t, values.Encode(), params.Encode())
				}).Once()

				var ledger uint64
				ledger = 1988727
				horizonResponse := horizon.SubmitTransactionResponse{
					Hash:   "6a0049b44e0d0341bd52f131c74383e6ccd2b74b92c829c990994d24bbfcfa7a",
					Ledger: &ledger,
					Extras: nil,
				}

				mockTransactionSubmitter.On(
					"SignAndSubmitRawTransaction",
					params.Get("source"),
					mock.AnythingOfType("*xdr.Transaction"),
				).Run(func(args mock.Arguments) {
					tx := args.Get(1).(*xdr.Transaction)
					assert.Equal(t, *tx, *expectedTx)
				}).Return(horizonResponse, nil).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
				  "hash": "6a0049b44e0d0341bd52f131c74383e6ccd2b74b92c829c990994d24bbfcfa7a",
				  "ledger": 1988727
				}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})
	})
}
func TestRequestHandlerAuthorize(t *testing.T) {
	mockTransactionSubmitter := new(mocks.MockTransactionSubmitter)

	config := config.Config{
		Assets: []config.Asset{
			{Code: "USD", Issuer: "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR"},
			{Code: "EUR", Issuer: "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR"},
		},
		Accounts: config.Accounts{
			IssuingAccountID: "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR",
			// GBQXA3ABGQGTCLEVZIUTDRWWJOQD5LSAEDZAG7GMOGD2HBLWONGUVO4I
			AuthorizingSeed: "SC37TBSIAYKIDQ6GTGLT2HSORLIHZQHBXVFI5P5K4Q5TSHRTRBK3UNWG",
		},
	}

	requestHandler := RequestHandler{Config: &config, TransactionSubmitter: mockTransactionSubmitter}
	testServer := httptest.NewServer(http.HandlerFunc(requestHandler.Authorize))
	defer testServer.Close()

	Convey("Given authorize request", t, func() {
		Convey("When accountId is invalid", func() {
			accountID := "GD3YBOYIUVLU"
			assetCode := "USD"

			Convey("it should return error", func() {
				statusCode, response := net.GetResponse(testServer, url.Values{"account_id": {accountID}, "asset_code": {assetCode}})
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 400, statusCode)
				expected := test.StringToJSONMap(`{
				  "code": "invalid_parameter",
				  "message": "Invalid parameter.",
				  "data": {
				    "name": "account_id"
				  }
				}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("When assetCode is invalid", func() {
			accountID := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"
			assetCode := "GBP"

			Convey("it should return error", func() {
				statusCode, response := net.GetResponse(testServer, url.Values{"account_id": {accountID}, "asset_code": {assetCode}})
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 400, statusCode)
				expected := test.StringToJSONMap(`{
				  "code": "invalid_parameter",
				  "message": "Invalid parameter.",
				  "data": {
				    "name": "asset_code"
				  }
				}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("When params are valid", func() {
			accountID := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632"
			assetCode := "USD"

			operation := b.AllowTrust(
				b.Trustor{accountID},
				b.Authorize{true},
				b.AllowTrustAsset{assetCode},
			)

			Convey("transaction fails", func() {
				mockTransactionSubmitter.On(
					"SubmitTransaction",
					config.Accounts.AuthorizingSeed,
					operation,
					nil,
				).Return(
					horizon.SubmitTransactionResponse{},
					errors.New("Error sending transaction"),
				).Once()

				Convey("it should return server error", func() {
					statusCode, response := net.GetResponse(testServer, url.Values{"account_id": {accountID}, "asset_code": {assetCode}})
					responseString := strings.TrimSpace(string(response))
					assert.Equal(t, 500, statusCode)
					expected := test.StringToJSONMap(`{
					  "code": "internal_server_error",
					  "message": "Internal Server Error, please try again."
					}`)
					assert.Equal(t, expected, test.StringToJSONMap(responseString))

					mockTransactionSubmitter.AssertExpectations(t)
				})
			})

			Convey("transaction succeeds", func() {
				var ledger uint64
				ledger = 100
				expectedSubmitResponse := horizon.SubmitTransactionResponse{
					Ledger: &ledger,
				}

				mockTransactionSubmitter.On(
					"SubmitTransaction",
					config.Accounts.AuthorizingSeed,
					operation,
					nil,
				).Return(expectedSubmitResponse, nil).Once()

				Convey("it should succeed", func() {
					statusCode, response := net.GetResponse(testServer, url.Values{"account_id": {accountID}, "asset_code": {assetCode}})
					var actualSubmitTransactionResponse horizon.SubmitTransactionResponse
					json.Unmarshal(response, &actualSubmitTransactionResponse)
					assert.Equal(t, 200, statusCode)
					assert.Equal(t, expectedSubmitResponse, actualSubmitTransactionResponse)
					mockTransactionSubmitter.AssertExpectations(t)
				})
			})
		})
	})
}
func TestRequestHandlerSend(t *testing.T) {
	c := &config.Config{
		NetworkPassphrase: "Test SDF Network ; September 2015",
		Keys: config.Keys{
			// GBYJZW5XFAI6XV73H5SAIUYK6XZI4CGGVBUBO3ANA2SV7KKDAXTV6AEB
			SigningSeed: "SDWTLFPALQSP225BSMX7HPZ7ZEAYSUYNDLJ5QI3YGVBNRUIIELWH3XUV",
		},
		Callbacks: config.Callbacks{
			FetchInfo: "http://fetch_info",
		},
	}

	mockHTTPClient := new(mocks.MockHTTPClient)
	mockEntityManager := new(mocks.MockEntityManager)
	mockRepository := new(mocks.MockRepository)
	mockFederationResolver := new(mocks.MockFederationResolver)
	mockSignerVerifier := new(mocks.MockSignerVerifier)
	mockStellartomlResolver := new(mocks.MockStellartomlResolver)
	requestHandler := RequestHandler{}

	// Inject mocks
	var g inject.Graph

	err := g.Provide(
		&inject.Object{Value: &requestHandler},
		&inject.Object{Value: c},
		&inject.Object{Value: mockHTTPClient},
		&inject.Object{Value: mockEntityManager},
		&inject.Object{Value: mockRepository},
		&inject.Object{Value: mockFederationResolver},
		&inject.Object{Value: mockSignerVerifier},
		&inject.Object{Value: mockStellartomlResolver},
	)
	if err != nil {
		panic(err)
	}

	if err := g.Populate(); err != nil {
		panic(err)
	}

	httpHandle := func(w http.ResponseWriter, r *http.Request) {
		requestHandler.HandlerSend(web.C{}, w, r)
	}

	testServer := httptest.NewServer(http.HandlerFunc(httpHandle))
	defer testServer.Close()

	Convey("Given send request", t, func() {
		Convey("When source param is missing", func() {
			statusCode, response := net.GetResponse(testServer, url.Values{})
			responseString := strings.TrimSpace(string(response))
			assert.Equal(t, 400, statusCode)
			expected := test.StringToJSONMap(`{
			  "code": "missing_parameter",
			  "message": "Required parameter is missing.",
			  "data": {
			    "name": "source"
			  }
			}`)
			assert.Equal(t, expected, test.StringToJSONMap(responseString))
		})

		Convey("When source param is invalid", func() {
			params := url.Values{
				"source":       {"bad"},
				"sender":       {"alice*stellar.org"}, // GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD
				"destination":  {"bob*stellar.org"},   // GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE
				"amount":       {"20"},
				"asset_code":   {"USD"},
				"asset_issuer": {"GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE"},
				"extra_memo":   {"hello world"},
			}

			statusCode, response := net.GetResponse(testServer, params)
			responseString := strings.TrimSpace(string(response))
			assert.Equal(t, 400, statusCode)
			expected := test.StringToJSONMap(`{
			  "code": "invalid_parameter",
			  "message": "Invalid parameter.",
			  "data": {
			    "name": "source"
			  }
			}`)
			assert.Equal(t, expected, test.StringToJSONMap(responseString))
		})

		Convey("When params are valid", func() {
			params := url.Values{
				"source":       {"GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD"},
				"sender":       {"alice*stellar.org"}, // GAW77Z6GPWXSODJOMF5L5BMX6VMYGEJRKUNBC2CZ725JTQZORK74HQQD
				"destination":  {"bob*stellar.org"},   // GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE
				"amount":       {"20"},
				"asset_code":   {"USD"},
				"asset_issuer": {"GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE"},
				"extra_memo":   {"hello world"},
			}

			Convey("it returns SendResponse when success (payment)", func() {
				authServer := "https://acme.com/auth"

				mockFederationResolver.On(
					"Resolve",
					"bob*stellar.org",
				).Return(federation.Response{
					AccountID: "GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE",
					MemoType:  "text",
					Memo:      "bob",
				}, stellartoml.StellarToml{
					AuthServer: authServer,
				}, nil).Once()

				transactionXdr := "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANLw6drH5OZQsQFOcJZvFBrx8zFYFlryZWs/9cwBTVH5QAAAAEAAAAAAAAAAQAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAFVU0QAAAAAABlS/NwyRcB9LCpsugCICWA+xnsYg9GLs0jIqAQgFDicAAAAAAvrwgAAAAAA"
				data := "{\"sender\":\"alice*stellar.org\",\"need_info\":false,\"tx\":\"" + transactionXdr + "\",\"memo\":\"{\\n  \\\"transaction\\\": {\\n    \\\"sender_info\\\": \\\"{\\\\\\\"name\\\\\\\": \\\\\\\"Alice Doe\\\\\\\"}\\\",\\n    \\\"route\\\": \\\"bob\\\",\\n    \\\"extra\\\": \\\"hello world\\\",\\n    \\\"note\\\": \\\"\\\"\\n  },\\n  \\\"operations\\\": null\\n}\"}"
				sig := "YeMlOYWNysyGBfsAe40z9dGgpRsKSQrqFIGAEsyJQ8osnXlLPynvJ2WQDGcBq2n5AA96YZdABhQz5ymqvxfQDw=="

				authResponse := compliance.AuthResponse{
					InfoStatus: compliance.AuthStatusOk,
					TxStatus:   compliance.AuthStatusOk,
				}

				mockHTTPClient.On(
					"PostForm",
					c.Callbacks.FetchInfo,
					url.Values{"address": {"alice*stellar.org"}},
				).Return(
					net.BuildHTTPResponse(200, "{\"name\": \"Alice Doe\"}"),
					nil,
				).Once()

				mockHTTPClient.On(
					"PostForm",
					authServer,
					url.Values{"data": {data}, "sig": {sig}},
				).Return(
					net.BuildHTTPResponse(200, string(authResponse.Marshal())),
					nil,
				).Once()

				mockSignerVerifier.On(
					"Sign",
					c.Keys.SigningSeed,
					[]byte(data),
				).Return(sig, nil).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
				  "auth_response": {
				    "info_status": "ok",
				    "tx_status": "ok"
				  },
				  "transaction_xdr": "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANLw6drH5OZQsQFOcJZvFBrx8zFYFlryZWs/9cwBTVH5QAAAAEAAAAAAAAAAQAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAFVU0QAAAAAABlS/NwyRcB9LCpsugCICWA+xnsYg9GLs0jIqAQgFDicAAAAAAvrwgAAAAAA"
				}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})

			Convey("it returns SendResponse when success (path payment)", func() {
				params["send_max"] = []string{"100"}
				params["send_asset_code"] = []string{"USD"}
				params["send_asset_issuer"] = []string{"GBDOSO3K4JTGSWJSIHXAOFIBMAABVM3YK3FI6VJPKIHHM56XAFIUCGD6"}

				// Native
				params["path[0][asset_code]"] = []string{""}
				params["path[0][asset_issuer]"] = []string{""}
				// Credit
				params["path[1][asset_code]"] = []string{"EUR"}
				params["path[1][asset_issuer]"] = []string{"GAF3PBFQLH57KPECN4GRGHU5NUZ3XXKYYWLOTBIRJMBYHPUBWANIUCZU"}

				authServer := "https://acme.com/auth"

				mockFederationResolver.On(
					"Resolve",
					"bob*stellar.org",
				).Return(federation.Response{
					AccountID: "GAMVF7G4GJC4A7JMFJWLUAEIBFQD5RT3DCB5DC5TJDEKQBBACQ4JZVEE",
					MemoType:  "text",
					Memo:      "bob",
				}, stellartoml.StellarToml{
					AuthServer: authServer,
				}, nil).Once()

				transactionXdr := "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANLw6drH5OZQsQFOcJZvFBrx8zFYFlryZWs/9cwBTVH5QAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA="
				data := "{\"sender\":\"alice*stellar.org\",\"need_info\":false,\"tx\":\"" + transactionXdr + "\",\"memo\":\"{\\n  \\\"transaction\\\": {\\n    \\\"sender_info\\\": \\\"{\\\\\\\"name\\\\\\\": \\\\\\\"Alice Doe\\\\\\\"}\\\",\\n    \\\"route\\\": \\\"bob\\\",\\n    \\\"extra\\\": \\\"hello world\\\",\\n    \\\"note\\\": \\\"\\\"\\n  },\\n  \\\"operations\\\": null\\n}\"}"
				sig := "ACamNqa0dF8gf97URhFVKWSD7fmvZKc5At+8dCLM5ySR0HsHySF3G2WuwYP2nKjeqjKmu3U9Z3+u1P10w1KBCA=="

				authResponse := compliance.AuthResponse{
					InfoStatus: compliance.AuthStatusOk,
					TxStatus:   compliance.AuthStatusOk,
				}

				mockHTTPClient.On(
					"PostForm",
					c.Callbacks.FetchInfo,
					url.Values{"address": {"alice*stellar.org"}},
				).Return(
					net.BuildHTTPResponse(200, "{\"name\": \"Alice Doe\"}"),
					nil,
				).Once()

				mockHTTPClient.On(
					"PostForm",
					authServer,
					url.Values{"data": {data}, "sig": {sig}},
				).Return(
					net.BuildHTTPResponse(200, string(authResponse.Marshal())),
					nil,
				).Once()

				mockSignerVerifier.On(
					"Sign",
					c.Keys.SigningSeed,
					[]byte(data),
				).Return(sig, nil).Once()

				statusCode, response := net.GetResponse(testServer, params)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
				  "auth_response": {
				    "info_status": "ok",
				    "tx_status": "ok"
				  },
				  "transaction_xdr": "AAAAAC3/58Z9rycNLmF6voWX9VmDETFVGhFoWf66mcMuir/DAAAAZAAAAAAAAAAAAAAAAAAAAANLw6drH5OZQsQFOcJZvFBrx8zFYFlryZWs/9cwBTVH5QAAAAEAAAAAAAAAAgAAAAFVU0QAAAAAAEbpO2riZmlZMkHuBxUBYAAas3hWyo9VL1IOdnfXAVFBAAAAADuaygAAAAAAGVL83DJFwH0sKmy6AIgJYD7GexiD0YuzSMioBCAUOJwAAAABVVNEAAAAAAAZUvzcMkXAfSwqbLoAiAlgPsZ7GIPRi7NIyKgEIBQ4nAAAAAAL68IAAAAAAgAAAAAAAAABRVVSAAAAAAALt4SwWfv1PIJvDRMenW0zu91YxZbphRFLA4O+gbAaigAAAAA="
				}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})
	})
}
func TestRequestHandlerBuilder(t *testing.T) {
	c := &config.Config{NetworkPassphrase: "Test SDF Network ; September 2015"}
	mockHorizon := new(mocks.MockHorizon)
	mockHTTPClient := new(mocks.MockHTTPClient)
	mockTransactionSubmitter := new(mocks.MockTransactionSubmitter)
	mockFederationResolver := new(mocks.MockFederationResolver)
	mockStellartomlResolver := new(mocks.MockStellartomlResolver)
	requestHandler := RequestHandler{}

	// Inject mocks
	var g inject.Graph

	err := g.Provide(
		&inject.Object{Value: &requestHandler},
		&inject.Object{Value: c},
		&inject.Object{Value: mockHorizon},
		&inject.Object{Value: mockHTTPClient},
		&inject.Object{Value: mockTransactionSubmitter},
		&inject.Object{Value: mockFederationResolver},
		&inject.Object{Value: mockStellartomlResolver},
	)
	if err != nil {
		panic(err)
	}

	if err := g.Populate(); err != nil {
		panic(err)
	}

	testServer := httptest.NewServer(http.HandlerFunc(requestHandler.Builder))
	defer testServer.Close()

	Convey("Builder", t, func() {
		Convey("CreateAccount", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "create_account",
        "body": {
        	"destination": "GCOEGO43PFSLE4K7WRZQNRO3PIOTRLKRASP32W7DSPBF65XFT4V6PSV3",
        	"starting_balance": "50"
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAnEM7m3lksnFftHMGxdt6HTitUQSfvVvjk8JfduWfK+cAAAAAHc1lAAAAAAAAAAABn420/AAAAECXY+neSolhAeHUXf+UrOV6PjeJnvLM/HqjOlOEWD3hmu/z9aBksDu9zqa26jS14eMpZzq8sofnnvt248FUO+cP"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("Payment", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "payment",
        "body": {
        	"destination": "GCOEGO43PFSLE4K7WRZQNRO3PIOTRLKRASP32W7DSPBF65XFT4V6PSV3",
        	"amount": "100",
        	"asset": {
        		"code": "USD",
        		"issuer": "GACETOPHMOLSZLG5IQ3D6KQDKCAAYUYTTQHIEY6IGZE4VOBDD2YY6YAO"
        	}
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAEAAAAAnEM7m3lksnFftHMGxdt6HTitUQSfvVvjk8JfduWfK+cAAAABVVNEAAAAAAAESbnnY5csrN1ENj8qA1CADFMTnA6CY8g2Scq4Ix6xjwAAAAA7msoAAAAAAAAAAAGfjbT8AAAAQGlQbmCv74lzQpjUOn8dsQ9/BFCKHSev6DLo4lS2wcS20GpfIjGZSXIAry/3porFM+3xrvBWlIH9Tr/QFKjqRAU="
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("PathPayment", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "path_payment",
        "body": {
        	"source": "GBYLUAJBHGZMVAYCALM4ZRTAOY74NTSSULG42VKVY2EOWS5X2HFBB2VL",
        	"destination": "GCOEGO43PFSLE4K7WRZQNRO3PIOTRLKRASP32W7DSPBF65XFT4V6PSV3",
        	"destination_amount": "500",
        	"destination_asset": {
        		"code": "EUR",
        		"issuer": "GDOJMKTDLGGLROSSM5BV5MXIAQ3JZHASQFUV55WBJ45AFOUXSVVFGPTJ"
        	},
        	"send_max": "100",
        	"send_asset": {
        		"code": "USD",
        		"issuer": "GACETOPHMOLSZLG5IQ3D6KQDKCAAYUYTTQHIEY6IGZE4VOBDD2YY6YAO"
        	},
        	"path": [
        		{
	        		"code": "ABCDEFG",
	        		"issuer": "GD4RIHH2HWB4MPJN72G2VGLRPUXDODFNQG6DVU47HMSSSF3RIQ4UXALD"
	        	},
	        	{}
        	]
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAQAAAABwugEhObLKgwIC2czGYHY/xs5Sos3NVVXGiOtLt9HKEAAAAAIAAAABVVNEAAAAAAAESbnnY5csrN1ENj8qA1CADFMTnA6CY8g2Scq4Ix6xjwAAAAA7msoAAAAAAJxDO5t5ZLJxX7RzBsXbeh04rVEEn71b45PCX3blnyvnAAAAAUVVUgAAAAAA3JYqY1mMuLpSZ0NesugENpycEoFpXvbBTzoCupeValMAAAABKgXyAAAAAAIAAAACQUJDREVGRwAAAAAAAAAAAPkUHPo9g8Y9Lf6NqplxfS43DK2BvDrTnzslKRdxRDlLAAAAAAAAAAAAAAABn420/AAAAEA9DEvKZhLwLcStP8/ZsqaEAdlNc91Eyz5mLUiN19etsIYaTPNugsVEWYJOiulXXSIwwitoyxQ1t2jr6VS0mXcB"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("ManageOffer", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "manage_offer",
        "body": {
        	"selling": {
        		"code": "EUR",
        		"issuer": "GDOJMKTDLGGLROSSM5BV5MXIAQ3JZHASQFUV55WBJ45AFOUXSVVFGPTJ"
        	},
        	"buying": {
        		"code": "USD",
        		"issuer": "GACETOPHMOLSZLG5IQ3D6KQDKCAAYUYTTQHIEY6IGZE4VOBDD2YY6YAO"
        	},
        	"amount": "123456",
        	"price": "2.93850088",
        	"offer_id": "100"
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAMAAAABRVVSAAAAAADclipjWYy4ulJnQ16y6AQ2nJwSgWle9sFPOgK6l5VqUwAAAAFVU0QAAAAAAARJuedjlyys3UQ2PyoDUIAMUxOcDoJjyDZJyrgjHrGPAAABH3GCoAACMHl9AL68IAAAAAAAAABkAAAAAAAAAAGfjbT8AAAAQEpMML2mghfM2Dzkpw6eT1N00rrIC7v3xe8zy7yc8rcGzFxIw/4/E69uq+rst+xDoeMTn0b3iBtjr2DEV52o/wE="
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("CreatePassiveOffer", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "create_passive_offer",
        "body": {
        	"selling": {
        		"code": "EUR",
        		"issuer": "GDOJMKTDLGGLROSSM5BV5MXIAQ3JZHASQFUV55WBJ45AFOUXSVVFGPTJ"
        	},
        	"buying": {
        		"code": "USD",
        		"issuer": "GACETOPHMOLSZLG5IQ3D6KQDKCAAYUYTTQHIEY6IGZE4VOBDD2YY6YAO"
        	},
        	"amount": "123456",
        	"price": "2.93850088"
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAQAAAABRVVSAAAAAADclipjWYy4ulJnQ16y6AQ2nJwSgWle9sFPOgK6l5VqUwAAAAFVU0QAAAAAAARJuedjlyys3UQ2PyoDUIAMUxOcDoJjyDZJyrgjHrGPAAABH3GCoAACMHl9AL68IAAAAAAAAAABn420/AAAAEAtK8juIThYp4LXtgpN8gVNRR42iiR6tz8euSKqqqzKGELCHcPrmFUuYqtecrJi8CyPCYTp0nqGY9mtJCHFYpsC"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("SetOptions", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "set_options",
        "body": {
        	"inflation_dest": "GBMPZVOMJ67WQBTBCVURDKTGL4557272EGQMAJCXPSMLOE63XPLL6SVA",
        	"set_flags": [1, 2],
        	"clear_flags": [4],
        	"master_weight": 100,
        	"low_threshold": 1,
        	"medium_threshold": 2,
        	"high_threshold": 3,
        	"home_domain": "stellar.org",
        	"signer": {
        		"public_key": "GA6VMJJQM2QBPPIXK2UVTAOS4XSSSAKSCOGFQE55IMRBQR65GIVDTTQV",
        		"weight": 5
        	}
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAUAAAABAAAAAFj81cxPv2gGYRVpEapmXzvf6/ohoMAkV3yYtxPbu9a/AAAAAQAAAAQAAAABAAAAAwAAAAEAAABkAAAAAQAAAAEAAAABAAAAAgAAAAEAAAADAAAAAQAAAAtzdGVsbGFyLm9yZwAAAAABAAAAAD1WJTBmoBe9F1apWYHS5eUpAVITjFgTvUMiGEfdMio5AAAABQAAAAAAAAABn420/AAAAEAtQAlVOLBR6sb/YHRg7XcSEPSJ07irs6cCSDpK95rYE7Ga5ghiLXHqRJQ2B9cMmf8FYqzeaHdYPiESZqowhb0F"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("ChangeTrust", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "change_trust",
        "body": {
        	"asset": {
        		"code": "USD",
        		"issuer": "GCHGRVNTXAV3OXNMCSA63BUCD6AZZX6PN2542QB6GIVTXGHQ65XS35DS"
        	}
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAYAAAABVVNEAAAAAACOaNWzuCu3XawUge2Ggh+BnN/PbrvNQD4yKzuY8PdvLX//////////AAAAAAAAAAGfjbT8AAAAQFftcSiqTvZOQwDJnoJ7buLgYXyjRacggCZ7yEhnPN4eXxlpQycvLLFa3U8xv0Mcnx5frSNKxu0sDIOm88Iicw8="
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("AllowTrust", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "allow_trust",
        "body": {
        	"asset_code": "USDUSD",
        	"trustor": "GBLH67TQHRNRLERQEIQJDNBV2DSWPHAPP43MBIF7DVKA7X55APUNS4LL",
        	"authorize": true
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAcAAAAAVn9+cDxbFZIwIiCRtDXQ5WecD382wKC/HVQP370D6NkAAAACVVNEVVNEAAAAAAAAAAAAAQAAAAAAAAABn420/AAAAEA9Ht9mJaKdYoRg/rAX/cl/Q89Juhmi8f7iGBdCrSVAs+VN7NVJXR+0aZpoZIjcJD/QBPiuzZIK1ea2fN7I0I8J"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("AccountMerge", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "account_merge",
        "body": {
        	"destination": "GBLH67TQHRNRLERQEIQJDNBV2DSWPHAPP43MBIF7DVKA7X55APUNS4LL"
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAgAAAAAVn9+cDxbFZIwIiCRtDXQ5WecD382wKC/HVQP370D6NkAAAAAAAAAAZ+NtPwAAABALCyRn/E/CgLdPWGgP+1pd2Lkf3jWgNANKQ4QeGgUxgROhqkTUXaPA6XzOWS8yUpzZMufl6nkh8UFqa6Hc1emCA=="
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("Inflation", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "inflation",
        "body": {}
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAkAAAAAAAAAAZ+NtPwAAABAlBFCwJ3VzBd+CE+n3mA4t71SVrDIjSgRyBnz9zYLN7qkqu8AD6cyvMRj8/alSozSPAZcSe+qBEO7E5biR+YrAA=="
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})

		Convey("ManageData", func() {
			data := test.StringToJSONMap(`{
  "source": "GBWJES3WOKK7PRLJKZVGIPVFGQSSGCRMY7H3GCZ7BEG6ZTDB4FZXTPJ5",
  "sequence_number": "123",
  "operations": [
    {
        "type": "manage_data",
        "body": {
        	"name": "test_data",
        	"data": "AQIDBAUG"
        }
    }
  ],
  "signers": ["SABY7FRMMJWPBTKQQ2ZN43AUJQ3Z2ZAK36VYSG2SPE2ABNQXA66H5E5G"]
}`)

			Convey("it should return correct XDR", func() {
				statusCode, response := net.JSONGetResponse(testServer, data)
				responseString := strings.TrimSpace(string(response))
				assert.Equal(t, 200, statusCode)
				expected := test.StringToJSONMap(`{
  "transaction_envelope": "AAAAAGySS3ZylffFaVZqZD6lNCUjCizHz7MLPwkN7Mxh4XN5AAAAZAAAAAAAAAB7AAAAAAAAAAAAAAABAAAAAAAAAAoAAAAJdGVzdF9kYXRhAAAAAAAAAQAAAAYBAgMEBQYAAAAAAAAAAAABn420/AAAAEBkO27ebDbsn1WzzLH5lUfJH3Y0Pgd1dlRx3Ip1dEZkvRPFFDLZuXi5DlW9uxNgeqThNsqnK7PPHfhyuWBVQpgN"
}`)
				assert.Equal(t, expected, test.StringToJSONMap(responseString))
			})
		})
	})
}