diff --git a/.githooks/post-receive b/.githooks/post-receive index 2426e63..9f23d3b 100644 --- a/.githooks/post-receive +++ b/.githooks/post-receive @@ -19,8 +19,11 @@ copy_env_file() { local branch="$1" + local env_file + env_file="$(get_deploy_env_file "$branch")" + source "$env_file" # Copy the .env file for the test environment - cp "$(get_deploy_env_file "$branch")" "$tmpdir/.env" || { + cp "$env_file" "$tmpdir/.env" || { echo "Error: Failed to copy .env file for test environment." return 1 } @@ -225,11 +228,7 @@ copy_env_file "$branch" || return 1 initialize_submodules "$tmpdir" || return 1 - - export TEST_PORT=4123 - export TEST_SCHEMA=http - export NODE_ENV=testing - + # echo "Skipping tests" # return 0 @@ -238,6 +237,7 @@ combine_css || return 1 echo "Starting application for tests..." + systemctl --user stop express-blog@"$branch".service nohup node src/app.js >>"$logfile" 2>&1 & echo $! >"$pidfile" @@ -249,7 +249,6 @@ run_tests "$branch" "$pidfile" "$logfile" || return 1 kill "$(cat "$pidfile")" 2>/dev/null || true - unset TEST_PORT TEST_SCHEMA NODE_ENV echo "Tests passed for branch '$branch' in temporary environment." return 0 @@ -274,7 +273,7 @@ wait_for_service() { local logfile="$1" # Wait for the application to become responsive - if ! _wait_for_service "http://127.0.0.1:$TEST_PORT"; then + if ! _wait_for_service "$SERVER_SCHEMA://$SERVER_DOMAIN"; then echo "Application did not start or respond for tests. Check logs in $logfile:" cat "$logfile" # Display logs on failure return 1 diff --git a/.githooks/pre-push b/.githooks/pre-push index 86e9f52..93153bc 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -9,11 +9,6 @@ set -euo pipefail set -x - -export TEST_SCHEMA="http" -export TEST_DOMAIN="127.0.0.1" -export TEST_PORT=4123 - node src/app.js >/dev/null 2>&1 & APP_PID=$! diff --git a/.gitignore b/.gitignore index 205f9ee..c618026 100755 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,5 @@ data/* !data/.gitkeep .last_tested_commit + +certs/* diff --git a/scripts/testHttp.js b/scripts/testHttp.js new file mode 100644 index 0000000..3643cf6 --- /dev/null +++ b/scripts/testHttp.js @@ -0,0 +1,57 @@ +const fetch = require("node-fetch"); +const http = require("http"); +const https = require("https"); +const fs = require("fs"); + +require("dotenv").config(); + +// Get URL from command-line arguments +const baseUrl = process.argv[2]; +if (!baseUrl) { + console.error("Usage: node routes.test.js "); + process.exit(1); +} + +const useHttps = baseUrl.startsWith("https"); + +const agent = useHttps + ? new https.Agent({ + keepAlive: true, + maxSockets: 10, + timeout: 10000, + // Uncomment if using SSL certs + // ca: fs.readFileSync(process.env.SSL_CA_PATH), + // cert: fs.readFileSync(process.env.SSL_CERT_PATH), + // key: fs.readFileSync(process.env.SSL_KEY_PATH), + // rejectUnauthorized: true, + }) + : new http.Agent({ + keepAlive: true, + maxSockets: 10, + timeout: 10000, + }); + +const controller = new AbortController(); +const timeout = setTimeout(() => controller.abort(), 10000); + +fetch(baseUrl, { + method: "GET", + agent, + redirect: "manual", // Do not follow redirects + signal: controller.signal, +}) + .then(async (res) => { + console.log(await res.headers); + console.log(await res.status); + // console.log(await res.text()); + }) + .catch((err) => { + if (err.name === "AbortError") { + console.error("Request timed out"); + } else { + console.error("Fetch error:", err); + } + }) + .finally(() => { + clearTimeout(timeout); + }); diff --git a/src/middleware/redirect.js b/src/middleware/redirect.js index b93f25a..cf206c5 100644 --- a/src/middleware/redirect.js +++ b/src/middleware/redirect.js @@ -10,36 +10,21 @@ // '/old-path': '/new-path', }; -// Helper function to build full URL -function buildRedirectUrl(req, targetPath) { - const protocol = req.get("x-forwarded-proto") || req.protocol; - const host = req.get("host"); - - // If targetPath is already a full URL, return it as-is - if (targetPath.startsWith("http")) { - return targetPath; - } - - // Build full URL - return `${protocol}://${host}${targetPath}`; -} - // Generic redirect handler function handleRedirect(req, res, targetPath, status = 302) { - const redirectUrl = buildRedirectUrl(req, targetPath); + const redirectUrl = qualifyLink(targetPath); // Check if this is a request that expects JSON (API calls) if (req.accepts("json") && !req.accepts("html")) { - return res.status(301).json({ + return res.status(status).json({ redirect: true, url: redirectUrl, }); } - res.set("Location", redirectUrl); - // For browsers, render the redirect page res.status(301); + res.set("Location", redirectUrl); res.renderWithBaseContext("pages/redirect", { redirectUrl: redirectUrl, originalUrl: req.originalUrl, @@ -48,9 +33,9 @@ // Middleware function to check for redirects function redirectMiddleware(req, res, next) { res.customRedirect = (targetPath, status) => - handleRedirect(req, res, qualifyLink(targetPath), status); - const targetPath = redirectConfig[req.path]; + handleRedirect(req, res, targetPath, status); + const targetPath = redirectConfig[req.path]; if (targetPath) { return handleRedirect(req, res, targetPath, 301); } diff --git a/src/routes/index.js b/src/routes/index.js index 5197f9d..346a771 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -75,7 +75,7 @@ }); router.use((req, res, next) => { - req.log(req.url); + req.log.warn(req.url); next(new HttpError("Page not found", 404)); }); diff --git a/src/utils/baseUrl.js b/src/utils/baseUrl.js index 535f5bc..015ee03 100644 --- a/src/utils/baseUrl.js +++ b/src/utils/baseUrl.js @@ -10,7 +10,8 @@ .replace(/^https?:\/\//, "") .replace(/\/$/, ""); - return `${finalProtocol}://${finalDomain}${finalPort != 80 ? `:${finalPort}` : ""}`; + // return `${finalProtocol}://${finalDomain}${finalPort != 80 ? `:${finalPort}` : ""}`; + return `${finalProtocol}://${finalDomain}`; } const baseUrl = getBaseUrl(); diff --git a/test/routes.test.js b/test/routes.test.js index 1d4538c..03f7bf7 100644 --- a/test/routes.test.js +++ b/test/routes.test.js @@ -2,17 +2,17 @@ const fetch = require("node-fetch"); const { expect } = require("chai"); const http = require("http"); +const https = require("https"); -let port = process.env.TEST_PORT; -let schema = process.env.TEST_SCHEMA; -let domain = process.env.se; +const fs = require("fs"); + require("dotenv").config(); -domain = domain || process.env.TEST_DOMAIN || process.env.SERVER_DOMAIN; -port = port || process.env.TEST_PORT || process.env.SERVER_PORT; -schema = schema || process.env.TEST_SCHEMA || process.env.SERVER_SCHEMA; +const domain = process.env.SERVER_DOMAIN; +const port = process.env.SERVER_PORT; +const schema = process.env.SERVER_SCHEMA; const server_address = process.env.SERVER_ADDRESS; -const baseUrl = `${schema}://${server_address}:${port}`; +const baseUrl = `${schema}://${domain}`; // Create a proper HTTP agent const httpAgent = new http.Agent({ @@ -21,6 +21,24 @@ timeout: 10000, }); +const useHttps = schema === "https"; + +const agent = useHttps + ? new https.Agent({ + keepAlive: true, + maxSockets: 10, + timeout: 10000, + // ca: fs.readFileSync(process.env.SSL_CA_PATH), + // cert: fs.readFileSync(process.env.SSL_CERT_PATH), + // key: fs.readFileSync(process.env.SSL_KEY_PATH), + rejectUnauthorized: true, // or false if using self-signed certs during dev + }) + : new http.Agent({ + keepAlive: true, + maxSockets: 10, + timeout: 10000, + }); + describe(`API route status tests with dependencies at ${baseUrl}`, () => { let serverOnline = false; let routes = []; @@ -34,12 +52,12 @@ it("should confirm server is online via /health", async () => { const res = await fetch(baseUrl + "/health", { - agent: httpAgent, + agent, timeout: 5000, method: "HEAD", redirect: "manual", }); - // console.log("Healthcheck body: ", res.text()); + console.log("Healthcheck body: ", await res.text()); expect(res.ok).to.be.true; serverOnline = true; }); @@ -51,7 +69,7 @@ try { const res = await fetch(baseUrl + "/sitemap.json", { - agent: httpAgent, + agent, timeout: 10000, }); @@ -110,38 +128,43 @@ } }); - it("should return 200 for all routes, except / route which should return 301", async function () { - this.timeout(30000); // 30 second timeout for entire test + it( + "should return 200 for all routes, except " + + baseUrl + + " route which should return 301", + async function () { + this.timeout(30000); // 30 second timeout for entire test - if (!serverOnline || routes.length === 0) { - this.skip(); - } + if (!serverOnline || routes.length === 0) { + this.skip(); + } - for (const route of routes) { - // Skip the root route and any routes without a proper loc - if (route.loc && route.loc !== "/" && route.loc !== "#") { - const url = route.loc; - // console.log(`Testing route: ${url}`); + for (const route of routes) { + // Skip the root route and any routes without a proper loc + if (route.loc && route.loc !== baseUrl + "/" && route.loc !== "#") { + const url = route.loc; + // console.log(`Testing route: ${url}`); - try { - const res = await fetch(url, { - method: "GET", - agent: httpAgent, - timeout: 10000, - }); + try { + const res = await fetch(url, { + method: "GET", + agent, + timeout: 10000, + }); - expect( - res.status, - `Route GET ${route.loc} should return 200` - ).to.equal(200); - } catch (error) { - console.error(route); - console.error(`Error testing route ${route.loc}:`, error.message); - throw error; + expect( + res.status, + `Route GET ${route.loc} should return 200` + ).to.equal(200); + } catch (error) { + console.error(route); + console.error(`Error testing route ${route.loc}:`, error.message); + throw error; + } } } } - }); + ); // Optional: Test the root route separately if you expect it to return 301 it("should return 301 for / route", async function () { @@ -151,7 +174,7 @@ try { const res = await fetch(baseUrl + "/", { - agent: httpAgent, + agent, timeout: 10000, redirect: "manual", // Don't follow redirects automatically });