Skip to content

Commit 5e96d5c

Browse files
authored
Merge pull request #44 from AutomateThePlanet/fixes-and-refactoring
Automatic Browser Shutdown Update
2 parents 06e638d + 876f283 commit 5e96d5c

File tree

13 files changed

+824
-791
lines changed

13 files changed

+824
-791
lines changed

bellatrix.core/src/main/java/solutions/bellatrix/core/plugins/junit/BaseTest.java

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,10 @@
3131
public class BaseTest extends UsesPlugins {
3232
static final ThreadLocal<TestResult> CURRENT_TEST_RESULT = new ThreadLocal<>();
3333
static final ThreadLocal<TimeRecord> CURRENT_TEST_TIME_RECORD = ThreadLocal.withInitial(TimeRecord::new);
34-
private static final ThreadLocal<Boolean> CONFIGURATION_EXECUTED = new ThreadLocal<>();
34+
private static final ThreadLocal<Boolean> CONFIGURATION_EXECUTED = ThreadLocal.withInitial(() -> false);
3535
private static final List<String> ALREADY_EXECUTED_BEFORE_CLASSES = Collections.synchronizedList(new ArrayList<>());
3636
private TestInfo testInfo;
3737

38-
public BaseTest() {
39-
// try {
40-
// Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
41-
// theUnsafe.setAccessible(true);
42-
// Unsafe u = (Unsafe)theUnsafe.get(null);
43-
//
44-
// Class<?> cls = Class.forName("jdk.internal.module.IllegalAccessLogger");
45-
// Field logger = cls.getDeclaredField("logger");
46-
// u.putObjectVolatile(cls, u.staticFieldOffset(logger), null);
47-
// } catch (Exception ignored) {}
48-
CONFIGURATION_EXECUTED.set(false);
49-
}
50-
5138
@BeforeEach
5239
public void beforeMethodCore(TestInfo testInfo) throws Exception {
5340
try {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2024 Automate The Planet Ltd.
3+
* Author: Miriam Kyoseva
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 http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
package solutions.bellatrix.core.utilities;
15+
16+
import lombok.experimental.UtilityClass;
17+
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
import java.util.concurrent.CopyOnWriteArrayList;
21+
import java.util.concurrent.ExecutorService;
22+
import java.util.concurrent.Executors;
23+
import java.util.concurrent.TimeUnit;
24+
25+
@UtilityClass
26+
public class ShutdownManager {
27+
private static final List<Runnable> instructions = new CopyOnWriteArrayList<>();
28+
private static final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
29+
30+
static {
31+
Runtime.getRuntime().addShutdownHook(new Thread(ShutdownManager::runAllInstructions));
32+
}
33+
34+
public static void register(Runnable runnable) {
35+
instructions.add(runnable);
36+
}
37+
38+
private static void runAllInstructions() {
39+
if (instructions.isEmpty()) return;
40+
41+
try {
42+
// Submit all instructions for parallel execution
43+
for (var instruction : instructions) {
44+
executor.submit(() -> {
45+
try {
46+
instruction.run();
47+
} catch (Exception ex) {
48+
DebugInformation.debugInfo(ex.getMessage());
49+
}
50+
});
51+
}
52+
} finally {
53+
shutdownAndAwaitTermination(executor);
54+
}
55+
}
56+
57+
private static void shutdownAndAwaitTermination(ExecutorService executor) {
58+
executor.shutdown(); // Disable new tasks from being submitted
59+
try {
60+
// Wait a while for existing tasks to terminate
61+
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
62+
executor.shutdownNow(); // Cancel currently executing tasks
63+
// Wait a while for tasks to respond to being cancelled
64+
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
65+
System.err.println("Executor did not terminate.");
66+
}
67+
}
68+
} catch (InterruptedException ie) {
69+
// (Re-)Cancel if current thread also interrupted
70+
executor.shutdownNow();
71+
// Preserve interrupt status
72+
Thread.currentThread().interrupt();
73+
}
74+
}
75+
}

bellatrix.core/src/main/java/solutions/bellatrix/core/utilities/SingletonFactory.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ public static <T> void register(Class<?> classKey, T instance) {
5555
mapHolder.get().put(classKey, instance);
5656
}
5757

58+
public static boolean containsKey(Class<?> classOf) {
59+
return mapHolder.get().containsKey(classOf);
60+
}
61+
62+
public static boolean containsValue(Object object) {
63+
return mapHolder.get().containsValue(object);
64+
}
65+
5866
public static void clear() {
5967
mapHolder.get().clear();
6068
}

bellatrix.playwright/src/main/java/solutions/bellatrix/playwright/components/shadowdom/ShadowDomService.java

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -106,25 +106,8 @@ private static String[] getAbsoluteCss(ShadowRoot shadowRoot, String locator) {
106106
.evaluate(String.format("(el, [locator]) => (%s)(el, locator)", javaScript), new Object[] { locator }))
107107
.toArray(String[]::new);
108108
};
109-
if (Wait.retry(() -> {
110-
String[] foundElements;
111-
try {
112-
foundElements = js.call();
113-
} catch (Exception e) {
114-
throw new RuntimeException(e);
115-
}
116-
if (foundElements == null || foundElements.length == 0) {
117-
throw new IllegalArgumentException();
118-
}
119-
}, Duration.ofSeconds(ConfigurationService.get(WebSettings.class).getTimeoutSettings().getElementWaitTimeout()), Duration.ofSeconds(1), false)) {
120-
try {
121-
return js.call();
122-
} catch (Exception e) {
123-
throw new RuntimeException(e);
124-
}
125-
} else {
126-
throw new IllegalArgumentException("No elements inside the shadow DOM were found with the locator: " + locator);
127-
}
109+
110+
return getCss(js, locator);
128111
}
129112

130113
private static String[] getRelativeCss(ShadowRoot shadowRoot, String locator, String parentLocator) {
@@ -134,10 +117,14 @@ private static String[] getRelativeCss(ShadowRoot shadowRoot, String locator, St
134117
.toArray(String[]::new);
135118
};
136119

120+
return getCss(js, locator);
121+
}
122+
123+
private static String[] getCss(Callable<String[]> callable, String locator) {
137124
if(Wait.retry(() -> {
138125
String[] foundElements;
139126
try {
140-
foundElements = js.call();
127+
foundElements = callable.call();
141128
} catch (Exception e) {
142129
throw new RuntimeException(e);
143130
}
@@ -146,15 +133,14 @@ private static String[] getRelativeCss(ShadowRoot shadowRoot, String locator, St
146133
}
147134
}, Duration.ofSeconds(ConfigurationService.get(WebSettings.class).getTimeoutSettings().getElementWaitTimeout()), Duration.ofSeconds(1), false)) {
148135
try {
149-
return js.call();
136+
return callable.call();
150137
} catch (Exception e) {
151138
throw new RuntimeException(e);
152139
}
153140
} else {
154141
throw new IllegalArgumentException("No elements inside the shadow DOM were found with the locator: " + locator);
155142
}
156143
}
157-
158144
private static <TComponent extends WebComponent> TComponent buildMissingShadowRootsAndCreate(Class<TComponent> clazz, ShadowRoot parentComponent, Ref<String> fullCss) {
159145
var component = InstanceFactory.create(clazz);
160146

0 commit comments

Comments
 (0)