$darkmode
DENOPTIM
SocketProvidedDescriptorTest.java
Go to the documentation of this file.
1/*
2 * DENOPTIM
3 * Copyright (C) 2022 Marco Foscato <marco.foscato@uib.no>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published
7 * by the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package denoptim.fitness.descriptors;
20
21import static org.junit.jupiter.api.Assertions.assertFalse;
22import static org.junit.jupiter.api.Assertions.assertTrue;
23
24import java.io.BufferedReader;
25import java.io.IOException;
26import java.io.InputStreamReader;
27import java.io.PrintWriter;
28import java.lang.reflect.Constructor;
29import java.net.ServerSocket;
30import java.net.Socket;
31
32import org.junit.jupiter.api.AfterEach;
33import org.junit.jupiter.api.BeforeEach;
34import org.junit.jupiter.api.Test;
35import org.openscience.cdk.DefaultChemObjectBuilder;
36import org.openscience.cdk.interfaces.IAtomContainer;
37import org.openscience.cdk.qsar.result.DoubleResult;
38import org.openscience.cdk.smiles.SmilesParser;
39
40import com.google.gson.Gson;
41import com.google.gson.GsonBuilder;
42import com.google.gson.JsonObject;
43import com.google.gson.JsonSyntaxException;
44
52{
55 private Gson jsonConverted;
56
57 private static final String HOSTNAME = "localhost";
58
59
60//------------------------------------------------------------------------------
61
62 @BeforeEach
63 public void setUpSertver() throws Exception
64 {
65 // We create a socket server the SocketProvidedDescriptor can talk to.
66 server = new MySocketServer();
68 int port = server.getPort();
69
70 jsonConverted = new GsonBuilder().create();
71
72 Constructor<SocketProvidedDescriptor> defaultConstructor =
73 SocketProvidedDescriptor.class.getConstructor();
74 this.descriptor = defaultConstructor.newInstance();
75 this.descriptor.setParameters(new Object[] {HOSTNAME, port});
76 }
77
78//------------------------------------------------------------------------------
79
80 @AfterEach
81 public void ClossServer() throws Exception
82 {
84 }
85
86//------------------------------------------------------------------------------
87
88 /*
89 * The dummy server we create and try to communicate with.
90 */
91 private class MySocketServer extends Thread
92 {
93 private ServerSocket server;
94
95 public void startServer()
96 {
97 try
98 {
99 server = new ServerSocket(0);
100
101 Runtime.getRuntime().addShutdownHook(new Thread(){
102 public void run()
103 {
104 try {
105 server.close();
106 } catch (IOException e) { /* failed */ }
107 }
108 });
109 this.start();
110 }
111 catch (IOException e)
112 {
113 e.printStackTrace();
114 }
115 }
116
117 public int getPort()
118 {
119 return server.getLocalPort();
120 }
121
122 public void stopServer()
123 {
124 try
125 {
126 server.close();
127 } catch (IOException e)
128 {
129 e.printStackTrace();
130 }
131 this.interrupt();
132 }
133
134 @Override
135 public void run()
136 {
137 while(!server.isClosed())
138 {
139 try
140 {
141 RequestHandler handler = new RequestHandler(
142 server.accept());
143 handler.start();
144 }
145 catch (IOException e)
146 {
147 // There is some lag between the closing of the server and
148 // the notification it is closed, se we end up here when
149 // the unit test if finishing and we are closing up the
150 // socket.
151 //e.printStackTrace();
152 }
153 }
154 }
155 }
156
157 /*
158 * Thread handling any requests on the server side.
159 */
160 class RequestHandler extends Thread
161 {
162 private Socket socket;
164 {
165 this.socket = socket;
166 }
167
168 @Override
169 public void run()
170 {
171 try
172 {
173 BufferedReader in = new BufferedReader(new InputStreamReader(
174 socket.getInputStream()));
175
176 // Read request
177 StringBuilder sb = new StringBuilder();
178 String line = in.readLine();
179 while(line != null && line.length()>0)
180 {
181 sb.append(line).append(System.getProperty("line.separator"));
182 line = in.readLine();
183 }
184
185 //
186 // WARNING: this is where the format of the request is evaluated.
187 // Any change to the format convention should be reflected here.
188 //
189
190 // Evaluate request format
191 String jsonStr = sb.toString();
192 JsonObject request = null;
193 try {
194 request = jsonConverted.fromJson(jsonStr, JsonObject.class);
195 } catch (JsonSyntaxException e) {
196 e.printStackTrace();
197 assertFalse(true,"JsonSyntaxException unpon converting "
198 + "requst to socket server");
199 }
201 assertTrue(request.has(smiKey), "JSON request has no " + smiKey);
202
203 //
204 // WARNING: this assumes consistency between this class and the
205 // unit test method.
206 //
207
208 // Prepare an answer that differs based on the request
209 String smiles = request.get(smiKey).getAsString();
210 long count = smiles.chars().filter(c -> c == 'c').count();
211 double score = Math.pow((double) count,2.5);
212
213 JsonObject jsonAnswer = new JsonObject();
214 if (score>0.1)
215 {
216 jsonAnswer.addProperty(
218 } else {
219 jsonAnswer.addProperty(
221 "#SocketServer: fake error.");
222 }
223
224 // Send response
225 PrintWriter out = new PrintWriter(socket.getOutputStream());
226 out.println(jsonConverted.toJson(jsonAnswer));
227 out.flush();
228
229 // Do not close our connection: we'll be reusing it
230 //in.close();
231 //out.close();
232 }
233 catch (Exception e)
234 {
235 e.printStackTrace();
236 }
237 }
238 }
239
240//------------------------------------------------------------------------------
241
242 @Test
243 public void testSocketProvidedDescriptor() throws Exception
244 {
245 SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance());
246
247 String smiles = "O";
248 IAtomContainer mol1 = sp.parseSmiles(smiles);
249 mol1.setProperty("SMILES", smiles);
250 double value = ((DoubleResult) descriptor.calculate(mol1).getValue())
251 .doubleValue();
252 double expected = Double.NaN;
253 assertTrue(Double.isNaN(value), "Wrong socket-provided "
254 + "descriptor: expected " + expected + ", found "+ value + "(0)");
255
256 mol1.setProperty("SMILES", "c");
257 value = ((DoubleResult) descriptor.calculate(mol1).getValue())
258 .doubleValue();
259 expected = 1.0;
260 assertTrue(closeEnough(expected, value), "Wrong socket-provided "
261 + "descriptor: expected " + expected + ", found "+ value + "(1)");
262
263 mol1.setProperty("SMILES", "ccc");
264 value = ((DoubleResult) descriptor.calculate(mol1).getValue())
265 .doubleValue();
266 expected = 15.5884;
267 assertTrue(closeEnough(expected, value), "Wrong socket-provided "
268 + "descriptor: expected " + expected + ", found "+ value + "(2)");
269
270 smiles = "COc1ccccc1";
271 mol1 = sp.parseSmiles(smiles);
272 mol1.setProperty("SMILES", smiles);
273 value = ((DoubleResult) descriptor.calculate(mol1).getValue())
274 .doubleValue();
275 expected = 88.1816;
276 assertTrue(closeEnough(expected, value), "Wrong socket-provided "
277 + "descriptor: expected " + expected + ", found "+ value + "(3)");
278 }
279
280//------------------------------------------------------------------------------
281
282 private boolean closeEnough(double expected, double actual)
283 {
284 double threshold = 0.01;
285 double delta = Math.abs(expected-actual);
286 return delta < threshold;
287 }
288
289//------------------------------------------------------------------------------
290
291}
Sends the request to produce a numerical descriptor to a defined socket and receives back the respons...
void setParameters(Object[] params)
Set the parameters attributes.
static final String KEYJSONMEMBERSCORE
The key of the JSON member defining the score/s for the descriptor calculated.
static final String KEYJSONMEMBERSMILES
The key of the JSON member defining the SMILES of the candidate for which the socket server should pr...
static final String KEYJSONMEMBERERR
The key of the JSON member defining an error in the calculation of the score.
Unit test for descriptor SocketProvidedDescriptor.