Files
qbit-printing/dev/java/WorkloadFixture.java
james.maesandClaude Sonnet 5.5 e4639e3cca chore: integrate printing standards and strict Java compiler checks
Preserve current rendering, operator and retained-source behavior while integrating script quality, meaningful headers and strict Error Prone/NullAway contracts. Production and test compilation and the 189-case verification gate pass with zero failures and one intentional workload skip.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
2026-11-01 16:51:18 -06:00

248 lines
12 KiB
Java

/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2026. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// SPDX-License-Identifier: Apache-2.0
package com.kingsrook.qbits.printing;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import com.kingsrook.qqq.middleware.javalin.QApplicationLauncher;
import com.kingsrook.qqq.middleware.javalin.QApplicationLauncherConfig;
import io.javalin.Javalin;
import org.json.JSONArray;
import org.json.JSONObject;
/***************************************************************************
** Fixture only: real checkout host, synthetic SDK producer, no physical printer.
***************************************************************************/
public final class WorkloadFixture
{
/***************************************************************************
** Drive two synthetic tenants through real network workers and verify durable receipts and accounting.
***************************************************************************/
public static void main(String[] args) throws Exception
{
Path dir = Path.of(args[0]).toAbsolutePath();
if(!dir.getFileName().toString().startsWith("run-"))
{
throw new IllegalArgumentException("Owned run directory required");
}
String jdbc = "jdbc:h2:file:" + dir.resolve("synthetic").toString().replace('\\', '/') + ";DB_CLOSE_DELAY=-1";
String password = "synthetic-" + UUID.randomUUID();
List<QApplicationLauncher> launches = new ArrayList<>();
List<PrintingService> services = new ArrayList<>();
List<String> devices = new ArrayList<>();
JSONArray inputs = new JSONArray();
boolean idle = args.length > 1 && args[1].equals("idle");
int total = idle ? 40 : 10000;
long started = System.nanoTime();
int exit = 1;
try
{
for(int tenant = 0; tenant < 2; tenant++)
{
PrintingLocalHost host = new PrintingLocalHost(new PrintingLocalSettings(jdbc, "sa", "", "tenant-" + tenant, 0, "fixture-only-management-token-123456", "operator", password));
AtomicReference<Javalin> app = new AtomicReference<>();
QApplicationLauncher launch = QApplicationLauncher.run(host, new QApplicationLauncherConfig().withRegisterShutdownHook(false).withServerCustomizer(server ->
{
host.configure(server, false);
server.withJavalinConfigurationCustomizer(app::set);
}));
launches.add(launch);
PrintingService service = launch.getQInstance().getQBits().values().stream().map(v -> v.getConfig()).filter(PrintingQBitConfig.class::isInstance).map(PrintingQBitConfig.class::cast).findFirst().orElseThrow().getService();
services.add(service);
for(int lane = 0; lane < 4; lane++)
{
JSONObject enrolled = service.enrollForUser(service.createEnrollment("default", "Synthetic lane").put("deviceName", "Synthetic lane").put("agentVersion", "qualification"), "operator");
String device = enrolled.getString("deviceId");
devices.add(device);
service.inventory(device, new JSONArray().put(new JSONObject().put("printerId", "synthetic").put("name", "No physical printer").put("status", "READY").put("formats", new JSONArray().put("ZPL"))));
service.enablePrinter(device, "synthetic", true);
inputs.put(new JSONObject().put("origin", "http://127.0.0.1:" + app.get().port() + "/").put("username", "operator").put("password", password).put("tenant", "tenant-" + tenant).put("deviceId", device).put("deviceToken", enrolled.getString("deviceToken")));
}
}
// Only synthetic credentials inside the already protected run directory.
Files.writeString(dir.resolve("input.json"), new JSONObject().put("lanes", inputs).put("idle", idle).put("jobsPerLane", total / 8).toString());
await(dir.resolve("ready"), Duration.ofMinutes(2));
byte[] payload = ("^XA^FO20,20^FDSYNTHETIC NOT PRINTED^FS" + " ".repeat(980) + "^XZ").getBytes(StandardCharsets.US_ASCII);
String encoded = Base64.getEncoder().encodeToString(payload);
long producing = System.nanoTime();
if(idle)
{
for(int job = 0; job < total; job++)
{
int lane = job % 8;
PrintingService service = services.get(lane / 4);
JSONObject request = new JSONObject().put("deviceId", devices.get(lane)).put("printerId", "synthetic").put("title", "Synthetic idle workload").put("format", "ZPL").put("contentBase64", encoded).put("idempotencyKey", "idle-" + job);
service.submit(request);
await(dir.resolve("completed-" + (job + 1)), Duration.ofSeconds(30));
Thread.sleep(200);
}
}
else
{
try(var executor = Executors.newFixedThreadPool(8))
{
List<Future<?>> futures = new ArrayList<>();
for(int lane = 0; lane < 8; lane++)
{
final int index = lane;
futures.add(executor.submit(() ->
{
try
{
PrintingService service = services.get(index / 4);
for(int job = 0; job < 1250; job++)
{
JSONObject request = new JSONObject().put("deviceId", devices.get(index)).put("printerId", "synthetic").put("title", "Synthetic workload " + job).put("format", "ZPL").put("contentBase64", encoded).put("idempotencyKey", "lane-" + index + "-" + job);
JSONObject submitted = service.submit(request);
if(job % 25 == 0 && !submitted.getString("jobId").equals(service.submit(request).getString("jobId")))
{
throw new IllegalStateException("Replay duplicated job");
}
}
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}));
}
for(var future : futures)
{
future.get(15, TimeUnit.MINUTES);
}
}
}
double producerSeconds = (System.nanoTime() - producing) / 1e9;
Files.writeString(dir.resolve("producer-done"), "done");
await(dir.resolve("done"), Duration.ofMinutes(15));
JSONObject client = new JSONObject(Files.readString(dir.resolve("result.json")));
if(!client.getBoolean("success"))
{
throw new IllegalStateException("Client reported failure");
}
JSONObject report = new JSONObject().put("success", true).put("jobs", total).put("receipts", total * 3).put("idle", idle).put("producerSeconds", producerSeconds).put("elapsedSeconds", (System.nanoTime() - started) / 1e9).put("realPrinterCalls", 0);
try(Connection connection = DriverManager.getConnection(jdbc, "sa", ""); Statement query = connection.createStatement())
{
require(query, "SELECT COUNT(*) FROM printing_job", total);
require(query, "SELECT COUNT(*) FROM printing_job WHERE status='SPOOLED'", total);
require(query, "SELECT COUNT(*) FROM printing_event", total * 3);
require(query, "SELECT COUNT(*) FROM printing_document_orphan", 0);
for(int tenant = 0; tenant < 2; tenant++)
{
require(query, "SELECT COUNT(*) FROM printing_job WHERE tenant_id='tenant-" + tenant + "'", total / 2);
require(query, "SELECT retained_bytes FROM printing_resource_usage WHERE tenant_id='tenant-" + tenant + "' AND device_id=''", (total / 2L) * payload.length);
}
JSONArray cross = new JSONArray();
for(int tenant = 0; tenant < 2; tenant++)
{
String foreign = services.get(1 - tenant).jobsPage(1, null).getJSONArray("jobs").getJSONObject(0).getString("jobId");
try
{
services.get(tenant).getJob(foreign);
throw new IllegalStateException("Foreign job visible");
}
catch(PrintingException denied)
{
if(denied.getStatus() != 404)
{
throw denied;
}
}
cross.put(true);
}
report.put("tenantIsolation", cross).put("retainedAccountingVerified", true).put("bytesPerDocument", payload.length);
}
Files.writeString(dir.resolve("server-result.json"), report.toString(2));
exit = 0;
}
catch(Throwable failure)
{
Files.writeString(dir.resolve("server-error.json"), new JSONObject().put("error", failure.getClass().getName()).put("cause", failure.getCause() == null ? "" : failure.getCause().getClass().getName()).toString());
}
finally
{
for(int i = launches.size() - 1; i >= 0; i--)
{
launches.get(i).stop();
}
try(Connection connection = DriverManager.getConnection(jdbc, "sa", ""); Statement query = connection.createStatement())
{
query.execute("SHUTDOWN");
}
Files.writeString(dir.resolve("stopped.json"), new JSONObject().put("normalStop", true).put("exitCode", exit).toString());
}
System.exit(exit);
}
/***************************************************************************
** Wait for a private coordination marker with a monotonic deadline.
***************************************************************************/
static void await(Path file, Duration limit) throws Exception
{
long deadline = System.nanoTime() + limit.toNanos();
while(!Files.exists(file))
{
if(System.nanoTime() > deadline)
{
throw new TimeoutException("Fixture deadline");
}
Thread.sleep(100);
}
}
/***************************************************************************
** Verify a synthetic database aggregate without emitting row values.
***************************************************************************/
static void require(Statement query, String sql, long expected) throws Exception
{
try(ResultSet rows = query.executeQuery(sql))
{
if(!rows.next() || rows.getLong(1) != expected)
{
throw new IllegalStateException("Synthetic count/accounting mismatch");
}
}
}
}