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       * An object to call from.
49       */
50      public static class HttpPostRequest {
51          public static String execute(final String url, final String data) throws IOException {
52              return httpPostRequest(url, data);
53          }
54      }
55      // test class for testScriptUpdatesContext
56      // making this class private static will cause the test to fail.
57      // this is due to unusual code in ClassMap.getAccessibleMethods(Class)
58      // that treats non-public classes in a specific way. Why getAccessibleMethods
59      // does this is not known yet.
60      public static class Tester {
61          private String code;
62          public String getCode () {
63              return code;
64          }
65          public void setCode(final String c) {
66              code = c;
67          }
68      }
69      static final String TEST1 =  "src/test/scripts/test1.jexl";
70  
71      static final String TEST_ADD =  "src/test/scripts/testAdd.jexl";
72      static final String TEST_JSON =  "src/test/scripts/httpPost.jexl";
73  
74      /**
75       * Creates a simple local http server.
76       * <p>Only handles POST request on /test</p>
77       * @return the server
78       * @throws IOException
79       */
80      static HttpServer createJsonServer(final Function<HttpExchange, String> responder) throws IOException {
81          HttpServer server  = null;
82          IOException xlatest = null;
83          for(int port = 8001; server == null && port < 8127; ++port) {
84              try {
85                  server = HttpServer.create(new InetSocketAddress("localhost", port), 0);
86              } catch (final BindException xbind) {
87                  xlatest = xbind;
88              }
89          }
90          if (server == null) {
91              throw xlatest;
92          }
93          final ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
94          server.createContext("/test", httpExchange -> {
95              if ("POST".equals(httpExchange.getRequestMethod())) {
96                  try (OutputStream outputStream = httpExchange.getResponseBody()) {
97                      final String json = responder.apply(httpExchange);
98                      httpExchange.sendResponseHeaders(200, json.length());
99                      outputStream.write(json.toString().getBytes());
100                     outputStream.flush();
101                 }
102             } else {
103                 // error
104                 httpExchange.sendResponseHeaders(500, 0);
105             }
106         });
107         server.setExecutor(threadPoolExecutor);
108         server.start();
109         return server;
110     }
111 
112     /**
113      *  HTTP post.
114      * @param sURL the url
115      * @param jsonData some json data
116      * @return the result
117      * @throws IOException
118      */
119     private static String httpPostRequest(final String sURL, final String jsonData) throws IOException {
120         final URL url = new java.net.URL(sURL);
121         final HttpURLConnection con = (HttpURLConnection) url.openConnection();
122         con.setRequestMethod("POST");
123         con.setRequestProperty("Accept", "application/json");
124         // send data
125         if (jsonData != null) {
126             con.setRequestProperty("Content-Type", "application/json");
127             con.setDoOutput(true);
128 
129             final OutputStream outputStream = con.getOutputStream();
130             final byte[] input = jsonData.getBytes(StandardCharsets.UTF_8);
131             outputStream.write(input, 0, input.length);
132         }
133         // read response
134         final int responseCode = con.getResponseCode();
135         InputStream inputStream = null;
136         inputStream = con.getInputStream();
137         final StringBuilder response = new StringBuilder();
138         if (inputStream != null) {
139             try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) {
140                 String inputLine = "";
141                 while ((inputLine = in.readLine()) != null) {
142                     response.append(inputLine);
143                 }
144             }
145         }
146         return response.toString();
147     }
148 
149     /**
150      * Create a new test case.
151      */
152     public ScriptTest() {
153         super("ScriptTest");
154     }
155 
156     @Test
157     void testArgScriptFromFile() {
158         final File testScript = new File(TEST_ADD);
159         final JexlScript s = JEXL.createScript(testScript,"x", "y");
160         final JexlContext jc = new MapContext();
161         jc.set("out", System.out);
162         final Object result = s.execute(jc, 13, 29);
163         assertNotNull(result, "No result");
164         assertEquals(42, result, "Wrong result");
165     }
166 
167     @Test
168     void testArgScriptFromURL() throws Exception {
169         final URL testUrl = new File(TEST_ADD).toURI().toURL();
170         final JexlScript s = JEXL.createScript(testUrl,"x", "y");
171         final JexlContext jc = new MapContext();
172         jc.set("out", System.out);
173         final Object result = s.execute(jc, 13, 29);
174         assertNotNull(result, "No result");
175         assertEquals(42, result, "Wrong result");
176     }
177 
178     @Test
179     void testScriptFromFile() {
180         final File testScript = new File(TEST1);
181         final JexlScript s = JEXL.createScript(testScript);
182         final JexlContext jc = new MapContext();
183         jc.set("out", System.out);
184         final Object result = s.execute(jc);
185         assertNotNull(result, "No result");
186         assertEquals(7, result, "Wrong result");
187     }
188 
189     @Test
190     void testScriptFromURL() throws Exception {
191         final URL testUrl = new File(TEST1).toURI().toURL();
192         final JexlScript s = JEXL.createScript(testUrl);
193         final JexlContext jc = new MapContext();
194         jc.set("out", System.out);
195         final Object result = s.execute(jc);
196         assertNotNull(result, "No result");
197         assertEquals(7, result, "Wrong result");
198     }
199 
200     @Test
201     void testScriptJsonFromFileJava() throws IOException {
202         HttpServer server = null;
203         try {
204             final String response = "{  \"id\": 101}";
205             server = createJsonServer(h -> response);
206             final String url = "http:/" + server.getAddress().toString() + "/test";
207             final String testScript = "httpr.execute('" + url + "', null)";
208             final JexlScript s = JEXL.createScript(testScript);
209             final JexlContext jc = new MapContext();
210             jc.set("httpr", new HttpPostRequest());
211             final Object result = s.execute(jc);
212             assertNotNull(result);
213             assertEquals(response, result);
214         } finally {
215             if (server != null) {
216                 server.stop(0);
217             }
218         }
219     }
220 
221     @Test
222     void testScriptJsonFromFileJexl() throws IOException {
223         HttpServer server = null;
224         try {
225             final String response = "{  \"id\": 101}";
226             server = createJsonServer(h -> response);
227             final File httprFile = new File(TEST_JSON);
228             final JexlScript httprScript = JEXL.createScript(httprFile);
229             final JexlContext jc = new MapContext();
230             final Object httpr = httprScript.execute(jc);
231             final JexlScript s = JEXL.createScript("(httpr,url)->httpr.execute(url, null)");
232             // jc.set("httpr", new HttpPostRequest());
233             final String url = "http:/" + server.getAddress().toString() + "/test";
234             final Object result = s.execute(jc, httpr, url);
235             assertNotNull(result);
236             assertEquals(response, result);
237         } finally {
238             if (server != null) {
239                 server.stop(0);
240             }
241         }
242     }
243 
244     @Test
245     void testScriptUpdatesContext() {
246         final String jexlCode = "resultat.setCode('OK')";
247         final JexlExpression e = JEXL.createExpression(jexlCode);
248         final JexlScript s = JEXL.createScript(jexlCode);
249 
250         final Tester resultatJexl = new Tester();
251         final JexlContext jc = new MapContext();
252         jc.set("resultat", resultatJexl);
253 
254         resultatJexl.setCode("");
255         e.evaluate(jc);
256         assertEquals("OK", resultatJexl.getCode());
257         resultatJexl.setCode("");
258         s.execute(jc);
259         assertEquals("OK", resultatJexl.getCode());
260     }
261 
262     /**
263      * Test creating a script from a string.
264      */
265     @Test
266     void testSimpleScript() {
267         final String code = "while (x < 10) x = x + 1;";
268         final JexlScript s = JEXL.createScript(code);
269         final JexlContext jc = new MapContext();
270         jc.set("x",1);
271 
272         final Object o = s.execute(jc);
273         assertEquals(10, o, "Result is wrong");
274         assertEquals(code, s.getSourceText(), "getText is wrong");
275     }
276 
277     /**
278      * Test creating a script from spaces.
279      */
280     @Test
281     void testSpacesScript() {
282         final String code = " ";
283         final JexlScript s = JEXL.createScript(code);
284         assertNotNull(s);
285     }
286 
287 }