test(bench): add automated benchmark scripts and document baseline metrics
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
package scripts.bench;
|
||||
|
||||
import br.com.cybercore.signer.core.domain.ManagedCertificate;
|
||||
import br.com.cybercore.signer.core.pdf.PdfSealPosition;
|
||||
import br.com.cybercore.signer.core.pdf.PdfSignatureOptions;
|
||||
import br.com.cybercore.signer.core.pdf.PdfSigningService;
|
||||
import br.com.cybercore.signer.core.provider.CertificateManager;
|
||||
import br.com.cybercore.signer.core.provider.Pkcs12CertificateProvider;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDPage;
|
||||
import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
||||
import org.apache.pdfbox.pdmodel.font.PDType1Font;
|
||||
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.BasicConstraints;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.asn1.x509.KeyUsage;
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.Files;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utilitário de benchmark para medição de latência de certificados e assinatura PAdES (100KB, 5MB e 50MB).
|
||||
*/
|
||||
public class BenchmarkRunner {
|
||||
|
||||
private static final String TARGET_DIR = "target/bench-data";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("===============================================================");
|
||||
System.out.println(" CyberCore Signer — Benchmark de Desempenho (Certificados & PAdES)");
|
||||
System.out.println("===============================================================");
|
||||
|
||||
File dir = new File(TARGET_DIR);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
// 1. Prepara Certificado A1 de Teste
|
||||
System.out.print("[1/3] Inicializando provedor e certificado A1 de teste... ");
|
||||
long tCertGenStart = System.currentTimeMillis();
|
||||
CertificateManager certManager = new CertificateManager();
|
||||
Pkcs12CertificateProvider a1Provider = new Pkcs12CertificateProvider();
|
||||
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
|
||||
kpg.initialize(2048);
|
||||
KeyPair keyPair = kpg.generateKeyPair();
|
||||
|
||||
X500Name name = new X500Name("CN=BENCHMARK TESTE:12345678900, O=ICP-Brasil Teste, C=BR");
|
||||
Date notBefore = Date.from(Instant.now().minus(1, ChronoUnit.DAYS));
|
||||
Date notAfter = Date.from(Instant.now().plus(30, ChronoUnit.DAYS));
|
||||
X509v3CertificateBuilder builder = new X509v3CertificateBuilder(
|
||||
name, BigInteger.ONE, notBefore, notAfter, name,
|
||||
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())
|
||||
);
|
||||
builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
|
||||
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.nonRepudiation));
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate());
|
||||
X509CertificateHolder holder = builder.build(signer);
|
||||
X509Certificate cert = new JcaX509CertificateConverter().getCertificate(holder);
|
||||
|
||||
KeyStore ks = KeyStore.getInstance("PKCS12");
|
||||
ks.load(null, null);
|
||||
ks.setKeyEntry("bench-alias", keyPair.getPrivate(), "1234".toCharArray(), new Certificate[]{cert});
|
||||
ByteArrayOutputStream baosKs = new ByteArrayOutputStream();
|
||||
ks.store(baosKs, "1234".toCharArray());
|
||||
a1Provider.loadFromBytes(baosKs.toByteArray(), "1234".toCharArray());
|
||||
certManager.registerProvider(a1Provider);
|
||||
System.out.println("OK (" + (System.currentTimeMillis() - tCertGenStart) + " ms)");
|
||||
|
||||
// 2. Mede Tempo de Enumeração de Certificados
|
||||
System.out.print("[2/3] Medindo tempo de enumeração de certificados (discoverCertificates)... ");
|
||||
long tDiscStart = System.nanoTime();
|
||||
List<ManagedCertificate> certs = certManager.discoverCertificates();
|
||||
long tDiscEnd = System.nanoTime();
|
||||
double discMs = (tDiscEnd - tDiscStart) / 1_000_000.0;
|
||||
System.out.printf("OK (%.2f ms | %d certificado(s) listado(s))\n", discMs, certs.size());
|
||||
|
||||
String certId = certs.get(0).id();
|
||||
|
||||
// 3. Prepara arquivos PDF de 100 KB, 5 MB e 50 MB
|
||||
System.out.println("[3/3] Preparando e assinando documentos PDF com PAdES e selo visual...");
|
||||
File pdf100Kb = preparePdf(new File(dir, "doc_100kb.pdf"), 100 * 1024);
|
||||
File pdf5Mb = preparePdf(new File(dir, "doc_5mb.pdf"), 5 * 1024 * 1024);
|
||||
File pdf50Mb = preparePdf(new File(dir, "doc_50mb.pdf"), 50 * 1024 * 1024);
|
||||
|
||||
PdfSigningService pdfService = new PdfSigningService(certManager);
|
||||
PdfSignatureOptions options = PdfSignatureOptions.builder(certId)
|
||||
.position(PdfSealPosition.BOTTOM_RIGHT)
|
||||
.visibleSeal(true)
|
||||
.reason("Homologacao de Performance")
|
||||
.location("Brasilia, DF")
|
||||
.pinOrPassword("1234".toCharArray())
|
||||
.build();
|
||||
|
||||
// Warmup JIT (PDF pequeno)
|
||||
pdfService.signPdf(Files.readAllBytes(pdf100Kb.toPath()), options);
|
||||
|
||||
// Medição 100 KB
|
||||
long t100Start = System.nanoTime();
|
||||
byte[] signed100 = pdfService.signPdf(Files.readAllBytes(pdf100Kb.toPath()), options);
|
||||
long t100End = System.nanoTime();
|
||||
double ms100 = (t100End - t100Start) / 1_000_000.0;
|
||||
|
||||
// Medição 5 MB
|
||||
long t5mStart = System.nanoTime();
|
||||
byte[] signed5m = pdfService.signPdf(Files.readAllBytes(pdf5Mb.toPath()), options);
|
||||
long t5mEnd = System.nanoTime();
|
||||
double ms5m = (t5mEnd - t5mStart) / 1_000_000.0;
|
||||
|
||||
// Medição 50 MB
|
||||
long t50mStart = System.nanoTime();
|
||||
byte[] signed50m = pdfService.signPdf(Files.readAllBytes(pdf50Mb.toPath()), options);
|
||||
long t50mEnd = System.nanoTime();
|
||||
double ms50m = (t50mEnd - t50mStart) / 1_000_000.0;
|
||||
|
||||
System.out.println();
|
||||
System.out.println("==================== RESULTADOS DE LATÊNCIA PAdES ====================");
|
||||
System.out.printf(" - Enumeração de Certificados: %.2f ms\n", discMs);
|
||||
System.out.printf(" - Assinatura PAdES 100 KB: %.2f ms (saída: %d KB)\n", ms100, signed100.length / 1024);
|
||||
System.out.printf(" - Assinatura PAdES 5 MB: %.2f ms (saída: %.2f MB)\n", ms5m, signed5m.length / (1024.0 * 1024.0));
|
||||
System.out.printf(" - Assinatura PAdES 50 MB: %.2f ms (saída: %.2f MB)\n", ms50m, signed50m.length / (1024.0 * 1024.0));
|
||||
System.out.println("=======================================================================");
|
||||
}
|
||||
|
||||
private static File preparePdf(File file, int targetSizeBytes) throws Exception {
|
||||
if (file.exists() && file.length() >= targetSizeBytes * 0.95) {
|
||||
return file;
|
||||
}
|
||||
System.out.printf(" -> Gerando %s (~%d KB)... ", file.getName(), targetSizeBytes / 1024);
|
||||
try (PDDocument doc = new PDDocument()) {
|
||||
PDPage page = new PDPage();
|
||||
doc.addPage(page);
|
||||
|
||||
try (PDPageContentStream cs = new PDPageContentStream(doc, page)) {
|
||||
cs.beginText();
|
||||
cs.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), 14);
|
||||
cs.newLineAtOffset(50, 750);
|
||||
cs.showText("CyberCore Signer — Documento de Benchmark de Performance");
|
||||
cs.endText();
|
||||
}
|
||||
|
||||
// Para arquivos de 5MB e 50MB, adiciona páginas e streams para atingir a meta de tamanho
|
||||
int approxPageSize = 2500;
|
||||
int pagesNeeded = Math.max(1, targetSizeBytes / approxPageSize);
|
||||
for (int p = 1; p < pagesNeeded && p < 1200; p++) {
|
||||
PDPage extraPage = new PDPage();
|
||||
doc.addPage(extraPage);
|
||||
try (PDPageContentStream cs = new PDPageContentStream(doc, extraPage)) {
|
||||
cs.beginText();
|
||||
cs.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 10);
|
||||
cs.newLineAtOffset(50, 700);
|
||||
cs.showText("Pagina de teste de volume " + p + " com metadados para teste PAdES.");
|
||||
cs.endText();
|
||||
}
|
||||
}
|
||||
|
||||
// Grava documento
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
doc.save(fos);
|
||||
}
|
||||
}
|
||||
|
||||
// Se ainda não atingiu o tamanho exato desejado (especialmente para 50MB), preenche comentários PDF (% padding)
|
||||
long currentLen = file.length();
|
||||
if (currentLen < targetSizeBytes) {
|
||||
try (FileOutputStream fos = new FileOutputStream(file, true)) {
|
||||
byte[] chunk = new byte[64 * 1024];
|
||||
java.util.Arrays.fill(chunk, (byte) 'A');
|
||||
chunk[0] = '%';
|
||||
chunk[chunk.length - 1] = '\n';
|
||||
while (file.length() < targetSizeBytes) {
|
||||
long remaining = targetSizeBytes - file.length();
|
||||
int toWrite = (int) Math.min(chunk.length, remaining);
|
||||
fos.write(chunk, 0, toWrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.printf("OK (%d KB)\n", file.length() / 1024);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user