View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript;
16  
17  import java.util.ArrayList;
18  import java.util.Collections;
19  import java.util.List;
20  
21  import org.htmlunit.CollectingAlertHandler;
22  import org.htmlunit.MockWebConnection;
23  import org.htmlunit.WebClient;
24  import org.htmlunit.WebTestCase;
25  import org.htmlunit.html.HtmlPage;
26  
27  import junit.framework.Test;
28  import junit.framework.TestCase;
29  import junit.framework.TestSuite;
30  
31  /**
32   * Multi-threaded JavaScript engine test.
33   *
34   * @author David D. Kilzer
35   * @author Ahmed Ashour
36   */
37  public class ThreadTest extends TestCase {
38  
39      /**
40       * Creates a new instance.
41       * @param name the name of the test
42       */
43      public ThreadTest(final String name) {
44          super(name);
45      }
46  
47      /**
48       * @throws InterruptedException if the test fails
49       */
50      public void testJavaScriptEngineInMultipleThreads() throws InterruptedException {
51          final TestThread thread1 = new TestThread("thread1");
52          final TestThread thread2 = new TestThread("thread2");
53          final TestThread thread3 = new TestThread("thread3");
54          final TestThread thread4 = new TestThread("thread4");
55  
56          thread1.start();
57          thread2.start();
58          thread3.start();
59          thread4.start();
60  
61          thread1.join();
62          thread2.join();
63          thread3.join();
64          thread4.join();
65  
66          assertTrue("thread1 not successful", thread1.isSuccessful());
67          assertTrue("thread2 not successful", thread2.isSuccessful());
68          assertTrue("thread3 not successful", thread3.isSuccessful());
69          assertTrue("thread4 not successful", thread4.isSuccessful());
70      }
71  
72      /**
73       * Runs this test many times.
74       * @return a suite
75       */
76      public static Test suite() {
77          final TestSuite suite = new TestSuite("Run this many times");
78          suite.addTestSuite(ThreadTest.class);
79          for (int i = 1; i < 100; i++) {
80              suite.addTest(new ThreadTest("testJavaScriptEngineInMultipleThreads"));
81          }
82          return suite;
83      }
84  
85      /** A test object for threads. */
86      private static class TestThread extends Thread {
87  
88          private boolean successful_ = false;
89  
90          /**
91           * Creates an instance.
92           * @param name the name of the thread
93           */
94          TestThread(final String name) {
95              super(name);
96          }
97  
98          /**
99           * @see Thread#run()
100          */
101         @Override
102         public void run() {
103             try {
104                 testCallInheritedFunction();
105                 successful_ = true;
106             }
107             catch (final Exception e) {
108                 System.err.println(">>> Thread " + getName());
109                 e.printStackTrace(System.err);
110                 successful_ = false;
111             }
112         }
113 
114         /**
115          * @return true if the test was successful
116          */
117         public boolean isSuccessful() {
118             return successful_;
119         }
120 
121         /**
122          * @see HtmlUnitScriptableTest#callInheritedFunction()
123          * @throws Exception if the test failed
124          */
125         public void testCallInheritedFunction() throws Exception {
126             final String html =
127                 "<html><head><title>foo</title><script>\n"
128                 + "function doTest() {\n"
129                 + "  document.form1.textfield1.focus();\n"
130                 + "  alert('past focus');\n"
131                 + "}\n"
132                 + "</script></head><body onload='doTest()'>\n"
133                 + "<p>hello world</p>\n"
134                 + "<form name='form1'>\n"
135                 + "  <input type='text' name='textfield1' id='textfield1' value='foo'>\n"
136                 + "</form>\n"
137                 + "</body></html>";
138 
139             final List<String> collectedAlerts = new ArrayList<>();
140 
141             try (WebClient webClient = new WebClient()) {
142                 webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
143                 final MockWebConnection connection = new MockWebConnection();
144                 connection.setDefaultResponse(html);
145                 webClient.setWebConnection(connection);
146 
147                 final HtmlPage page = webClient.getPage(WebTestCase.URL_FIRST);
148 
149                 assertEquals("foo", page.getTitleText());
150                 assertEquals("focus not changed to textfield1",
151                              page.getFormByName("form1").getInputByName("textfield1"),
152                              page.getFocusedElement());
153                 final List<String> expectedAlerts = Collections.singletonList("past focus");
154                 assertEquals(expectedAlerts, collectedAlerts);
155             }
156         }
157     }
158 
159 }