api.rs (5122B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2024, 2025, 2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 use std::sync::LazyLock; 18 19 use axum::http::StatusCode; 20 use common::setup; 21 use sqlx::{PgPool, Row, postgres::PgRow}; 22 use taler_api::db::TypeHelper as _; 23 use taler_common::{ 24 api_common::{HashCode, ShortHashCode}, 25 api_revenue::RevenueConfig, 26 api_transfer::PreparedTransferConfig, 27 api_wire::{OutgoingHistory, TransferResponse, TransferState, WireConfig}, 28 db::IncomingType, 29 error_code::ErrorCode, 30 types::{ 31 amount::amount, 32 payto::{PaytoURI, payto}, 33 url, 34 }, 35 }; 36 use taler_test_utils::{ 37 json, 38 routine::{ 39 Status, admin_add_incoming_routine, in_history_routine, registration_routine, 40 revenue_routine, routine_pagination, transfer_routine, 41 }, 42 server::TestServer as _, 43 }; 44 45 mod common; 46 47 static PAYTO: LazyLock<PaytoURI> = LazyLock::new(|| payto("payto://test?receiver-name=Test")); 48 49 #[tokio::test] 50 async fn errors() { 51 let (server, _) = setup().await; 52 server 53 .get("/unknown") 54 .await 55 .assert_error(ErrorCode::GENERIC_ENDPOINT_UNKNOWN); 56 server 57 .post("/taler-revenue/config") 58 .await 59 .assert_error(ErrorCode::GENERIC_METHOD_INVALID); 60 } 61 62 #[tokio::test] 63 async fn config() { 64 let (server, _) = setup().await; 65 server 66 .get("/taler-wire-gateway/config") 67 .await 68 .assert_ok_json::<WireConfig>(); 69 server 70 .get("/taler-prepared-transfer/config") 71 .await 72 .assert_ok_json::<PreparedTransferConfig>(); 73 server 74 .get("/taler-revenue/config") 75 .await 76 .assert_ok_json::<RevenueConfig>(); 77 } 78 79 #[tokio::test] 80 async fn transfer() { 81 let (server, _) = setup().await; 82 transfer_routine(&server, TransferState::success, &PAYTO).await; 83 } 84 85 #[tokio::test] 86 async fn outgoing_history() { 87 let (server, _) = setup().await; 88 routine_pagination::<OutgoingHistory>( 89 &server, 90 "/taler-wire-gateway/history/outgoing", 91 async |i| { 92 server 93 .post("/taler-wire-gateway/transfer") 94 .json(&json!({ 95 "request_uid": HashCode::rand(), 96 "amount": amount(format!("EUR:0.0{i}")), 97 "exchange_base_url": url("http://exchange.taler"), 98 "wtid": ShortHashCode::rand(), 99 "credit_account": PAYTO.clone(), 100 })) 101 .await 102 .assert_ok_json::<TransferResponse>(); 103 }, 104 ) 105 .await; 106 } 107 108 #[tokio::test] 109 async fn admin_add_incoming() { 110 let (server, _) = setup().await; 111 admin_add_incoming_routine(&server, &PAYTO, true).await; 112 } 113 114 #[tokio::test] 115 async fn in_history() { 116 let (server, _) = setup().await; 117 in_history_routine(&server, &PAYTO, true).await; 118 } 119 120 #[tokio::test] 121 async fn revenue() { 122 let (server, _) = setup().await; 123 revenue_routine(&server, &PAYTO, true).await; 124 } 125 126 #[tokio::test] 127 async fn account_check() { 128 let (server, _) = setup().await; 129 server 130 .get("/taler-wire-gateway/account/check") 131 .query("account", "payto://test") 132 .await 133 .assert_status(StatusCode::NOT_IMPLEMENTED); 134 } 135 136 async fn check_in(pool: &PgPool) -> Vec<Status> { 137 sqlx::query( 138 " 139 SELECT pending_recurrent_in.authorization_pub IS NOT NULL, bounced.tx_in_id IS NOT NULL, type, taler_in.account_pub 140 FROM tx_in 141 LEFT JOIN taler_in USING (tx_in_id) 142 LEFT JOIN pending_recurrent_in USING (tx_in_id) 143 LEFT JOIN bounced USING (tx_in_id) 144 ORDER BY tx_in.tx_in_id 145 ", 146 ) 147 .try_map(|r: PgRow| { 148 Ok( 149 if r.try_get_flag(0)? { 150 Status::Pending 151 } else if r.try_get_flag(1)? { 152 Status::Bounced 153 } else { 154 match r.try_get(2)? { 155 None => Status::Simple, 156 Some(IncomingType::reserve) => Status::Reserve(r.try_get(3)?), 157 Some(IncomingType::kyc) => Status::Kyc(r.try_get(3)?), 158 Some(e) => unreachable!("{e:?}") 159 } 160 } 161 ) 162 }) 163 .fetch_all(pool) 164 .await 165 .unwrap() 166 } 167 168 #[tokio::test] 169 async fn registration() { 170 let (server, pool) = setup().await; 171 registration_routine(&server, &PAYTO, || check_in(&pool)).await; 172 }