Skip to content

Commit 00e578d

Browse files
tests: enhance global tests (#371)
1 parent 45c77c4 commit 00e578d

File tree

143 files changed

+126388
-126
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+126388
-126
lines changed

Cargo.lock

Lines changed: 60 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ chrono = { version = "0.4.31", features = ["serde"] }
77
regex = "1.10.6"
88
log = "0.4.20"
99
tera = "1.19.1"
10+
static-files = "0.2.1"
1011
lazy_static = "1.4.0"
1112
serde = { version = "1.0.205", features = ["derive"] }
1213
rust_decimal = { version = "1.33.1", features = [

xbuilder/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@ rust_decimal = { workspace = true, features = ["serde-str", "serde-with-str"] }
1616
rust_decimal_macros = { workspace = true }
1717

1818
[dev-dependencies]
19+
libxml = { workspace = true }
20+
21+
serial_test = { workspace = true }
22+
tokio = { workspace = true, features = ["macros"] }
23+
1924
xsender = { path = "../xsender" }
25+
xsigner = { path = "../xsigner" }

xbuilder/src/models/common.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rust_decimal::Decimal;
55
use serde::Serialize;
66

77
/// Quien provee el documento electronico. Quien genera o crea el documento.
8-
#[derive(Clone, Debug, Serialize)]
8+
#[derive(Clone, Debug, Serialize, Default)]
99
pub struct Proveedor {
1010
pub ruc: &'static str,
1111
pub razon_social: &'static str,
@@ -22,7 +22,7 @@ pub struct Firmante {
2222
}
2323

2424
/// Quien es el cliente de la transaccion
25-
#[derive(Clone, Debug, Serialize)]
25+
#[derive(Clone, Debug, Serialize, Default)]
2626
pub struct Cliente {
2727
/// Catalog6
2828
pub tipo_documento_identidad: &'static str,
@@ -141,7 +141,7 @@ pub struct DocumentoRelacionado {
141141
}
142142

143143
/// Detalle de las ventas en Boleta/Factura/Nota Credito/Nota Debito
144-
#[derive(Clone, Debug, Serialize)]
144+
#[derive(Clone, Debug, Serialize, Default)]
145145
pub struct Detalle {
146146
pub descripcion: &'static str,
147147
pub cantidad: Decimal,

xbuilder/src/models/invoice.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::models::common::{
1010
};
1111

1212
/// Boleta o Factura
13-
#[derive(Debug, Serialize)]
13+
#[derive(Debug, Serialize, Default)]
1414
pub struct Invoice {
1515
pub leyendas: HashMap<&'static str, &'static str>,
1616

xbuilder/tests/common/mod.rs

Lines changed: 136 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,47 @@ use std::collections::HashMap;
22
use std::fs;
33

44
use chrono::NaiveDate;
5+
use libxml::tree::Document;
56
use rust_decimal::Decimal;
67
use rust_decimal_macros::dec;
78

89
use xbuilder::prelude::*;
910

11+
use libxml::schemas::SchemaParserContext;
12+
use libxml::schemas::SchemaValidationContext;
13+
use xsender::prelude::Credentials;
14+
use xsender::prelude::DocumentType;
15+
use xsender::prelude::FileSender;
16+
use xsender::prelude::SendFileAggregatedResponse;
17+
use xsender::prelude::UblFile;
18+
use xsender::prelude::Urls;
19+
use xsigner::RsaKeyPair;
20+
use xsigner::XSigner;
21+
22+
const INVOICE_XSD: &str = "tests/resources/xsd/2.1/maindoc/UBL-Invoice-2.1.xsd";
23+
const CREDIT_NOTE_XSD: &str = "tests/resources/xsd/2.1/maindoc/UBL-CreditNote-2.1.xsd";
24+
const DEBIT_NOTE_XSD: &str = "tests/resources/xsd/2.1/maindoc/UBL-DebitNote-2.1.xsd";
25+
const _DESPATCH_ADVICE_XSD: &str = "tests/resources/xsd/2.1/maindoc/UBL-DespatchAdvice-2.1.xsd";
26+
const _VOIDED_DOCUMENTS_XSD: &str = "tests/resources/xsd/2.0/maindoc/UBLPE-VoidedDocuments-1.0.xsd";
27+
const _SUMMARY_DOCUMENTS_XSD: &str =
28+
"tests/resources/xsd/2.0/maindoc/UBLPE-SummaryDocuments-1.0.xsd";
29+
const _PERCEPTION_XSD: &str = "tests/resources/xsd/2.0/maindoc/UBLPE-Perception-1.0.xsd";
30+
const _RETENTION_XSD: &str = "tests/resources/xsd/2.0/maindoc/UBLPE-Retention-1.0.xsd";
31+
32+
lazy_static::lazy_static! {
33+
pub static ref CLIENT: FileSender = FileSender {
34+
urls: Urls {
35+
invoice: "https://e-beta.sunat.gob.pe/ol-ti-itcpfegem-beta/billService".to_string(),
36+
perception_retention:"https://e-beta.sunat.gob.pe/ol-ti-itemision-otroscpe-gem-beta/billService".to_string(),
37+
despatch: "https://api-cpe.sunat.gob.pe/v1/contribuyente/gem".to_string(),
38+
},
39+
credentials: Credentials {
40+
username: "12345678959MODDATOS".to_string(),
41+
password: "MODDATOS".to_string(),
42+
},
43+
};
44+
}
45+
1046
pub fn defaults_base() -> Defaults {
1147
Defaults {
1248
date: NaiveDate::from_ymd_opt(2019, 12, 24).unwrap(),
@@ -179,40 +215,65 @@ pub fn detalle_base() -> Detalle {
179215
}
180216
}
181217

218+
fn sign_xml(xml: &str) -> Document {
219+
let private_key_from_file = fs::read_to_string("tests/resources/certificates/private.key")
220+
.expect("Could not read private.key");
221+
let certificate_from_file = fs::read_to_string("tests/resources/certificates/public.cer")
222+
.expect("Could not read public.cer");
223+
224+
let rsa_key_pair =
225+
RsaKeyPair::from_pkcs1_pem_and_certificate(&private_key_from_file, &certificate_from_file)
226+
.expect("Could not initialize RsaKeyPair");
227+
228+
let signer = XSigner::from_string(xml).expect("Could parse xml");
229+
signer.sign(&rsa_key_pair).expect("Could not sign document");
230+
231+
signer.xml_document
232+
}
233+
182234
#[allow(dead_code)]
183-
pub fn assert_invoice(invoice: &mut Invoice, snapshot_filename: &str) {
235+
pub async fn assert_invoice(invoice: &mut Invoice, snapshot_filename: &str) {
184236
let defaults = defaults_base();
185237
invoice.enrich(&defaults);
186238

187-
let result = invoice.render();
188-
assert!(result.is_ok());
239+
let xml = invoice.render().expect("Could not render invoice");
240+
241+
assert_snapshot(&xml, snapshot_filename);
189242

190-
assert_snapshot(result.ok().unwrap(), snapshot_filename)
243+
let xml_signed = sign_xml(&xml);
244+
assert_xsd(&xml_signed, INVOICE_XSD);
245+
assert_sunat(&xml_signed).await;
191246
}
192247

193248
#[allow(dead_code)]
194-
pub fn assert_credit_note(credit_note: &mut CreditNote, snapshot_filename: &str) {
249+
pub async fn assert_credit_note(credit_note: &mut CreditNote, snapshot_filename: &str) {
195250
let defaults = defaults_base();
196251
credit_note.enrich(&defaults);
197252

198-
let result = credit_note.render();
199-
assert!(result.is_ok());
253+
let xml = credit_note.render().expect("Could not render credit note");
254+
255+
assert_snapshot(&xml, snapshot_filename);
200256

201-
assert_snapshot(result.ok().unwrap(), snapshot_filename)
257+
let xml_signed = sign_xml(&xml);
258+
assert_xsd(&xml_signed, CREDIT_NOTE_XSD);
259+
assert_sunat(&xml_signed).await;
202260
}
203261

204262
#[allow(dead_code)]
205-
pub fn assert_debit_note(debit_note: &mut DebitNote, snapshot_filename: &str) {
263+
pub async fn assert_debit_note(debit_note: &mut DebitNote, snapshot_filename: &str) {
206264
let defaults = defaults_base();
207265
debit_note.enrich(&defaults);
208266

209-
let result = debit_note.render();
210-
assert!(result.is_ok());
267+
let xml = debit_note.render().expect("Could not render debit note");
211268

212-
assert_snapshot(result.ok().unwrap(), snapshot_filename)
269+
assert_snapshot(&xml, snapshot_filename);
270+
271+
let xml_signed = sign_xml(&xml);
272+
assert_xsd(&xml_signed, DEBIT_NOTE_XSD);
273+
assert_sunat(&xml_signed).await;
213274
}
214275

215-
fn assert_snapshot(expected: String, snapshot_filename: &str) {
276+
fn assert_snapshot(expected: &str, snapshot_filename: &str) {
216277
let snapshot_file_content = fs::read_to_string(snapshot_filename);
217278
assert!(snapshot_file_content.is_ok());
218279

@@ -223,3 +284,65 @@ fn assert_snapshot(expected: String, snapshot_filename: &str) {
223284
snapshot_filename
224285
);
225286
}
287+
288+
fn assert_xsd(xml: &Document, schema: &str) {
289+
let mut xsdparser = SchemaParserContext::from_file(schema);
290+
let xsd = SchemaValidationContext::from_parser(&mut xsdparser);
291+
292+
if let Err(errors) = xsd {
293+
for err in &errors {
294+
println!("{}", err.message.as_ref().unwrap());
295+
}
296+
297+
panic!("Failed to parse schema");
298+
}
299+
300+
let mut xsd = xsd.unwrap();
301+
302+
if let Err(errors) = xsd.validate_document(xml) {
303+
for err in &errors {
304+
println!("{}", err.message.as_ref().unwrap());
305+
}
306+
307+
panic!("Invalid XML accoding to XSD schema");
308+
}
309+
}
310+
311+
async fn assert_sunat(xml: &Document) {
312+
let xml_file = UblFile {
313+
file_content: xml.to_string(),
314+
};
315+
316+
let result = CLIENT
317+
.send_file(&xml_file)
318+
.await
319+
.expect("Could not get a valid response");
320+
321+
let documet_type = xml_file
322+
.metadata()
323+
.expect("Could not extract xml metadata")
324+
.document_type;
325+
326+
match documet_type.as_str() {
327+
DocumentType::VOIDED_DOCUMENTS | DocumentType::SUMMARY_DOCUMENTS => {
328+
let result = match result.response {
329+
SendFileAggregatedResponse::Cdr(_, _) => false,
330+
SendFileAggregatedResponse::Ticket(_) => true,
331+
SendFileAggregatedResponse::Error(_) => false,
332+
};
333+
assert!(result)
334+
}
335+
_ => {
336+
let result = match result.response {
337+
SendFileAggregatedResponse::Cdr(_, cdr_metadata) => {
338+
assert_eq!("0", cdr_metadata.response_code);
339+
assert_eq!(Vec::<String>::new(), cdr_metadata.notes);
340+
true
341+
}
342+
SendFileAggregatedResponse::Ticket(_) => false,
343+
SendFileAggregatedResponse::Error(_) => false,
344+
};
345+
assert!(result)
346+
}
347+
};
348+
}

xbuilder/tests/credit_note.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ mod common;
99

1010
const BASE: &str = "tests/resources/e2e/renderer/creditnote/CreditNoteTest";
1111

12-
#[test]
13-
fn credit_note() {
12+
#[serial_test::serial]
13+
#[tokio::test]
14+
async fn credit_note() {
1415
let mut credit_note = CreditNote {
1516
detalles: vec![
1617
Detalle {
@@ -29,5 +30,5 @@ fn credit_note() {
2930
..credit_note_base()
3031
};
3132

32-
assert_credit_note(&mut credit_note, &format!("{BASE}/MinData_RUC.xml"));
33+
assert_credit_note(&mut credit_note, &format!("{BASE}/MinData_RUC.xml")).await;
3334
}

0 commit comments

Comments
 (0)