Skip to content

Commit

Permalink
chore(utils): refactor runner test logic to special test cases (#16)
Browse files Browse the repository at this point in the history
* chore(utils): refactor runner test logic to special test cases

* remove dummy text
  • Loading branch information
nully0x authored Dec 8, 2024
1 parent 051ae40 commit 760811a
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 34 deletions.
2 changes: 1 addition & 1 deletion baseImages/python/Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
FROM python:3.9-slim
FROM python:3.11-slim
2 changes: 1 addition & 1 deletion src/utils/resultReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export async function reportResults(
result: TestResult,
): Promise<void> {
try {
logger.info("Reporting test results:", { result });
logger.info("Reporting test results:", { commitSha });

const channel = getChannel();
const message = JSON.stringify({ result });
Expand Down
51 changes: 26 additions & 25 deletions src/utils/runScriptGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { TestRepoManager } from "./testRepoManager";
import path from "path";
import fs from "fs/promises";

Expand All @@ -9,32 +8,34 @@ export async function generateRunScript(
testContent: string | null,
): Promise<void> {
const runScript = `#!/bin/bash
set -e # Exit on any error
set -e # Exit on any error
if [ -f "requirements.txt" ]; then
# For Python projects
${
testContent
? `pytest ./app/stage${currentStep}${TestRepoManager.getTestExtension(language)} -v`
: "python ./app/main.py"
}
elif [ -f "Cargo.toml" ]; then
# For Rust projects
cargo build ${testContent ? "--quiet" : ""}
${
testContent ? `cargo test --test stage${currentStep}_test` : "cargo run"
}
else
# For TypeScript projects
${
testContent
? `bun test ./app/stage${currentStep}${TestRepoManager.getTestExtension(language)}`
: "bun run start"
}
fi
`;
${generateCommandForLanguage(language, currentStep, testContent)}
`;

const runScriptPath = path.join(repoDir, ".hxckr", "run.sh");
await fs.writeFile(runScriptPath, runScript);
await fs.chmod(runScriptPath, 0o755); // Making it executable
await fs.chmod(runScriptPath, 0o755);
}

function generateCommandForLanguage(
language: string,
currentStep: number,
testContent: string | null,
): string {
switch (language) {
case "python":
return `pytest ./app/stage${currentStep}_test.py -v`;
case "rust":
return `cargo build
cargo test ${
testContent
? `--test stage${currentStep}_test`
: `--test stage${currentStep}`
}`;
case "typescript":
return `bun test ./app/stage${currentStep}.test.ts`;
default:
throw new Error(`Unsupported language: ${language}`);
}
}
36 changes: 35 additions & 1 deletion src/utils/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,50 @@ export async function runTestProcess(request: TestRunRequest): Promise<void> {
if (!challengeId) {
throw new Error("Challenge ID not found in progress data.");
}

// Check if the challenge is completed
if (progress.status === "completed") {
logger.info("Challenge already completed", { commitSha });

// Ensure connection is ready
const isConnected =
await SSEManager.getInstance().ensureConnection(commitSha);
if (!isConnected) {
logger.warn("SSE connection not established in time", { commitSha });
}
SSELogger.log(commitSha, "Challenge completed.");

const testResult: TestResult = {
event_type: EVENT_TYPE,
repoUrl,
commitSha,
success: true,
output: "Challenge completed. No further testing needed.",
};
await reportResults(commitSha, testResult);

await SSEManager.getInstance().closeConnection(commitSha);
return;
}

// Check if the status is "not_started"
if (progress.status === "not_started") {
logger.info("First run detected, confirming repository setup", {
commitSha,
});
// Just verify we can clone the repository
repoDir = await cloneRepository(repoUrl, branch, commitSha);
// Report success without running any tests
const testResult: TestResult = {
event_type: EVENT_TYPE,
repoUrl,
commitSha,
success: true,
output: "Challenge setup completed successfully.",
output: "Challenge setup completed successfully",
};
await reportResults(commitSha, testResult);
SSELogger.log(commitSha, "Challenge setup completed successfully.");
SSEManager.getInstance().closeConnection(commitSha);
return;
}

Expand Down
40 changes: 34 additions & 6 deletions src/utils/sseManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import logger from "./logger";
export class SSEManager {
private static instance: SSEManager;
private connections: Map<string, Response>;
private connectionReadyCallbacks: Map<string, () => void>;

private constructor() {
this.connections = new Map();
this.connectionReadyCallbacks = new Map();
}

public static getInstance(): SSEManager {
Expand All @@ -17,27 +19,52 @@ export class SSEManager {
}

public addConnection(commitSha: string, res: Response): void {
// Check if connection already exists
if (this.connections.has(commitSha)) {
logger.warn(`Connection already exists for commit: ${commitSha}`);
return;
}

// Set headers only once
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");

// Store the connection
this.connections.set(commitSha, res);

// Send initial message
this.sendMessage(commitSha, "Connected to test runner...");
// Resolve the ready promise if any waiting
const readyCallback = this.connectionReadyCallbacks.get(commitSha);
if (readyCallback) {
readyCallback();
this.connectionReadyCallbacks.delete(commitSha);
}

res.on("close", () => {
this.removeConnection(commitSha);
logger.info(`SSE connection closed for commit: ${commitSha}`);
});

// Send initial message
this.sendMessage(commitSha, "Connected to test runner...");
}

public async ensureConnection(
commitSha: string,
timeout = 5000,
): Promise<boolean> {
if (this.connections.has(commitSha)) {
return true;
}

return new Promise((resolve) => {
const timeoutId = setTimeout(() => {
this.connectionReadyCallbacks.delete(commitSha);
resolve(false);
}, timeout);

this.connectionReadyCallbacks.set(commitSha, () => {
clearTimeout(timeoutId);
resolve(true);
});
});
}

public sendMessage(commitSha: string, message: string): void {
Expand All @@ -57,10 +84,11 @@ export class SSEManager {

public removeConnection(commitSha: string): void {
this.connections.delete(commitSha);
this.connectionReadyCallbacks.delete(commitSha);
logger.debug(`Removed connection for ${commitSha}`);
}

public closeConnection(commitSha: string): void {
public async closeConnection(commitSha: string): Promise<void> {
const connection = this.connections.get(commitSha);
if (connection) {
try {
Expand Down

0 comments on commit 760811a

Please sign in to comment.