Skip to content

Commit 021a7d9

Browse files
committed
Add proxy isolation tests for GUI installer
Add block-list feature to proxy server
1 parent a8746f4 commit 021a7d9

11 files changed

+195
-73
lines changed

tests/CLIRunner.test.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"nonInteractive": false // Whether to prevent running in non-interactive mode (set to true if omitted)
1717
},
1818
"deleteAfterTest": true // Whether to remove IDF installation folder and IDF tools folder after test
19-
"testProxyMode": "block" // If the test run with local proxy to log or block internet access during test : "block", "log", false
19+
"testProxyMode": "block" // If the test run with local proxy to log or block internet access during test : "block", "block-list", "log", false
20+
"proxyBlockList": [] // List of domains to block when testProxyMode is set to "block-list"
2021
2122
2223
*/
@@ -84,6 +85,7 @@ function testRun(jsonScript) {
8485

8586
const deleteAfterTest = test.deleteAfterTest ?? true;
8687
const testProxyMode = test.testProxyMode ?? false;
88+
const proxyBlockList = test.proxyBlockList ?? [];
8789

8890
describe(`Test${test.id}- ${test.name} |`, function () {
8991
this.timeout(6000000);
@@ -92,6 +94,7 @@ function testRun(jsonScript) {
9294
id: `${test.id}1`,
9395
pathToEIM: pathToEIMCLI,
9496
testProxyMode,
97+
proxyBlockList,
9598
});
9699

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

139142
test.data.toolsMirror &&
140-
installArgs.push(`-m ${TOOLSMIRRORS[test.data.toolsMirror] || "https://github.com"}`);
143+
installArgs.push(
144+
`-m ${TOOLSMIRRORS[test.data.toolsMirror] || "https://github.com"}`
145+
);
141146

142147
test.data.idfMirror &&
143-
installArgs.push(`--idf-mirror ${IDFMIRRORS[test.data.idfMirror] || "https://github.com"}`);
148+
installArgs.push(
149+
`--idf-mirror ${
150+
IDFMIRRORS[test.data.idfMirror] || "https://github.com"
151+
}`
152+
);
144153

145154
test.data.pypiMirror &&
146-
installArgs.push(`--pypi-mirror ${PYPIMIRRORS[test.data.pypiMirror] || "https://pypi.org/simple"}`);
155+
installArgs.push(
156+
`--pypi-mirror ${
157+
PYPIMIRRORS[test.data.pypiMirror] || "https://pypi.org/simple"
158+
}`
159+
);
147160

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

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

153166
const deleteAfterTest = test.deleteAfterTest ?? true;
154167
const testProxyMode = test.testProxyMode ?? false;
168+
const proxyBlockList = test.proxyBlockList ?? [];
155169

156170
describe(`Test${test.id}- ${test.name} |`, function () {
157171
this.timeout(6000000);
@@ -161,6 +175,7 @@ function testRun(jsonScript) {
161175
pathToEIM: pathToEIMCLI,
162176
args: installArgs,
163177
testProxyMode,
178+
proxyBlockList,
164179
});
165180

166181
runInstallVerification({
@@ -193,7 +208,7 @@ function testRun(jsonScript) {
193208
: INSTALLFOLDER;
194209

195210
const deleteAfterTest = test.deleteAfterTest ?? true;
196-
211+
197212
describe(`Test${test.id}- ${test.name} |`, function () {
198213
this.timeout(60000);
199214

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

219235
describe(`Test${test.id}- ${test.name} |`, async function () {
220236
this.timeout(6000000);
@@ -225,6 +241,7 @@ function testRun(jsonScript) {
225241
offlineIDFVersion: IDFDefaultVersion,
226242
offlinePkgName: pkgName,
227243
testProxyMode,
244+
proxyBlockList,
228245
});
229246

230247
runInstallVerification({

tests/GUIRunner.test.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"pypiMirror": "pypi_org", // Mirror to download python packages "pypi_org", "pypi_aliyun", "pypi_tsinghua", "pypi_ustc"
1515
}
1616
"deleteAfterTest": true // Whether to remove IDF installation folder and IDF tools folder after test
17-
"testProxyMode": "block" // If the test run with local proxy to log or block internet access during test : "block", "log", false
17+
"testProxyMode": "block" // If the test run with local proxy to log or block internet access during test : "block", "block-list", "log", false
18+
"proxyBlockList": [] // List of domains to block when testProxyMode is set to "block-list"
1819
1920
*/
2021

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

7172
const deleteAfterTest = test.deleteAfterTest ?? true;
73+
const testProxyMode = test.testProxyMode ?? false;
74+
const proxyBlockList = test.proxyBlockList ?? [];
7275

7376
describe(`Test${test.id}- ${test.name} |`, function () {
7477
runGUISimplifiedInstallTest({
7578
id: `${test.id}1`,
7679
pathToEIM: pathToEIMGUI,
80+
testProxyMode,
81+
proxyBlockList,
7782
});
7883

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

124129
const deleteAfterTest = test.deleteAfterTest ?? true;
130+
const testProxyMode = test.testProxyMode ?? false;
131+
const proxyBlockList = test.proxyBlockList ?? [];
125132

126133
describe(`Test${test.id}- ${test.name} |`, function () {
127134
runGUICustomInstallTest({
@@ -133,6 +140,8 @@ function testRun(script) {
133140
toolsMirror,
134141
idfMirror,
135142
pypiMirror,
143+
testProxyMode,
144+
proxyBlockList,
136145
});
137146

138147
runGUIAfterInstallTest({
@@ -170,7 +179,7 @@ function testRun(script) {
170179
? path.join(os.homedir(), test.data.installFolder)
171180
: INSTALLFOLDER;
172181
const deleteAfterTest = test.deleteAfterTest ?? true;
173-
182+
174183
describe(`Test${test.id}- ${test.name} |`, function () {
175184
this.timeout(60000);
176185

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

198207
const deleteAfterTest = test.deleteAfterTest ?? true;
208+
const testProxyMode = test.testProxyMode ?? "block";
209+
const proxyBlockList = test.proxyBlockList ?? [];
199210

200211
describe(`Test${test.id}- ${test.name} |`, function () {
201212
this.timeout(6000000);
@@ -205,6 +216,8 @@ function testRun(script) {
205216
pathToEIM: pathToEIMGUI,
206217
offlineIDFVersion: IDFDefaultVersion,
207218
offlinePkgName: pkgName,
219+
testProxyMode,
220+
proxyBlockList,
208221
});
209222

210223
runGUIAfterInstallTest({

tests/classes/CLITestRunner.class.js

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -44,56 +44,11 @@ class CLITestRunner {
4444
}
4545
}
4646

47-
// Create isolated environment for network blocking
48-
createIsolatedEnvironment() {
49-
const proxyUrl = "http://127.0.0.1:8888";
50-
51-
// Set proxy environment variables to a monitoring server
52-
this.environment.HTTP_PROXY = proxyUrl;
53-
this.environment.HTTPS_PROXY = proxyUrl;
54-
this.environment.http_proxy = proxyUrl;
55-
this.environment.https_proxy = proxyUrl;
56-
this.environment.FTP_PROXY = proxyUrl;
57-
this.environment.ftp_proxy = proxyUrl;
58-
this.environment.NO_PROXY = "";
59-
this.environment.no_proxy = "";
60-
61-
// Additional environment variables that some tools respect
62-
this.environment.REQUESTS_CA_BUNDLE = ""; // Disable SSL certificates for Python requests
63-
this.environment.CURL_CA_BUNDLE = ""; // Disable SSL certificates for curl
64-
this.environment.SSL_CERT_FILE = ""; // Disable SSL certificates
65-
this.environment.SSL_CERT_DIR = ""; // Disable SSL certificates
66-
67-
// Rust/Cargo specific
68-
this.environment.CARGO_HTTP_PROXY = proxyUrl;
69-
this.environment.CARGO_HTTPS_PROXY = proxyUrl;
70-
71-
// Git specific
72-
this.environment.GIT_PROXY_COMMAND = "";
73-
74-
// Node.js specific
75-
this.environment.npm_config_proxy = proxyUrl;
76-
this.environment.npm_config_https_proxy = proxyUrl;
77-
78-
// Python pip specific
79-
this.environment.PIP_PROXY = proxyUrl;
80-
81-
logger.debug("Network isolation environment variables set");
82-
}
83-
84-
async start({
85-
command = this.command,
86-
fullArgs = this.args,
87-
isolatedEnvironment = false,
88-
} = {}) {
47+
async start({ command = this.command, fullArgs = this.args } = {}) {
8948
logger.debug(
9049
`Starting terminal emulator ${this.command} with args ${this.args}`
9150
);
9251

93-
if (isolatedEnvironment) {
94-
this.createIsolatedEnvironment();
95-
}
96-
9752
this.process = pty.spawn(command, fullArgs, {
9853
name: "eim-terminal",
9954
cols: 80,

tests/classes/TestProxy.class.js

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,51 @@ import net from "net";
44
import url from "url";
55

66
class TestProxy {
7-
constructor({ mode = "log" } = {}) {
7+
constructor({ mode = "log", blockedDomains = [] } = {}) {
88
this.port = 8888;
99
this.host = "127.0.0.1";
10-
this.mode = mode;
10+
this.mode = mode; // "log", "block" or "block-list"
1111
this.attempts = [];
1212
this.server = null;
13+
this.blockedDomains = blockedDomains.map((domain) => domain.toLowerCase());
14+
}
15+
16+
matchesBlocked(hostname) {
17+
if (!hostname) return false;
18+
const host = hostname.toLowerCase();
19+
return this.blockedDomains.some(
20+
(d) => host === d || host.endsWith("." + d)
21+
);
22+
}
23+
24+
setEnvironment() {
25+
logger.info("Setting proxy environment variables");
26+
const proxyUrl = "http://127.0.0.1:8888";
27+
let environment = { ...process.env };
28+
environment.HTTP_PROXY = proxyUrl;
29+
environment.HTTPS_PROXY = proxyUrl;
30+
environment.http_proxy = proxyUrl;
31+
environment.https_proxy = proxyUrl;
32+
environment.FTP_PROXY = proxyUrl;
33+
environment.ftp_proxy = proxyUrl;
34+
environment.NO_PROXY = "127.0.0.1,localhost,::1";
35+
environment.no_proxy = "127.0.0.1,localhost,::1";
36+
environment.CARGO_HTTP_PROXY = proxyUrl;
37+
environment.CARGO_HTTPS_PROXY = proxyUrl;
38+
environment.GIT_PROXY_COMMAND = "";
39+
environment.npm_config_proxy = proxyUrl;
40+
environment.npm_config_https_proxy = proxyUrl;
41+
environment.PIP_PROXY = proxyUrl;
42+
process.env = { ...environment };
1343
}
1444

1545
async start() {
46+
if (this.server) {
47+
logger.info("Proxy server already running");
48+
return;
49+
}
1650
logger.info(`Starting proxy server with mode ${this.mode}`);
17-
if (this.server) return;
18-
51+
this.setEnvironment();
1952
this.server = http.createServer((req, res) => {
2053
this.attempts.push({ type: "http", method: req.method, url: req.url });
2154
logger.info(`New HTTP connection attempt: ${req.url}`);
@@ -26,7 +59,6 @@ class TestProxy {
2659
logger.debug("HTTP Connection blocked");
2760
return;
2861
}
29-
3062
const hostHeader = req.headers["host"];
3163
let hostname, port;
3264

@@ -40,6 +72,19 @@ class TestProxy {
4072
port = port || 80;
4173
}
4274

75+
if (this.mode === "block-list" && this.matchesBlocked(hostname)) {
76+
this.attempts.push({
77+
type: "http",
78+
method: req.method,
79+
url: req.url,
80+
blocked: true,
81+
});
82+
res.writeHead(503, { "Content-Type": "text/plain" });
83+
res.end("Blocked by test proxy (domain block-list)");
84+
logger.debug(`HTTP Connection to ${hostname} blocked by domain list`);
85+
return;
86+
}
87+
4388
const options = {
4489
hostname,
4590
port,
@@ -48,6 +93,9 @@ class TestProxy {
4893
headers: req.headers,
4994
};
5095

96+
logger.info(`Proxying request to ${hostname}:${port}${req.url}`);
97+
logger.info(options);
98+
5199
const proxyReq = http.request(options, (proxyRes) => {
52100
res.writeHead(proxyRes.statusCode, proxyRes.headers);
53101
proxyRes.pipe(res);
@@ -56,6 +104,7 @@ class TestProxy {
56104
req.pipe(proxyReq);
57105

58106
proxyReq.on("error", (err) => {
107+
logger.info("HTTP Proxy request error:", err);
59108
res.writeHead(500);
60109
res.end("Proxy error: " + err.message);
61110
});
@@ -74,14 +123,25 @@ class TestProxy {
74123
}
75124

76125
const [host, port] = req.url.split(":");
126+
127+
if (this.mode === "block-list" && this.matchesBlocked(host)) {
128+
this.attempts.push({ type: "https", host, blocked: true });
129+
logger.info(`HTTPS Connection to ${host} blocked by domain list`);
130+
clientSocket.write("HTTP/1.1 503 Service Unavailable\r\n\r\n");
131+
clientSocket.end();
132+
return;
133+
}
134+
logger.info(`Proxying CONNECT to ${host}:${port}`);
135+
77136
const serverSocket = net.connect(port || 443, host, () => {
78137
clientSocket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
79138
serverSocket.write(head);
80139
serverSocket.pipe(clientSocket);
81140
clientSocket.pipe(serverSocket);
82141
});
83142

84-
serverSocket.on("error", () => {
143+
serverSocket.on("error", (err) => {
144+
logger.info("HTTPS Connection error:", err);
85145
clientSocket.write("HTTP/1.1 500 Connection error\r\n\r\n");
86146
clientSocket.end();
87147
});

tests/scripts/CLICustomInstall.test.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export function runCLICustomInstallTest({
1313
offlineIDFVersion = null,
1414
offlinePkgName = null,
1515
testProxyMode = false,
16+
proxyBlockList = [],
1617
}) {
1718
describe(`${id}- Run custom |`, function () {
1819
let testRunner = null;
@@ -35,17 +36,18 @@ export function runCLICustomInstallTest({
3536
}
3637
if (testProxyMode) {
3738
try {
38-
proxy = new TestProxy({ mode: testProxyMode });
39+
proxy = new TestProxy({
40+
mode: testProxyMode,
41+
blockedDomains: proxyBlockList,
42+
});
3943
await proxy.start();
4044
} catch (error) {
4145
logger.info("Error to start proxy server");
4246
logger.debug(`Error: ${error}`);
4347
}
4448
}
4549
try {
46-
await testRunner.start({
47-
isolatedEnvironment: testProxyMode === false ? false : true,
48-
});
50+
await testRunner.start();
4951
} catch (error) {
5052
logger.info("Error to start terminal");
5153
logger.debug(`Error: ${error}`);

0 commit comments

Comments
 (0)