Skip to content

Commit 1678a71

Browse files
Merge pull request #57 from Benzyl-titanium/master
Fix: update test-webservices
2 parents 5b0f0fb + a6c1323 commit 1678a71

2 files changed

Lines changed: 86 additions & 99 deletions

File tree

.github/scripts/test-webservices.js

Lines changed: 82 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,25 @@ const fs = require('fs');
44
const path = require('path');
55

66
const TEST_SMILES = [
7-
'C(C1=CC=CC=C1)[Ti](CC1=CC=CC=C1)(CC1=CC=CC=C1)CC1=CC=CC=C1',
8-
'O=C(O)C[C@H](CC(C)C)CN',
9-
'CNCCC(C1=CC=CC=C1)OC2=CC=C(C=C2)C(F)(F)F',
7+
'CCCCCCCCC=O',
108
];
119

10+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
11+
12+
function getSpoofedHeaders(targetUrl) {
13+
try {
14+
const urlObj = new URL(targetUrl);
15+
return {
16+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
17+
'Origin': urlObj.origin,
18+
'Referer': urlObj.origin + '/',
19+
'Content-Type': 'application/json'
20+
};
21+
} catch (e) {
22+
return { 'Content-Type': 'application/json' };
23+
}
24+
}
25+
1226
function loadWebservicesConfig() {
1327
try {
1428
const webservicesPath = path.join(process.cwd(), 'public/marvin/js/webservices.js');
@@ -40,13 +54,20 @@ function loadWebservicesConfig() {
4054
async function testServiceEndpoint(url, timeout = 10000) {
4155
try {
4256
console.log(`Testing endpoint: ${url}`);
57+
58+
const headers = getSpoofedHeaders(url);
59+
delete headers['Content-Type'];
60+
4361
const response = await axios.get(url, {
4462
timeout,
63+
headers: headers,
4564
validateStatus: function (status) {
4665
return status < 500;
4766
}
4867
});
4968

69+
await sleep(500);
70+
5071
console.log(`Endpoint ${url} responded with status: ${response.status}`);
5172
return {
5273
success: response.status < 400 || response.status === 405,
@@ -66,39 +87,48 @@ async function testServiceEndpoint(url, timeout = 10000) {
6687
async function testSmilesConversion(serviceUrl, smiles, timeout = 15000) {
6788
try {
6889
console.log(`Testing SMILES conversion: ${smiles}`);
69-
70-
const formats = ['mol', 'sdf', 'smiles'];
90+
91+
const formats = ['mol', 'smiles'];
7192
const results = [];
7293

7394
for (const format of formats) {
74-
try {
75-
const response = await axios.post(serviceUrl, {
76-
structure: smiles,
77-
parameters: `${format}`
78-
}, {
79-
timeout,
80-
headers: {
81-
'Content-Type': 'application/json'
95+
let retries = 1;
96+
let success = false;
97+
let response = null;
98+
let lastError = null;
99+
100+
while (retries >= 0 && !success) {
101+
try {
102+
await sleep(1000);
103+
104+
response = await axios.post(serviceUrl, {
105+
structure: smiles,
106+
parameters: `${format}`
107+
}, {
108+
timeout,
109+
headers: getSpoofedHeaders(serviceUrl)
110+
});
111+
112+
if (response.status === 200) {
113+
success = true;
82114
}
83-
});
84-
85-
const success = response.status === 200 && response.data;
86-
results.push({
87-
format,
88-
success,
89-
status: response.status,
90-
hasData: !!response.data
91-
});
92-
93-
console.log(`SMILES ${smiles} -> ${format}: ${success ? 'SUCCESS' : 'FAILED'}`);
94-
} catch (error) {
95-
results.push({
96-
format,
97-
success: false,
98-
error: error.message
99-
});
100-
console.log(`SMILES ${smiles} -> ${format}: FAILED (${error.message})`);
115+
} catch (error) {
116+
lastError = error;
117+
if (error.response && error.response.status === 429) {
118+
console.log(`Rate limited (429), waiting 3s...`);
119+
await sleep(3000);
120+
}
121+
retries--;
122+
}
101123
}
124+
125+
results.push({
126+
format,
127+
success,
128+
status: response ? response.status : 'ERR',
129+
error: success ? null : (lastError ? lastError.message : 'Unknown')
130+
});
131+
console.log(`SMILES ${smiles} -> ${format}: ${success ? 'SUCCESS' : 'FAILED'}`);
102132
}
103133

104134
return {
@@ -107,12 +137,7 @@ async function testSmilesConversion(serviceUrl, smiles, timeout = 15000) {
107137
overallSuccess: results.some(r => r.success)
108138
};
109139
} catch (error) {
110-
console.error(`SMILES conversion test failed for ${smiles}:`, error.message);
111-
return {
112-
smiles,
113-
success: false,
114-
error: error.message
115-
};
140+
return { smiles, success: false, error: error.message };
116141
}
117142
}
118143

@@ -129,43 +154,18 @@ async function sendEmailNotification(failedServices, failedConversions) {
129154
try {
130155
const transporter = nodemailer.createTransporter({
131156
service: 'gmail',
132-
auth: {
133-
user: emailUser,
134-
pass: emailPass
135-
}
157+
auth: { user: emailUser, pass: emailPass }
136158
});
137159

138-
const failedServicesList = failedServices.map(s => `- ${s.url}: ${s.error || s.status}`).join('\n');
139-
const failedConversionsList = failedConversions.map(c => `- ${c.smiles}: ${c.error || 'Conversion failed'}`).join('\n');
160+
const failedList = [...failedServices, ...failedConversions]
161+
.map(f => `- ${f.url || f.smiles}: ${f.error || 'Failed'}`).join('\n');
140162

141-
const mailOptions = {
163+
await transporter.sendMail({
142164
from: emailUser,
143165
to: notificationEmail,
144-
subject: '🚨 Webservice Health Check Failed - SMILES Conversion Issues',
145-
html: `
146-
<h2>Webservice Health Check Failed</h2>
147-
<p><strong>Time:</strong> ${new Date().toISOString()}</p>
148-
<p><strong>Repository:</strong> StructuredSearch</p>
149-
150-
<h3>Failed Services (${failedServices.length})</h3>
151-
<pre>${failedServicesList}</pre>
152-
153-
<h3>Failed SMILES Conversions (${failedConversions.length})</h3>
154-
<pre>${failedConversionsList}</pre>
155-
156-
<h3>Recommended Actions</h3>
157-
<ul>
158-
<li>Check the webservice server status</li>
159-
<li>Verify network connectivity</li>
160-
<li>Update webservice URLs if necessary</li>
161-
<li>Check GitHub Issues for automated issue creation</li>
162-
</ul>
163-
164-
<p><em>This notification was sent automatically by the GitHub Actions workflow.</em></p>
165-
`
166-
};
167-
168-
await transporter.sendMail(mailOptions);
166+
subject: '🚨 Webservice Health Check Failed',
167+
html: `<h3>Health Check Failed</h3><pre>${failedList}</pre>`
168+
});
169169
console.log('Email notification sent successfully');
170170
} catch (error) {
171171
console.error('Failed to send email notification:', error.message);
@@ -193,37 +193,29 @@ async function runHealthCheck() {
193193

194194
console.log('\n=== Testing SMILES Conversions ===');
195195
const molconvertUrl = config.services.molconvert;
196-
197-
for (const smiles of TEST_SMILES) {
198-
const result = await testSmilesConversion(molconvertUrl, smiles);
199-
if (!result.overallSuccess) {
200-
hasFailures = true;
201-
failedConversions.push(result);
196+
197+
if (!hasFailures) {
198+
for (const smiles of TEST_SMILES) {
199+
const result = await testSmilesConversion(molconvertUrl, smiles);
200+
if (!result.overallSuccess) {
201+
hasFailures = true;
202+
failedConversions.push(result);
203+
}
202204
}
203205
}
204-
205-
console.log('\n=== Health Check Summary ===');
206-
console.log(`Failed Services: ${failedServices.length}`);
207-
console.log(`Failed Conversions: ${failedConversions.length}`);
208-
console.log(`Overall Status: ${hasFailures ? 'FAILED' : 'PASSED'}`);
206+
207+
console.log('\n=== Summary ===');
208+
console.log(`Status: ${hasFailures ? 'FAILED' : 'PASSED'}`);
209209

210210
if (hasFailures) {
211211
await sendEmailNotification(failedServices, failedConversions);
212-
}
213-
214-
const hasConversionFailures = failedConversions.length > 0;
215-
216-
if (hasConversionFailures) {
217-
console.error('Health check failed - SMILES conversion is not working correctly');
218212
process.exit(1);
219213
} else {
220-
console.log('Health check passed - SMILES conversion is working correctly');
221214
process.exit(0);
222215
}
223216

224217
} catch (error) {
225-
console.error('Health check encountered an error:', error.message);
226-
console.error(error.stack);
218+
console.error('Error:', error.message);
227219
process.exit(1);
228220
}
229221
}
@@ -232,9 +224,4 @@ if (require.main === module) {
232224
runHealthCheck();
233225
}
234226

235-
module.exports = {
236-
runHealthCheck,
237-
testServiceEndpoint,
238-
testSmilesConversion,
239-
loadWebservicesConfig
240-
};
227+
module.exports = { runHealthCheck };

public/marvin/js/webservices.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ function getDefaultServices() {
1010
var base = getDefaultServicesPrefix();
1111
var services = {
1212
"clean2dws": base + "/rest-v1/util/convert/clean",
13-
// "clean3dws" : base + "/rest-v1/util/convert/clean",
13+
"clean3dws" : base + "/rest-v1/util/convert/clean",
1414
"molconvertws": base + "/rest-v1/util/calculate/molExport",
1515
"stereoinfows": base + "/rest-v1/util/calculate/cipStereoInfo",
16-
// "reactionconvertws" : base + "/rest-v1/util/calculate/reactionExport",
17-
// "hydrogenizews" : base + "/rest-v1/util/convert/hydrogenizer",
18-
// "automapperws" : base + "/rest-v1/util/convert/reactionConverter",
16+
"reactionconvertws" : base + "/rest-v1/util/calculate/reactionExport",
17+
"hydrogenizews" : base + "/rest-v1/util/convert/hydrogenizer",
18+
"automapperws" : base + "/rest-v1/util/convert/reactionConverter",
1919
"aromatizews": base + "/rest-v1/util/calculate/molExport"
2020
};
2121
return services;

0 commit comments

Comments
 (0)