"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); var sqlite3 = require("sqlite3"); var faker_1 = require("@faker-js/faker"); var lodash_1 = require("lodash"); var luxon_1 = require("luxon"); var sqlite_1 = require("sqlite"); var uuid_1 = require("uuid"); var dbPath = "./db/sqlite.db"; // Configurations for test data generation var startDate = luxon_1.DateTime.fromISO("2024-11-01"); var endDate = luxon_1.DateTime.fromISO("2024-11-30"); var holidays = []; // Example holidays var existingJobs = []; // Calendar week usage configs var weekUsage = { 44: { minJobs: 4, maxJobs: 6 }, 45: { minJobs: 10, maxJobs: 15 }, 46: { minJobs: 10, maxJobs: 15 }, 47: { minJobs: 3, maxJobs: 5 }, 48: { minJobs: 10, maxJobs: 15 }, }; var printerUsageBias = { fastPrints: ["Printer A", "Printer B"], largePrints: ["Printer C", "Printer D", "Printer E"], }; var initDB = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { console.log("Initializing database connection..."); return [2 /*return*/, (0, sqlite_1.open)({ filename: dbPath, driver: sqlite3.Database, })]; }); }); }; var createUser = function (isPowerUser) { if (isPowerUser === void 0) { isPowerUser = false; } var name = [faker_1.faker.person.firstName(), faker_1.faker.person.lastName()]; var user = { id: (0, uuid_1.v4)(), github_id: faker_1.faker.number.int(), username: "".concat(name[0].slice(0, 2)).concat(name[1].slice(0, 6)).toUpperCase(), displayName: "".concat(name[0], " ").concat(name[1]).toUpperCase(), email: "".concat(name[0], ".").concat(name[1], "@mercedes-benz.com"), role: (0, lodash_1.sample)(["user", "admin"]), isPowerUser: isPowerUser, }; console.log("Created user:", user); return user; }; var createPrinter = function () { var printer = { id: (0, uuid_1.v4)(), name: "Printer ".concat(faker_1.faker.number.int({ max: 9 })), description: faker_1.faker.lorem.sentence(), status: (0, lodash_1.random)(0, 2), }; console.log("Created printer:", printer); return printer; }; var isPrinterAvailable = function (printer, startAt, duration) { var endAt = startAt + duration * 60 * 1000; // Convert minutes to milliseconds return !existingJobs.some(function (job) { var jobStart = job.startAt; var jobEnd = job.startAt + job.durationInMinutes * 60 * 1000; return (printer.id === job.printerId && ((startAt >= jobStart && startAt < jobEnd) || (endAt > jobStart && endAt <= jobEnd) || (startAt <= jobStart && endAt >= jobEnd))); }); }; var weightedSampleUser = function (users) { var weights = users.map(function (user) { return (user.isPowerUser ? 3 : 1); }); var weightedUsers = users.flatMap(function (user, index) { return Array(weights[index]).fill(user); }); return (0, lodash_1.sample)(weightedUsers); }; var normalRandom = function (mean, stdDev) { var u = 0; var v = 0; while (u === 0) u = Math.random(); while (v === 0) v = Math.random(); return mean + stdDev * Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v); }; var createPrintJob = function (users, printers, startAt) { var user = weightedSampleUser(users); var printer; // Probabilistic determination for large prints var isLargePrint = (0, lodash_1.random)(0, 100) < 30; // 30% chance for a large print if (isLargePrint) { printer = (0, lodash_1.sample)(printers.filter(function (p) { return printerUsageBias.largePrints.includes(p.name); })); } else { printer = (0, lodash_1.sample)(printers.filter(function (p) { return printerUsageBias.fastPrints.includes(p.name); })); } if (!printer) { printer = (0, lodash_1.sample)(printers); } // Variable duration for print jobs with realistic limits var duration = Math.round(normalRandom(isLargePrint ? 240 : 75, 30)); var minDuration = 15; var maxDuration = isLargePrint ? 5760 : 3540; // Maximum duration of 96 hours or 59 minutes in minutes if (isLargePrint) { duration = Math.min(duration, maxDuration); } duration = Math.max(duration, minDuration); duration = Math.min(duration, maxDuration); // Ensure printer availability if (!isPrinterAvailable(printer, startAt, duration)) { console.log("Printer not available, skipping job creation."); return null; } // Dynamic error probability based on printer status, duration, and other factors var aborted = false; var abortReason = null; var baseErrorRate = Math.max(0, Math.min(5, 100)); // Ensure error rate is between 0% and 100% var userErrorModifier = user.isPowerUser ? -2 : 2; // Power users make fewer errors var timeErrorModifier = startAt >= luxon_1.DateTime.fromObject({ hour: 14 }).toMillis() && startAt <= luxon_1.DateTime.fromObject({ hour: 17 }).toMillis() ? 1 : 0; // More errors in the afternoon var errorRate = baseErrorRate + userErrorModifier + timeErrorModifier; if ((0, lodash_1.random)(0, 100) < Math.max(0, Math.min(errorRate, 100))) { aborted = true; abortReason = generateDynamicAbortReason(); } var printJob = { id: (0, uuid_1.v4)(), printerId: printer.id, userId: user.id, startAt: startAt, durationInMinutes: duration, comments: faker_1.faker.lorem.sentence(), aborted: aborted, abortReason: abortReason, }; console.log("Created print job:", printJob); return printJob; }; var generateDynamicAbortReason = function () { var reasons = [ "Filament gerissen", "Drucker überhitzt", "Schichtversatz festgestellt", "Düse verstopft", "Kalibrierung fehlgeschlagen", "E".concat((0, lodash_1.random)(500, 599)), ]; var reason = (0, lodash_1.sample)(reasons); // Add typos to simulate human variability if ((0, lodash_1.random)(0, 1)) { reason = reason.replace("e", (0, lodash_1.random)(0, 1) ? "é" : "e"); } return reason; }; var generatePrintJobsForWeek = function (users, printers, weekNumber, // biome-ignore lint/suspicious/noExplicitAny: db, dryRun) { return __awaiter(void 0, void 0, void 0, function () { var weekConfig, totalJobs, startOfWeek, jobsRemaining, day, dayDate, _i, printers_1, printer, jobsForDay, i, timeSlots, selectedSlot, startAt, printJob; return __generator(this, function (_a) { switch (_a.label) { case 0: console.log("Generating print jobs for week ".concat(weekNumber, "...")); weekConfig = weekUsage[weekNumber]; totalJobs = (0, lodash_1.random)(weekConfig.minJobs, weekConfig.maxJobs); startOfWeek = startDate.plus({ weeks: weekNumber - 44 }); jobsRemaining = totalJobs; day = 0; _a.label = 1; case 1: if (!(day < 7)) return [3 /*break*/, 7]; dayDate = startOfWeek.plus({ days: day }); if (dayDate > endDate || jobsRemaining <= 0) return [3 /*break*/, 7]; if (holidays.includes(dayDate.toISODate()) || dayDate.weekday === 6 || dayDate.weekday === 7) { console.log("Skipping holiday or weekend: ".concat(dayDate.toISODate())); return [3 /*break*/, 6]; } // Update printer status to simulate maintenance or breakdowns for (_i = 0, printers_1 = printers; _i < printers_1.length; _i++) { printer = printers_1[_i]; if ((0, lodash_1.random)(0, 100) < 5) { // 5% chance per day that a printer goes out of service printer.status = 2; // Status 2 means "out of service" console.log("Printer ".concat(printer.name, " is out of service on ").concat(dayDate.toISODate())); } else if (printer.status === 2) { printer.status = 0; // Printer becomes available again } } jobsForDay = Math.min(jobsRemaining, (0, lodash_1.random)(1, 3)); jobsRemaining -= jobsForDay; console.log("Generating ".concat(jobsForDay, " print jobs for day ").concat(dayDate.toISODate(), "...")); i = 0; _a.label = 2; case 2: if (!(i < jobsForDay)) return [3 /*break*/, 6]; timeSlots = [ { hour: 7, minute: 0 }, { hour: 11, minute: 0 }, { hour: 13, minute: 0 }, { hour: 15, minute: 0 }, ]; selectedSlot = (0, lodash_1.sample)(timeSlots); startAt = luxon_1.DateTime.fromISO("".concat(dayDate.toISODate(), "T").concat(String(selectedSlot.hour).padStart(2, "0"), ":").concat(String(selectedSlot.minute + (0, lodash_1.random)(0, 30)).padStart(2, "0"), ":00")); printJob = createPrintJob(users, printers, startAt.toMillis()); if (!printJob) return [3 /*break*/, 5]; if (!!dryRun) return [3 /*break*/, 4]; return [4 /*yield*/, db.run("INSERT INTO printJob (id, printerId, userId, startAt, durationInMinutes, comments, aborted, abortReason)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)", [ printJob.id, printJob.printerId, printJob.userId, printJob.startAt, printJob.durationInMinutes, printJob.comments, printJob.aborted ? 1 : 0, printJob.abortReason, ])]; case 3: _a.sent(); _a.label = 4; case 4: existingJobs.push(printJob); console.log("Inserted print job into database:", printJob.id); console.log(JSON.stringify({ event: "PrintJobCreated", jobId: printJob.id, printerId: printJob.printerId, userId: printJob.userId, startAt: new Date(printJob.startAt).toISOString(), duration: printJob.durationInMinutes, aborted: printJob.aborted, })); _a.label = 5; case 5: i++; return [3 /*break*/, 2]; case 6: day++; return [3 /*break*/, 1]; case 7: return [2 /*return*/]; } }); }); }; var generateTestData = function () { var args_1 = []; for (var _i = 0; _i < arguments.length; _i++) { args_1[_i] = arguments[_i]; } return __awaiter(void 0, __spreadArray([], args_1, true), void 0, function (dryRun) { var db, users, printers, _a, users_1, user, _b, printers_2, printer, validateData, _c, _d, weekNumber; if (dryRun === void 0) { dryRun = false; } return __generator(this, function (_e) { switch (_e.label) { case 0: console.log("Starting test data generation..."); return [4 /*yield*/, initDB()]; case 1: db = _e.sent(); users = __spreadArray(__spreadArray([], Array.from({ length: 7 }, function () { return createUser(false); }), true), Array.from({ length: 3 }, function () { return createUser(true); }), true); printers = Array.from({ length: 5 }, createPrinter); if (!!dryRun) return [3 /*break*/, 9]; _a = 0, users_1 = users; _e.label = 2; case 2: if (!(_a < users_1.length)) return [3 /*break*/, 5]; user = users_1[_a]; return [4 /*yield*/, db.run("INSERT INTO user (id, github_id, name, displayName, email, role)\n VALUES (?, ?, ?, ?, ?, ?)", [user.id, user.github_id, user.username, user.displayName, user.email, user.role])]; case 3: _e.sent(); console.log("Inserted user into database:", user.id); _e.label = 4; case 4: _a++; return [3 /*break*/, 2]; case 5: _b = 0, printers_2 = printers; _e.label = 6; case 6: if (!(_b < printers_2.length)) return [3 /*break*/, 9]; printer = printers_2[_b]; return [4 /*yield*/, db.run("INSERT INTO printer (id, name, description, status)\n VALUES (?, ?, ?, ?)", [printer.id, printer.name, printer.description, printer.status])]; case 7: _e.sent(); console.log("Inserted printer into database:", printer.id); _e.label = 8; case 8: _b++; return [3 /*break*/, 6]; case 9: validateData = function (printJobs, users, printers) { var _loop_1 = function (job) { var userExists = users.some(function (user) { return user.id === job.userId; }); var printerExists = printers.some(function (printer) { return printer.id === job.printerId; }); if (!userExists || !printerExists) { console.error("Invalid job detected: ".concat(job.id)); } }; for (var _i = 0, printJobs_1 = printJobs; _i < printJobs_1.length; _i++) { var job = printJobs_1[_i]; _loop_1(job); } }; _c = 0, _d = Object.keys(weekUsage); _e.label = 10; case 10: if (!(_c < _d.length)) return [3 /*break*/, 13]; weekNumber = _d[_c]; return [4 /*yield*/, generatePrintJobsForWeek(users, printers, Number.parseInt("".concat(weekNumber)), db, dryRun)]; case 11: _e.sent(); console.log("======> \uD83D\uDCC5 Week ".concat(weekNumber)); validateData(existingJobs, users, printers); _e.label = 12; case 12: _c++; return [3 /*break*/, 10]; case 13: if (!!dryRun) return [3 /*break*/, 15]; return [4 /*yield*/, db.close()]; case 14: _e.sent(); console.log("Database connection closed. Test data generation complete."); return [3 /*break*/, 16]; case 15: console.log("Dry run complete. No data was written to the database."); _e.label = 16; case 16: return [2 /*return*/]; } }); }); }; generateTestData(process.argv.includes("--dry-run")) .then(function () { console.log("Test data generation script finished."); }) .catch(function (err) { console.error("Error generating test data:", err); });