Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions tests/CLIRunner.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"nonInteractive": false // Whether to prevent running in non-interactive mode (set to true if omitted)
},
"deleteAfterTest": true // Whether to remove IDF installation folder and IDF tools folder after test
"testProxyMode": "block" // If the test run with local proxy to log or block internet access during test : "block", "log", false
"testProxyMode": "block" // If the test run with local proxy to log or block internet access during test : "block", "block-list", "log", false
"proxyBlockList": [] // List of domains to block when testProxyMode is set to "block-list"


*/
Expand Down Expand Up @@ -84,6 +85,7 @@ function testRun(jsonScript) {

const deleteAfterTest = test.deleteAfterTest ?? true;
const testProxyMode = test.testProxyMode ?? false;
const proxyBlockList = test.proxyBlockList ?? [];

describe(`Test${test.id}- ${test.name} |`, function () {
this.timeout(6000000);
Expand All @@ -92,6 +94,7 @@ function testRun(jsonScript) {
id: `${test.id}1`,
pathToEIM: pathToEIMCLI,
testProxyMode,
proxyBlockList,
});

runInstallVerification({
Expand Down Expand Up @@ -137,13 +140,23 @@ function testRun(jsonScript) {
test.data.idfList && installArgs.push(`-i ${idfUpdatedList.join(",")}`);

test.data.toolsMirror &&
installArgs.push(`-m ${TOOLSMIRRORS[test.data.toolsMirror] || "https://github.com"}`);
installArgs.push(
`-m ${TOOLSMIRRORS[test.data.toolsMirror] || "https://github.com"}`
);

test.data.idfMirror &&
installArgs.push(`--idf-mirror ${IDFMIRRORS[test.data.idfMirror] || "https://github.com"}`);
installArgs.push(
`--idf-mirror ${
IDFMIRRORS[test.data.idfMirror] || "https://github.com"
}`
);

test.data.pypiMirror &&
installArgs.push(`--pypi-mirror ${PYPIMIRRORS[test.data.pypiMirror] || "https://pypi.org/simple"}`);
installArgs.push(
`--pypi-mirror ${
PYPIMIRRORS[test.data.pypiMirror] || "https://pypi.org/simple"
}`
);

test.data.recursive && installArgs.push(`-r ${test.data.recursive}`);

Expand All @@ -152,6 +165,7 @@ function testRun(jsonScript) {

const deleteAfterTest = test.deleteAfterTest ?? true;
const testProxyMode = test.testProxyMode ?? false;
const proxyBlockList = test.proxyBlockList ?? [];

describe(`Test${test.id}- ${test.name} |`, function () {
this.timeout(6000000);
Expand All @@ -161,6 +175,7 @@ function testRun(jsonScript) {
pathToEIM: pathToEIMCLI,
args: installArgs,
testProxyMode,
proxyBlockList,
});

runInstallVerification({
Expand Down Expand Up @@ -193,7 +208,7 @@ function testRun(jsonScript) {
: INSTALLFOLDER;

const deleteAfterTest = test.deleteAfterTest ?? true;

describe(`Test${test.id}- ${test.name} |`, function () {
this.timeout(60000);

Expand All @@ -215,6 +230,7 @@ function testRun(jsonScript) {
//routine for offline installation test
const deleteAfterTest = test.deleteAfterTest ?? true;
const testProxyMode = test.testProxyMode ?? "block";
const proxyBlockList = test.proxyBlockList ?? [];

describe(`Test${test.id}- ${test.name} |`, async function () {
this.timeout(6000000);
Expand All @@ -225,6 +241,7 @@ function testRun(jsonScript) {
offlineIDFVersion: IDFDefaultVersion,
offlinePkgName: pkgName,
testProxyMode,
proxyBlockList,
});

runInstallVerification({
Expand Down
17 changes: 15 additions & 2 deletions tests/GUIRunner.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"pypiMirror": "pypi_org", // Mirror to download python packages "pypi_org", "pypi_aliyun", "pypi_tsinghua", "pypi_ustc"
}
"deleteAfterTest": true // Whether to remove IDF installation folder and IDF tools folder after test
"testProxyMode": "block" // If the test run with local proxy to log or block internet access during test : "block", "log", false
"testProxyMode": "block" // If the test run with local proxy to log or block internet access during test : "block", "block-list", "log", false
"proxyBlockList": [] // List of domains to block when testProxyMode is set to "block-list"

*/

Expand Down Expand Up @@ -69,11 +70,15 @@ function testRun(script) {
//routine for default simplified installation

const deleteAfterTest = test.deleteAfterTest ?? true;
const testProxyMode = test.testProxyMode ?? false;
const proxyBlockList = test.proxyBlockList ?? [];

describe(`Test${test.id}- ${test.name} |`, function () {
runGUISimplifiedInstallTest({
id: `${test.id}1`,
pathToEIM: pathToEIMGUI,
testProxyMode,
proxyBlockList,
});

runGUIAfterInstallTest({
Expand Down Expand Up @@ -122,6 +127,8 @@ function testRun(script) {
const pypiMirror = test.data.pypiMirror || "pypi_org";

const deleteAfterTest = test.deleteAfterTest ?? true;
const testProxyMode = test.testProxyMode ?? false;
const proxyBlockList = test.proxyBlockList ?? [];

describe(`Test${test.id}- ${test.name} |`, function () {
runGUICustomInstallTest({
Expand All @@ -133,6 +140,8 @@ function testRun(script) {
toolsMirror,
idfMirror,
pypiMirror,
testProxyMode,
proxyBlockList,
});

runGUIAfterInstallTest({
Expand Down Expand Up @@ -170,7 +179,7 @@ function testRun(script) {
? path.join(os.homedir(), test.data.installFolder)
: INSTALLFOLDER;
const deleteAfterTest = test.deleteAfterTest ?? true;

describe(`Test${test.id}- ${test.name} |`, function () {
this.timeout(60000);

Expand All @@ -196,6 +205,8 @@ function testRun(script) {
: INSTALLFOLDER;

const deleteAfterTest = test.deleteAfterTest ?? true;
const testProxyMode = test.testProxyMode ?? "block";
const proxyBlockList = test.proxyBlockList ?? [];

describe(`Test${test.id}- ${test.name} |`, function () {
this.timeout(6000000);
Expand All @@ -205,6 +216,8 @@ function testRun(script) {
pathToEIM: pathToEIMGUI,
offlineIDFVersion: IDFDefaultVersion,
offlinePkgName: pkgName,
testProxyMode,
proxyBlockList,
});

runGUIAfterInstallTest({
Expand Down
50 changes: 2 additions & 48 deletions tests/classes/CLITestRunner.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class CLITestRunner {
os.platform() !== "win32"
? []
: ["-ExecutionPolicy", "Bypass", "-NoProfile"];
this.environment = { ...process.env };
}

async runIDFTerminal(loadScript, timeout = 3000) {
Expand All @@ -44,62 +43,17 @@ class CLITestRunner {
}
}

// Create isolated environment for network blocking
createIsolatedEnvironment() {
const proxyUrl = "http://127.0.0.1:8888";

// Set proxy environment variables to a monitoring server
this.environment.HTTP_PROXY = proxyUrl;
this.environment.HTTPS_PROXY = proxyUrl;
this.environment.http_proxy = proxyUrl;
this.environment.https_proxy = proxyUrl;
this.environment.FTP_PROXY = proxyUrl;
this.environment.ftp_proxy = proxyUrl;
this.environment.NO_PROXY = "";
this.environment.no_proxy = "";

// Additional environment variables that some tools respect
this.environment.REQUESTS_CA_BUNDLE = ""; // Disable SSL certificates for Python requests
this.environment.CURL_CA_BUNDLE = ""; // Disable SSL certificates for curl
this.environment.SSL_CERT_FILE = ""; // Disable SSL certificates
this.environment.SSL_CERT_DIR = ""; // Disable SSL certificates

// Rust/Cargo specific
this.environment.CARGO_HTTP_PROXY = proxyUrl;
this.environment.CARGO_HTTPS_PROXY = proxyUrl;

// Git specific
this.environment.GIT_PROXY_COMMAND = "";

// Node.js specific
this.environment.npm_config_proxy = proxyUrl;
this.environment.npm_config_https_proxy = proxyUrl;

// Python pip specific
this.environment.PIP_PROXY = proxyUrl;

logger.debug("Network isolation environment variables set");
}

async start({
command = this.command,
fullArgs = this.args,
isolatedEnvironment = false,
} = {}) {
async start({ command = this.command, fullArgs = this.args } = {}) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This refactoring has introduced a critical issue. The CLITestRunner instance is created before the proxy is started in the test scripts. The CLITestRunner constructor caches process.env into this.environment. Later, TestProxy.start() modifies process.env, but the CLITestRunner instance still holds the old, stale environment. Consequently, when testRunner.start() is called, it spawns a process using the stale environment, and the proxy settings are not applied.

To fix this, CLITestRunner should get the latest environment when spawning the process. A possible fix is to change the pty.spawn call inside the start method to use process.env directly instead of this.environment.

logger.debug(
`Starting terminal emulator ${this.command} with args ${this.args}`
);

if (isolatedEnvironment) {
this.createIsolatedEnvironment();
}

this.process = pty.spawn(command, fullArgs, {
name: "eim-terminal",
cols: 80,
rows: 30,
cwd: process.cwd(),
env: this.environment,
env: process.env,
});
this.exited = false;

Expand Down
70 changes: 64 additions & 6 deletions tests/classes/TestProxy.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,49 @@ import net from "net";
import url from "url";

class TestProxy {
constructor({ mode = "log" } = {}) {
constructor({ mode = "log", blockedDomains = [] } = {}) {
this.port = 8888;
this.host = "127.0.0.1";
this.mode = mode;
this.mode = mode; // "log", "block" or "block-list"
this.attempts = [];
this.server = null;
this.blockedDomains = blockedDomains.map((domain) => domain.toLowerCase());
}

matchesBlocked(hostname) {
if (!hostname) return false;
const host = hostname.toLowerCase();
return this.blockedDomains.some(
(d) => host === d || host.endsWith("." + d)
);
}

setEnvironment() {
logger.info("Setting proxy environment variables");
const proxyUrl = "http://127.0.0.1:8888";
process.env.HTTP_PROXY = proxyUrl;
process.env.HTTPS_PROXY = proxyUrl;
process.env.http_proxy = proxyUrl;
process.env.https_proxy = proxyUrl;
process.env.FTP_PROXY = proxyUrl;
process.env.ftp_proxy = proxyUrl;
process.env.NO_PROXY = "127.0.0.1,localhost,::1";
process.env.no_proxy = "127.0.0.1,localhost,::1";
process.env.CARGO_HTTP_PROXY = proxyUrl;
process.env.CARGO_HTTPS_PROXY = proxyUrl;
process.env.GIT_PROXY_COMMAND = "";
process.env.npm_config_proxy = proxyUrl;
process.env.npm_config_https_proxy = proxyUrl;
process.env.PIP_PROXY = proxyUrl;
}

async start() {
if (this.server) {
logger.info("Proxy server already running");
return;
}
logger.info(`Starting proxy server with mode ${this.mode}`);
if (this.server) return;

this.setEnvironment();
this.server = http.createServer((req, res) => {
this.attempts.push({ type: "http", method: req.method, url: req.url });
logger.info(`New HTTP connection attempt: ${req.url}`);
Expand All @@ -26,7 +57,6 @@ class TestProxy {
logger.debug("HTTP Connection blocked");
return;
}

const hostHeader = req.headers["host"];
let hostname, port;

Expand All @@ -40,6 +70,19 @@ class TestProxy {
port = port || 80;
}

if (this.mode === "block-list" && this.matchesBlocked(hostname)) {
this.attempts.push({
type: "http",
method: req.method,
url: req.url,
blocked: true,
});
res.writeHead(503, { "Content-Type": "text/plain" });
res.end("Blocked by test proxy (domain block-list)");
logger.debug(`HTTP Connection to ${hostname} blocked by domain list`);
return;
}

const options = {
hostname,
port,
Expand All @@ -48,6 +91,9 @@ class TestProxy {
headers: req.headers,
};

logger.info(`Proxying request to ${hostname}:${port}${req.url}`);
logger.info(options);

const proxyReq = http.request(options, (proxyRes) => {
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
Expand All @@ -56,6 +102,7 @@ class TestProxy {
req.pipe(proxyReq);

proxyReq.on("error", (err) => {
logger.info("HTTP Proxy request error:", err);
res.writeHead(500);
res.end("Proxy error: " + err.message);
});
Expand All @@ -74,14 +121,25 @@ class TestProxy {
}

const [host, port] = req.url.split(":");

if (this.mode === "block-list" && this.matchesBlocked(host)) {
this.attempts.push({ type: "https", host, blocked: true });
logger.info(`HTTPS Connection to ${host} blocked by domain list`);
clientSocket.write("HTTP/1.1 503 Service Unavailable\r\n\r\n");
clientSocket.end();
return;
}
logger.info(`Proxying CONNECT to ${host}:${port}`);

const serverSocket = net.connect(port || 443, host, () => {
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});

serverSocket.on("error", () => {
serverSocket.on("error", (err) => {
logger.info("HTTPS Connection error:", err);
clientSocket.write("HTTP/1.1 500 Connection error\r\n\r\n");
clientSocket.end();
});
Expand Down
10 changes: 6 additions & 4 deletions tests/scripts/CLICustomInstall.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function runCLICustomInstallTest({
offlineIDFVersion = null,
offlinePkgName = null,
testProxyMode = false,
proxyBlockList = [],
}) {
describe(`${id}- Run custom |`, function () {
let testRunner = null;
Expand All @@ -35,17 +36,18 @@ export function runCLICustomInstallTest({
}
if (testProxyMode) {
try {
proxy = new TestProxy({ mode: testProxyMode });
proxy = new TestProxy({
mode: testProxyMode,
blockedDomains: proxyBlockList,
});
await proxy.start();
} catch (error) {
logger.info("Error to start proxy server");
logger.debug(`Error: ${error}`);
}
}
try {
await testRunner.start({
isolatedEnvironment: testProxyMode === false ? false : true,
});
await testRunner.start();
} catch (error) {
logger.info("Error to start terminal");
logger.debug(`Error: ${error}`);
Expand Down
Loading
Loading