aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-cli
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-08-16 13:33:21 +0200
committerFlorian Dold <florian@dold.me>2021-08-16 13:33:31 +0200
commitec713f04b83126139087d908cb4b9d012da6c982 (patch)
tree1617947993a907a90f897ccc4e3a7d7a4b021695 /packages/taler-wallet-cli
parent0f851aceeda15b07e1f785c59547e3c3b7f2aefd (diff)
better coverage for merchant spec test
Diffstat (limited to 'packages/taler-wallet-cli')
-rw-r--r--packages/taler-wallet-cli/src/integrationtests/test-merchant-spec-public-orders.ts393
1 files changed, 337 insertions, 56 deletions
diff --git a/packages/taler-wallet-cli/src/integrationtests/test-merchant-spec-public-orders.ts b/packages/taler-wallet-cli/src/integrationtests/test-merchant-spec-public-orders.ts
index 523f760dd..ab7bf1acd 100644
--- a/packages/taler-wallet-cli/src/integrationtests/test-merchant-spec-public-orders.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/test-merchant-spec-public-orders.ts
@@ -28,7 +28,14 @@ import {
NodeHttpLib,
WalletApiOperation,
} from "@gnu-taler/taler-wallet-core";
-import { GlobalTestState, MerchantPrivateApi, WalletCli } from "./harness";
+import {
+ BankService,
+ ExchangeService,
+ GlobalTestState,
+ MerchantPrivateApi,
+ MerchantService,
+ WalletCli,
+} from "./harness";
import {
createSimpleTestkudosEnvironment,
withdrawViaBank,
@@ -36,65 +43,277 @@ import {
const httpLib = new NodeHttpLib();
-/**
- * Checks for the /orders/{id} endpoint of the merchant.
- *
- * The tests here should exercise all code paths in the executable
- * specification of the endpoint.
- */
-export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
- const {
- wallet,
- bank,
- exchange,
- merchant,
- } = await createSimpleTestkudosEnvironment(t);
- const wallet2 = new WalletCli(t);
-
- // Withdraw digital cash into the wallet.
+interface Context {
+ merchant: MerchantService;
+ merchantBaseUrl: string;
+ bank: BankService;
+ exchange: ExchangeService;
+}
+async function testWithClaimToken(
+ t: GlobalTestState,
+ c: Context,
+): Promise<void> {
+ const wallet = new WalletCli(t, "withclaimtoken");
+ const { bank, exchange } = c;
+ const { merchant, merchantBaseUrl } = c;
await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
- await withdrawViaBank(t, {
- wallet: wallet2,
- bank,
- exchange,
- amount: "TESTKUDOS:20",
+ const sessionId = "mysession";
+ const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
+ order: {
+ summary: "Buy me!",
+ amount: "TESTKUDOS:5",
+ fulfillment_url: "https://example.com/article42",
+ public_reorder_url: "https://example.com/article42-share",
+ },
});
- // Base URL for the default instance.
- const merchantBaseUrl = merchant.makeInstanceBaseUrl();
+
+ const claimToken = orderResp.token;
+ const orderId = orderResp.order_id;
+ t.assertTrue(!!claimToken);
+ let talerPayUri: string;
{
- const httpResp = await httpLib.get(new URL("config", merchantBaseUrl).href);
+ const httpResp = await httpLib.get(
+ new URL(`orders/${orderId}`, merchantBaseUrl).href,
+ );
const r = await httpResp.json();
+ t.assertDeepEqual(httpResp.status, 202);
console.log(r);
- t.assertDeepEqual(r.currency, "TESTKUDOS");
}
{
- const httpResp = await httpLib.get(
- new URL("orders/foo", merchantBaseUrl).href,
- );
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ url.searchParams.set("token", claimToken);
+ const httpResp = await httpLib.get(url.href);
const r = await httpResp.json();
+ t.assertDeepEqual(httpResp.status, 402);
console.log(r);
- t.assertDeepEqual(httpResp.status, 404);
- // FIXME: also check Taler error code
+ talerPayUri = r.taler_pay_uri;
+ t.assertTrue(!!talerPayUri);
}
{
- const httpResp = await httpLib.get(
- new URL("orders/foo", merchantBaseUrl).href,
- {
- headers: {
- Accept: "text/html",
- },
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ url.searchParams.set("token", claimToken);
+ const httpResp = await httpLib.get(url.href, {
+ headers: {
+ Accept: "text/html",
},
- );
+ });
const r = await httpResp.text();
+ t.assertDeepEqual(httpResp.status, 402);
console.log(r);
- t.assertDeepEqual(httpResp.status, 404);
- // FIXME: also check Taler error code
}
+ const preparePayResp = await wallet.client.call(
+ WalletApiOperation.PreparePayForUri,
+ {
+ talerPayUri,
+ },
+ );
+
+ t.assertTrue(preparePayResp.status === PreparePayResultType.PaymentPossible);
+ const contractTermsHash = preparePayResp.contractTermsHash;
+ const proposalId = preparePayResp.proposalId;
+
+ // claimed, unpaid, access with wrong h_contract
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ const hcWrong = encodeCrock(getRandomBytes(64));
+ url.searchParams.set("h_contract", hcWrong);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 403);
+ }
+
+ // claimed, unpaid, access with wrong claim token
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ const ctWrong = encodeCrock(getRandomBytes(16));
+ url.searchParams.set("token", ctWrong);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 403);
+ }
+
+ // claimed, unpaid, access with correct claim token
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ url.searchParams.set("token", claimToken);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 402);
+ }
+
+ // claimed, unpaid, access with correct contract terms hash
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ url.searchParams.set("h_contract", contractTermsHash);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 402);
+ }
+
+ // claimed, unpaid, access without credentials
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 202);
+ }
+
+ const confirmPayRes = await wallet.client.call(
+ WalletApiOperation.ConfirmPay,
+ {
+ proposalId: proposalId,
+ },
+ );
+
+ t.assertTrue(confirmPayRes.type === ConfirmPayResultType.Done);
+
+ // paid, access without credentials
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 202);
+ }
+
+ // paid, access with wrong h_contract
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ const hcWrong = encodeCrock(getRandomBytes(64));
+ url.searchParams.set("h_contract", hcWrong);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 403);
+ }
+
+ // paid, access with wrong claim token
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ const ctWrong = encodeCrock(getRandomBytes(16));
+ url.searchParams.set("token", ctWrong);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 403);
+ }
+
+ // paid, access with correct h_contract
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ url.searchParams.set("h_contract", contractTermsHash);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 200);
+ }
+
+ // paid, access with correct claim token, JSON
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ url.searchParams.set("token", claimToken);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 200);
+ const respFulfillmentUrl = r.fulfillment_url;
+ t.assertDeepEqual(respFulfillmentUrl, "https://example.com/article42");
+ }
+
+ // paid, access with correct claim token, HTML
+ {
+ const url = new URL(`orders/${orderId}`, merchantBaseUrl);
+ url.searchParams.set("token", claimToken);
+ const httpResp = await httpLib.get(url.href, {
+ headers: { Accept: "text/html" },
+ });
+ t.assertDeepEqual(httpResp.status, 200);
+ }
+
+ const confirmPayRes2 = await wallet.client.call(
+ WalletApiOperation.ConfirmPay,
+ {
+ proposalId: proposalId,
+ sessionId: sessionId,
+ },
+ );
+
+ t.assertTrue(confirmPayRes2.type === ConfirmPayResultType.Done);
+
+ // Create another order with identical fulfillment URL to test the "already paid" flow
+ const alreadyPaidOrderResp = await MerchantPrivateApi.createOrder(
+ merchant,
+ "default",
+ {
+ order: {
+ summary: "Buy me!",
+ amount: "TESTKUDOS:5",
+ fulfillment_url: "https://example.com/article42",
+ public_reorder_url: "https://example.com/article42-share",
+ },
+ },
+ );
+
+ const apOrderId = alreadyPaidOrderResp.order_id;
+ const apToken = alreadyPaidOrderResp.token;
+ t.assertTrue(!!apToken);
+
+ {
+ const url = new URL(`orders/${apOrderId}`, merchantBaseUrl);
+ url.searchParams.set("token", apToken);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 402);
+ }
+
+ // Check for already paid session ID, JSON
+ {
+ const url = new URL(`orders/${apOrderId}`, merchantBaseUrl);
+ url.searchParams.set("token", apToken);
+ url.searchParams.set("session_id", sessionId);
+ const httpResp = await httpLib.get(url.href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 402);
+ const alreadyPaidOrderId = r.already_paid_order_id;
+ t.assertDeepEqual(alreadyPaidOrderId, orderId);
+ }
+
+ // Check for already paid session ID, HTML
+ {
+ const url = new URL(`orders/${apOrderId}`, merchantBaseUrl);
+ url.searchParams.set("token", apToken);
+ url.searchParams.set("session_id", sessionId);
+ const httpResp = await httpLib.get(url.href, {
+ headers: { Accept: "text/html" },
+ });
+ t.assertDeepEqual(httpResp.status, 302);
+ const location = httpResp.headers.get("Location");
+ console.log("location header:", location);
+ t.assertDeepEqual(location, "https://example.com/article42");
+ }
+}
+
+async function testWithoutClaimToken(
+ t: GlobalTestState,
+ c: Context,
+): Promise<void> {
+ const wallet = new WalletCli(t, "withoutct");
+ const sessionId = "mysession2";
+ const { bank, exchange } = c;
+ const { merchant, merchantBaseUrl } = c;
+ await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:20" });
const orderResp = await MerchantPrivateApi.createOrder(merchant, "default", {
order: {
summary: "Buy me!",
@@ -102,11 +321,10 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
fulfillment_url: "https://example.com/article42",
public_reorder_url: "https://example.com/article42-share",
},
+ create_token: false,
});
- const claimToken = orderResp.token;
const orderId = orderResp.order_id;
- t.assertTrue(!!claimToken);
let talerPayUri: string;
{
@@ -114,13 +332,12 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
new URL(`orders/${orderId}`, merchantBaseUrl).href,
);
const r = await httpResp.json();
- t.assertDeepEqual(httpResp.status, 202);
+ t.assertDeepEqual(httpResp.status, 402);
console.log(r);
}
{
const url = new URL(`orders/${orderId}`, merchantBaseUrl);
- url.searchParams.set("token", claimToken);
const httpResp = await httpLib.get(url.href);
const r = await httpResp.json();
t.assertDeepEqual(httpResp.status, 402);
@@ -131,7 +348,6 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
{
const url = new URL(`orders/${orderId}`, merchantBaseUrl);
- url.searchParams.set("token", claimToken);
const httpResp = await httpLib.get(url.href, {
headers: {
Accept: "text/html",
@@ -149,6 +365,8 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
},
);
+ console.log(preparePayResp);
+
t.assertTrue(preparePayResp.status === PreparePayResultType.PaymentPossible);
const contractTermsHash = preparePayResp.contractTermsHash;
const proposalId = preparePayResp.proposalId;
@@ -175,10 +393,9 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
t.assertDeepEqual(httpResp.status, 403);
}
- // claimed, unpaid, access with correct claim token
+ // claimed, unpaid, no claim token
{
const url = new URL(`orders/${orderId}`, merchantBaseUrl);
- url.searchParams.set("token", claimToken);
const httpResp = await httpLib.get(url.href);
const r = await httpResp.json();
console.log(r);
@@ -201,7 +418,10 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
const httpResp = await httpLib.get(url.href);
const r = await httpResp.json();
console.log(r);
- t.assertDeepEqual(httpResp.status, 202);
+ // No credentials, but the order doesn't require a claim token.
+ // This effectively means that the order ID is already considered
+ // enough authentication, at least to check for the basic order status
+ t.assertDeepEqual(httpResp.status, 402);
}
const confirmPayRes = await wallet.client.call(
@@ -219,7 +439,7 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
const httpResp = await httpLib.get(url.href);
const r = await httpResp.json();
console.log(r);
- t.assertDeepEqual(httpResp.status, 202);
+ t.assertDeepEqual(httpResp.status, 200);
}
// paid, access with wrong h_contract
@@ -254,10 +474,9 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
t.assertDeepEqual(httpResp.status, 200);
}
- // paid, access with correct claim token, JSON
+ // paid, JSON
{
const url = new URL(`orders/${orderId}`, merchantBaseUrl);
- url.searchParams.set("token", claimToken);
const httpResp = await httpLib.get(url.href);
const r = await httpResp.json();
console.log(r);
@@ -266,10 +485,9 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
t.assertDeepEqual(respFulfillmentUrl, "https://example.com/article42");
}
- // paid, access with correct claim token, HTML
+ // paid, HTML
{
const url = new URL(`orders/${orderId}`, merchantBaseUrl);
- url.searchParams.set("token", claimToken);
const httpResp = await httpLib.get(url.href, {
headers: { Accept: "text/html" },
});
@@ -280,7 +498,7 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
WalletApiOperation.ConfirmPay,
{
proposalId: proposalId,
- sessionId: "mysession",
+ sessionId: sessionId,
},
);
@@ -317,7 +535,7 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
{
const url = new URL(`orders/${apOrderId}`, merchantBaseUrl);
url.searchParams.set("token", apToken);
- url.searchParams.set("session_id", "mysession");
+ url.searchParams.set("session_id", sessionId);
const httpResp = await httpLib.get(url.href);
const r = await httpResp.json();
console.log(r);
@@ -330,7 +548,7 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
{
const url = new URL(`orders/${apOrderId}`, merchantBaseUrl);
url.searchParams.set("token", apToken);
- url.searchParams.set("session_id", "mysession");
+ url.searchParams.set("session_id", sessionId);
const httpResp = await httpLib.get(url.href, {
headers: { Accept: "text/html" },
});
@@ -341,4 +559,67 @@ export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
}
}
+/**
+ * Checks for the /orders/{id} endpoint of the merchant.
+ *
+ * The tests here should exercise all code paths in the executable
+ * specification of the endpoint.
+ */
+export async function runMerchantSpecPublicOrdersTest(t: GlobalTestState) {
+ const {
+ bank,
+ exchange,
+ merchant,
+ } = await createSimpleTestkudosEnvironment(t);
+
+ // Base URL for the default instance.
+ const merchantBaseUrl = merchant.makeInstanceBaseUrl();
+
+ {
+ const httpResp = await httpLib.get(new URL("config", merchantBaseUrl).href);
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(r.currency, "TESTKUDOS");
+ }
+
+ {
+ const httpResp = await httpLib.get(
+ new URL("orders/foo", merchantBaseUrl).href,
+ );
+ const r = await httpResp.json();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 404);
+ // FIXME: also check Taler error code
+ }
+
+ {
+ const httpResp = await httpLib.get(
+ new URL("orders/foo", merchantBaseUrl).href,
+ {
+ headers: {
+ Accept: "text/html",
+ },
+ },
+ );
+ const r = await httpResp.text();
+ console.log(r);
+ t.assertDeepEqual(httpResp.status, 404);
+ // FIXME: also check Taler error code
+ }
+
+ await testWithClaimToken(t, {
+ merchant,
+ merchantBaseUrl,
+ exchange,
+ bank,
+ });
+
+ await testWithoutClaimToken(t, {
+ merchant,
+ merchantBaseUrl,
+ exchange,
+ bank,
+ });
+}
+
runMerchantSpecPublicOrdersTest.suites = ["merchant"];