فهرست منبع

Add test for duplicate payment ID rejection in mint quotes

Adds comprehensive test coverage to verify that duplicate payment IDs are
properly rejected when incrementing mint quote amounts, preventing
double-payment scenarios.

Changes:
- Added reject_duplicate_payment_ids test function to validate payment ID
  uniqueness
- Test verifies that attempting to increment amount with duplicate payment_id
  returns Error::Duplicate
- Test confirms that quote amount is not incremented when duplicate is rejected
- Test validates that different payment IDs can successfully increment the
  amount
- Updated mint_db_test macro to include the new test
- Simplified keyset duplicate insertion test to expect success (consistent
  behavior)

The test ensures database integrity by preventing the same payment from being
counted multiple times toward a mint quote's total paid amount.
Cesar Rodas 1 ماه پیش
والد
کامیت
df1b636e4e

+ 2 - 5
crates/cdk-common/src/database/mint/test/keys.rs

@@ -73,11 +73,8 @@ where
     // Both behaviors are acceptable
     let mut tx = KeysDatabase::begin_transaction(&db).await.unwrap();
     let result = tx.add_keyset_info(keyset_info).await;
-    if result.is_ok() {
-        tx.commit().await.unwrap();
-    } else {
-        tx.rollback().await.unwrap();
-    }
+    assert!(result.is_ok());
+    tx.commit().await.unwrap();
 
     // Verify keyset still exists
     let retrieved = db.get_keyset_info(&keyset_id).await.unwrap();

+ 67 - 0
crates/cdk-common/src/database/mint/test/mint.rs

@@ -1272,3 +1272,70 @@ where
     assert_eq!(retrieved_sig.c, sig.c);
     tx.commit().await.unwrap();
 }
+
+/// Test that duplicate payment IDs are rejected
+pub async fn reject_duplicate_payment_ids<DB>(db: DB)
+where
+    DB: Database<Error> + KeysDatabase<Err = Error>,
+{
+    use crate::database::mint::test::unique_string;
+
+    let mint_quote = MintQuote::new(
+        None,
+        "".to_owned(),
+        cashu::CurrencyUnit::Sat,
+        None,
+        0,
+        PaymentIdentifier::CustomId(unique_string()),
+        None,
+        1000.into(),
+        0.into(),
+        cashu::PaymentMethod::Bolt11,
+        0,
+        vec![],
+        vec![],
+    );
+
+    // Add quote
+    let mut tx = Database::begin_transaction(&db).await.unwrap();
+    tx.add_mint_quote(mint_quote.clone()).await.unwrap();
+    tx.commit().await.unwrap();
+
+    // First payment with payment_id "payment_1"
+    let mut tx = Database::begin_transaction(&db).await.unwrap();
+    let new_total = tx
+        .increment_mint_quote_amount_paid(&mint_quote.id, 300.into(), "payment_1".to_string())
+        .await
+        .unwrap();
+    assert_eq!(new_total, 300.into());
+    tx.commit().await.unwrap();
+
+    // Try to add the same payment_id again - should fail with Duplicate error
+    let mut tx = Database::begin_transaction(&db).await.unwrap();
+    let result = tx
+        .increment_mint_quote_amount_paid(&mint_quote.id, 300.into(), "payment_1".to_string())
+        .await;
+
+    assert!(
+        matches!(result.unwrap_err(), Error::Duplicate),
+        "Duplicate payment_id should be rejected"
+    );
+    tx.rollback().await.unwrap();
+
+    // Verify that the amount_paid is still 300 (not 600)
+    let retrieved = db.get_mint_quote(&mint_quote.id).await.unwrap().unwrap();
+    assert_eq!(retrieved.amount_paid(), 300.into());
+
+    // A different payment_id should succeed
+    let mut tx = Database::begin_transaction(&db).await.unwrap();
+    let new_total = tx
+        .increment_mint_quote_amount_paid(&mint_quote.id, 200.into(), "payment_2".to_string())
+        .await
+        .unwrap();
+    assert_eq!(new_total, 500.into());
+    tx.commit().await.unwrap();
+
+    // Verify final state
+    let retrieved = db.get_mint_quote(&mint_quote.id).await.unwrap().unwrap();
+    assert_eq!(retrieved.amount_paid(), 500.into());
+}

+ 2 - 1
crates/cdk-common/src/database/mint/test/mod.rs

@@ -301,7 +301,8 @@ macro_rules! mint_db_test {
             get_melt_quote_in_transaction,
             get_mint_quote_by_request_in_transaction,
             get_mint_quote_by_request_lookup_id_in_transaction,
-            get_blind_signatures_in_transaction
+            get_blind_signatures_in_transaction,
+            reject_duplicate_payment_ids
         );
     };
     ($make_db_fn:ident, $($name:ident),+ $(,)?) => {