$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 public String fakeErrorMsg = "#SocketServer: fake error.";
58
59 private static final String HOSTNAME = "localhost";
60
61
62//------------------------------------------------------------------------------
63
64 @BeforeEach
65 public void setUpServer() throws Exception
66 {
67 // We create a socket server the SocketProvidedDescriptor can talk to.
68 server = new MySocketServer();
70 int port = server.getPort();
71
72 jsonConverted = new GsonBuilder().create();
73
74 Constructor<SocketProvidedDescriptor> defaultConstructor =
75 SocketProvidedDescriptor.class.getConstructor();
76 this.descriptor = defaultConstructor.newInstance();
77 this.descriptor.setParameters(new Object[] {HOSTNAME, port});
78 }
79
80//------------------------------------------------------------------------------
81
82 @AfterEach
83 public void closeServer() throws Exception
84 {
86 }
87
88//------------------------------------------------------------------------------
89
90 /*
91 * The dummy server we create and try to communicate with.
92 */
93 private class MySocketServer extends Thread
94 {
95 private ServerSocket server;
96
97 public void startServer()
98 {
99 try
100 {
101 server = new ServerSocket(0);
102
103 Runtime.getRuntime().addShutdownHook(new Thread(){
104 public void run()
105 {
106 try {
107 server.close();
108 } catch (IOException e) { /* failed */ }
109 }
110 });
111 this.start();
112 }
113 catch (IOException e)
114 {
115 e.printStackTrace();
116 }
117 }
118
119 public int getPort()
120 {
121 return server.getLocalPort();
122 }
123
124 public void stopServer()
125 {
126 try
127 {
128 server.close();
129 } catch (IOException e)
130 {
131 e.printStackTrace();
132 }
133 this.interrupt();
134 }
135
136 @Override
137 public void run()
138 {
139 while(!server.isClosed())
140 {
141 try
142 {
143 RequestHandler handler = new RequestHandler(
144 server.accept());
145 handler.start();
146 }
147 catch (IOException e)
148 {
149 // There is some lag between the closing of the server and
150 // the notification it is closed, se we end up here when
151 // the unit test if finishing and we are closing up the
152 // socket.
153 //e.printStackTrace();
154 }
155 }
156 }
157 }
158
159 /*
160 * Thread handling any requests on the server side.
161 */
162 class RequestHandler extends Thread
163 {
164 private Socket socket;
166 {
167 this.socket = socket;
168 }
169
170 @Override
171 public void run()
172 {
173 try
174 {
175 BufferedReader in = new BufferedReader(new InputStreamReader(
176 socket.getInputStream()));
177
178 // Read request
179 StringBuilder sb = new StringBuilder();
180 String line = in.readLine();
181 while(line != null && line.length()>0)
182 {
183 sb.append(line).append(System.getProperty("line.separator"));
184 line = in.readLine();
185 }
186
187 //
188 // WARNING: this is where the format of the request is evaluated.
189 // Any change to the format convention should be reflected here.
190 //
191
192 // Evaluate request format
193 String jsonStr = sb.toString();
194 JsonObject request = null;
195 try {
196 request = jsonConverted.fromJson(jsonStr, JsonObject.class);
197 } catch (JsonSyntaxException e) {
198 e.printStackTrace();
199 assertFalse(true,"JsonSyntaxException unpon converting "
200 + "requst to socket server");
201 }
203 assertTrue(request.has(smiKey), "JSON request has no " + smiKey);
204
205 //
206 // WARNING: this assumes consistency between this class and the
207 // unit test method.
208 //
209
210 // Prepare an answer that differs based on the request
211 String smiles = request.get(smiKey).getAsString();
212 long count = smiles.chars().filter(c -> c == 'c').count();
213 double score = Math.pow((double) count,2.5);
214
215 JsonObject jsonAnswer = new JsonObject();
216 if (score>0.1)
217 {
218 jsonAnswer.addProperty(
220 } else {
221 jsonAnswer.addProperty(
224 }
225
226 // Send response
227 PrintWriter out = new PrintWriter(socket.getOutputStream());
228 out.println(jsonConverted.toJson(jsonAnswer));
229 out.flush();
230
231 // Do not close our connection: we'll be reusing it
232 //in.close();
233 //out.close();
234 }
235 catch (Exception e)
236 {
237 e.printStackTrace();
238 }
239 }
240 }
241
242//------------------------------------------------------------------------------
243
244 @Test
245 public void testSocketProvidedDescriptor() throws Exception
246 {
247 SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance());
248
249 String smiles = "O";
250 IAtomContainer mol1 = sp.parseSmiles(smiles);
251 mol1.setProperty("SMILES", smiles);
252 double value = ((DoubleResult) descriptor.calculate(mol1).getValue())
253 .doubleValue();
254 double expected = Double.NaN;
255 assertTrue(Double.isNaN(value), "Wrong socket-provided "
256 + "descriptor: expected " + expected + ", found "+ value + "(0)");
257
258 mol1.setProperty("SMILES", "c");
259 value = ((DoubleResult) descriptor.calculate(mol1).getValue())
260 .doubleValue();
261 expected = 1.0;
262 assertTrue(closeEnough(expected, value), "Wrong socket-provided "
263 + "descriptor: expected " + expected + ", found "+ value + "(1)");
264
265 mol1.setProperty("SMILES", "ccc");
266 value = ((DoubleResult) descriptor.calculate(mol1).getValue())
267 .doubleValue();
268 expected = 15.5884;
269 assertTrue(closeEnough(expected, value), "Wrong socket-provided "
270 + "descriptor: expected " + expected + ", found "+ value + "(2)");
271
272 smiles = "COc1ccccc1";
273 mol1 = sp.parseSmiles(smiles);
274 mol1.setProperty("SMILES", smiles);
275 value = ((DoubleResult) descriptor.calculate(mol1).getValue())
276 .doubleValue();
277 expected = 88.1816;
278 assertTrue(closeEnough(expected, value), "Wrong socket-provided "
279 + "descriptor: expected " + expected + ", found "+ value + "(3)");
280 }
281
282//------------------------------------------------------------------------------
283
284 private boolean closeEnough(double expected, double actual)
285 {
286 double threshold = 0.01;
287 double delta = Math.abs(expected-actual);
288 return delta < threshold;
289 }
290
291//------------------------------------------------------------------------------
292
293}
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.