View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jexl3;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  
22  import java.io.BufferedReader;
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.InputStreamReader;
27  import java.io.OutputStream;
28  import java.net.BindException;
29  import java.net.HttpURLConnection;
30  import java.net.InetSocketAddress;
31  import java.net.URL;
32  import java.nio.charset.StandardCharsets;
33  import java.util.concurrent.Executors;
34  import java.util.concurrent.ThreadPoolExecutor;
35  import java.util.function.Function;
36  
37  import org.junit.jupiter.api.Test;
38  
39  import com.sun.net.httpserver.HttpExchange;
40  import com.sun.net.httpserver.HttpServer;
41  
42  /**
43   * Tests for JexlScript
44   */
45  @SuppressWarnings({"AssertEqualsBetweenInconvertibleTypes"})
46  class ScriptTest extends JexlTestCase {
47  
48      /**
49       * An object to call from.
50       */
51      public static class HttpPostRequest {
52          public static String execute(final String url, final String data) throws IOException {
53              return httpPostRequest(url, data);
54          }
55      }
56      // test class for testScriptUpdatesContext
57      // making this class private static will cause the test to fail.
58      // this is due to unusual code in ClassMap.getAccessibleMethods(Class)
59      // that treats non-public classes in a specific way. Why getAccessibleMethods
60      // does this is not known yet.
61      public static class Tester {
62          private String code;
63          public String getCode () {
64              return code;
65          }
66          public void setCode(final String c) {
67              code = c;
68          }
69      }
70      static final String TEST1 =  "src/test/scripts/test1.jexl";
71  
72      static final String TEST_ADD =  "src/test/scripts/testAdd.jexl";
73      static final String TEST_JSON =  "src/test/scripts/httpPost.jexl";
74  
75      /**
76       * Creates a simple local http server.
77       * <p>Only handles POST request on /test</p>
78       * @return The server
79       * @throws IOException
80       */
81      static HttpServer createJsonServer(final Function<HttpExchange, String> responder) throws IOException {
82          HttpServer server  = null;
83          IOException xlatest = null;
84          for(int port = 8001; server == null && port < 8127; ++port) {
85              try {
86                  server = HttpServer.create(new InetSocketAddress("localhost", port), 0);
87              } catch (final BindException xbind) {
88                  xlatest = xbind;
89              }
90          }
91          if (server == null) {
92              throw xlatest;
93          }
94          final ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
95          server.createContext("/test", httpExchange -> {
96              if ("POST".equals(httpExchange.getRequestMethod())) {
97                  try (OutputStream outputStream = httpExchange.getResponseBody()) {
98                      final String json = responder.apply(httpExchange);
99                      httpExchange.sendResponseHeaders(200, json.length());
100                     outputStream.write(json.toString().getBytes());
101                     outputStream.flush();
102                 }
103             } else {
104                 // error
105                 httpExchange.sendResponseHeaders(500, 0);
106             }
107         });
108         server.setExecutor(threadPoolExecutor);
109         server.start();
110         return server;
111     }
112 
113     /**
114      *  HTTP post.
115      * @param sURL The url
116      * @param jsonData some json data
117      * @return The result
118      * @throws IOException
119      */
120     private static String httpPostRequest(final String sURL, final String jsonData) throws IOException {
121         final URL url = new java.net.URL(sURL);
122         final HttpURLConnection con = (HttpURLConnection) url.openConnection();
123         con.setRequestMethod("POST");
124         con.setRequestProperty("Accept", "application/json");
125         // send data
126         if (jsonData != null) {
127             con.setRequestProperty("Content-Type", "application/json");
128             con.setDoOutput(true);
129 
130             final OutputStream outputStream = con.getOutputStream();
131             final byte[] input = jsonData.getBytes(StandardCharsets.UTF_8);
132             outputStream.write(input, 0, input.length);
133         }
134         // read response
135         final int responseCode = con.getResponseCode();
136         InputStream inputStream = null;
137         inputStream = con.getInputStream();
138         final StringBuilder response = new StringBuilder();
139         if (inputStream != null) {
140             try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) {
141                 String inputLine = "";
142                 while ((inputLine = in.readLine()) != null) {
143                     response.append(inputLine);
144                 }
145             }
146         }
147         return response.toString();
148     }
149 
150     /**
151      * Create a new test case.
152      */
153     public ScriptTest() {
154         super("ScriptTest");
155     }
156 
157     @Test
158     void testArgScriptFromFile() {
159         final File testScript = new File(TEST_ADD);
160         final JexlScript s = JEXL.createScript(testScript,"x", "y");
161         final JexlContext jc = new MapContext();
162         jc.set("out", System.out);
163         final Object result = s.execute(jc, 13, 29);
164         assertNotNull(result, "No result");
165         assertEquals(42, result, "Wrong result");
166     }
167 
168     @Test
169     void testArgScriptFromURL() throws Exception {
170         final URL testUrl = new File(TEST_ADD).toURI().toURL();
171         final JexlScript s = JEXL.createScript(testUrl,"x", "y");
172         final JexlContext jc = new MapContext();
173         jc.set("out", System.out);
174         final Object result = s.execute(jc, 13, 29);
175         assertNotNull(result, "No result");
176         assertEquals(42, result, "Wrong result");
177     }
178 
179     @Test
180     void testScriptFromFile() {
181         final File testScript = new File(TEST1);
182         final JexlScript s = JEXL.createScript(testScript);
183         final JexlContext jc = new MapContext();
184         jc.set("out", System.out);
185         final Object result = s.execute(jc);
186         assertNotNull(result, "No result");
187         assertEquals(7, result, "Wrong result");
188     }
189 
190     @Test
191     void testScriptFromURL() throws Exception {
192         final URL testUrl = new File(TEST1).toURI().toURL();
193         final JexlScript s = JEXL.createScript(testUrl);
194         final JexlContext jc = new MapContext();
195         jc.set("out", System.out);
196         final Object result = s.execute(jc);
197         assertNotNull(result, "No result");
198         assertEquals(7, result, "Wrong result");
199     }
200 
201     @Test
202     void testScriptJsonFromFileJava() throws IOException {
203         HttpServer server = null;
204         try {
205             final String response = "{  \"id\": 101}";
206             server = createJsonServer(h -> response);
207             final String url = "http:/" + server.getAddress().toString() + "/test";
208             final String testScript = "httpr.execute('" + url + "', null)";
209             final JexlScript s = JEXL.createScript(testScript);
210             final JexlContext jc = new MapContext();
211             jc.set("httpr", new HttpPostRequest());
212             final Object result = s.execute(jc);
213             assertNotNull(result);
214             assertEquals(response, result);
215         } finally {
216             if (server != null) {
217                 server.stop(0);
218             }
219         }
220     }
221 
222     @Test
223     void testScriptJsonFromFileJexl() throws IOException {
224         HttpServer server = null;
225         try {
226             final String response = "{  \"id\": 101}";
227             server = createJsonServer(h -> response);
228             final File httprFile = new File(TEST_JSON);
229             final JexlScript httprScript = JEXL.createScript(httprFile);
230             final JexlContext jc = new MapContext();
231             final Object httpr = httprScript.execute(jc);
232             final JexlScript s = JEXL.createScript("(httpr,url)->httpr.execute(url, null)");
233             // jc.set("httpr", new HttpPostRequest());
234             final String url = "http:/" + server.getAddress().toString() + "/test";
235             final Object result = s.execute(jc, httpr, url);
236             assertNotNull(result);
237             assertEquals(response, result);
238         } finally {
239             if (server != null) {
240                 server.stop(0);
241             }
242         }
243     }
244 
245     @Test
246     void testScriptUpdatesContext() {
247         final String jexlCode = "resultat.setCode('OK')";
248         final JexlExpression e = JEXL.createExpression(jexlCode);
249         final JexlScript s = JEXL.createScript(jexlCode);
250 
251         final Tester resultatJexl = new Tester();
252         final JexlContext jc = new MapContext();
253         jc.set("resultat", resultatJexl);
254 
255         resultatJexl.setCode("");
256         e.evaluate(jc);
257         assertEquals("OK", resultatJexl.getCode());
258         resultatJexl.setCode("");
259         s.execute(jc);
260         assertEquals("OK", resultatJexl.getCode());
261     }
262 
263     /**
264      * Test creating a script from a string.
265      */
266     @Test
267     void testSimpleScript() {
268         final String code = "while (x < 10) x = x + 1;";
269         final JexlScript s = JEXL.createScript(code);
270         final JexlContext jc = new MapContext();
271         jc.set("x",1);
272 
273         final Object o = s.execute(jc);
274         assertEquals(10, o, "Result is wrong");
275         assertEquals(code, s.getSourceText(), "getText is wrong");
276     }
277 
278     /**
279      * Test creating a script from spaces.
280      */
281     @Test
282     void testSpacesScript() {
283         final String code = " ";
284         final JexlScript s = JEXL.createScript(code);
285         assertNotNull(s);
286     }
287 
288 }