Skip to content

Commit 1c4645a

Browse files
sampesonsoisetupsaikkonen
authored
0.6.0 changes from development (#50)
* Experimental java agent support JavaFXLibrary can now be attached to process as java agent. * Fix docker-compose up Building the docker demo failed because of missing package versions for the newer Ubuntu image. Base image of the demo is now fixed to bionic tag since Ubuntu updates have broken the build earlier as well. Related Launchpad ticket: https://bugs.launchpad.net/ubuntu/+source/openjfx/+bug/1799946 * Updated documentation (java agent) * Add possibility to configure different directory for log.html in Set Screenshotdir, fixes #17 * java agent documentation fix * Set Classpath failure as warnings and add failIfNotFound argument * Use asyncFx for helperfunctions methods, remove waitForFxEvents usage, failure printout improvements * remove deprecated keywords and methods (enhancement #11) Co-authored-by: Turo Soisenniemi <[email protected]> Co-authored-by: Pasi Saikkonen <[email protected]>
1 parent 356b688 commit 1c4645a

File tree

20 files changed

+279
-539
lines changed

20 files changed

+279
-539
lines changed

AUTHORS.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ Tatu Lahtela Find All With Pseudo Class and Find Class keywords
88
Sakari Hoisko Dockerized linux env with X
99
Juho Lehtonen Optimized docker environment.
1010
Juho Saarinen Package improvements, initial monocle support, screenshot bug fix
11-
11+
Turo Soisenniemi Initial java agent support

Dockerfile_build

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ RUN mvn package
1414
# ENTRYPOINT java -jar /code/target/javafxlibrary-*-SNAPSHOT-jar-with-dependencies.jar
1515

1616
FROM ubuntu:16.04
17-
COPY --from=builder /code/target/javafxlibrary-*-jar-with-dependencies.jar /.
18-
COPY --from=builder /code/target/javafxlibrary-*-tests.jar /.
17+
COPY --from=builder /code/target/javafxlibrary-*-jar-with-dependencies.jar /
18+
COPY --from=builder /code/target/javafxlibrary-*-tests.jar /
1919
RUN echo "Built following jar files" && ls -latr /*.jar
2020
COPY entrypoint_build.sh /.
2121
RUN apt-get -qq update && apt-get dist-upgrade -y && apt-get install -qq --no-install-recommends --allow-unauthenticated -y \

README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Executing _test.sh_ runs the acceptance suite twice: first using JavaFXLibrary a
7575
If you want the suite to run only once, you can define which type of library to use by including **local** or **remote** as an argument. For example command `test.sh remote` will execute the suite only in remote mode.
7676

7777
## Experimental: Headless support
78-
Library supports headless operation utilizing [Monocle](https://wiki.openjdk.java.net/display/OpenJFX/Monocle). The support for this is still at experimental level.
78+
Library supports headless operation utilizing [Monocle](https://wiki.openjdk.java.net/display/OpenJFX/Monocle). The support for this is still at experimental level.
7979

8080
### Main issues with headless function
8181
* Scrolling doesn't work same way as with screen
@@ -97,4 +97,7 @@ Remote:
9797
```
9898
*** Settings ***
9999
Library Remote http://127.0.0.1:8270 ${True} WITH NAME JavaFXLibrary
100-
```
100+
```
101+
102+
## Experimental: Java agent support
103+
Library can be used as java agent. Launch application with `-javaagent:/path/to/javafxlibrary-<version>.jar`. Default port is 8270 and can be changed with adding `=<port>` to java agent command. Only remote library is supported. Using launch keyword is still required but instead of starting new application keyword initializes Stage for library.

docker/robot-javafx-demo/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM dorowu/ubuntu-desktop-lxde-vnc
1+
FROM dorowu/ubuntu-desktop-lxde-vnc:bionic
22

33
ENV DEBIAN_FRONTEND noninteractive
44

pom.xml

+3
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@
221221
<addClasspath>true</addClasspath>
222222
<mainClass>JavaFXLibrary</mainClass>
223223
</manifest>
224+
<manifestEntries>
225+
<Premain-Class>JavaFXLibrary</Premain-Class>
226+
</manifestEntries>
224227
</archive>
225228
</configuration>
226229
<executions>

src/main/java/JavaFXLibrary.java

+38-20
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ public class JavaFXLibrary extends AnnotationLibrary {
5656
add("javafxlibrary/keywords/Keywords/*.class");
5757
add("javafxlibrary/keywords/*.class");
5858
add("javafxlibrary/tests/*.class");
59-
}};
59+
}};
6060

6161
public JavaFXLibrary() {
62-
this(false);
62+
this(false);
6363
}
64-
64+
6565
public JavaFXLibrary(boolean headless) {
6666
super(includePatterns);
6767
if (headless) {
@@ -71,9 +71,9 @@ public JavaFXLibrary(boolean headless) {
7171
System.setProperty("prism.text", "t2k");
7272
TestFxAdapter.isHeadless = true;
7373
} else {
74-
//v4.0.15-alpha sets default robot as glass, which breaks rolling
75-
//Forcing usage of awt robot as previous versions
76-
System.setProperty("testfx.robot", "awt");
74+
// v4.0.15-alpha sets default robot as glass, which breaks rolling
75+
// Forcing usage of awt robot as previous versions
76+
System.setProperty("testfx.robot", "awt");
7777
}
7878
}
7979

@@ -108,7 +108,6 @@ public Object runKeyword(String keywordName, List args, Map kwargs) {
108108
finalKwargs = kwargs;
109109
}
110110

111-
112111
AtomicReference<Object> retval = new AtomicReference<>();
113112
AtomicReference<RuntimeException> retExcep = new AtomicReference<>();
114113

@@ -121,12 +120,12 @@ public Object runKeyword(String keywordName, List args, Map kwargs) {
121120
retval.set(super.runKeyword(keywordName, finalArgs, finalKwargs));
122121
return true;
123122

124-
} catch (JavaFXLibraryTimeoutException jfxte){
123+
} catch (JavaFXLibraryTimeoutException jfxte) {
125124
// timeout already expired, catch exception and jump out
126125
retExcep.set(jfxte);
127126
throw jfxte;
128127

129-
} catch (RuntimeException e){
128+
} catch (RuntimeException e) {
130129
// catch exception and continue trying
131130
retExcep.set(e);
132131
return false;
@@ -165,10 +164,11 @@ public Object runKeyword(String keywordName, List args) {
165164

166165
List finalArgs;
167166
// JavalibCore changes arguments of Call Method keywords to Strings after this check, so they need to handle their own objectMapping
168-
if (!(keywordName.equals("callObjectMethod") || keywordName.equals("callObjectMethodInFxApplicationThread")))
167+
if (!(keywordName.equals("callObjectMethod") || keywordName.equals("callObjectMethodInFxApplicationThread"))) {
169168
finalArgs = HelperFunctions.useMappedObjects(args);
170-
else
169+
} else {
171170
finalArgs = args;
171+
}
172172

173173
AtomicReference<Object> retval = new AtomicReference<>();
174174
AtomicReference<RuntimeException> retExcep = new AtomicReference<>();
@@ -182,12 +182,12 @@ public Object runKeyword(String keywordName, List args) {
182182
retval.set(super.runKeyword(keywordName, finalArgs));
183183
return true;
184184

185-
} catch (JavaFXLibraryTimeoutException jfxte){
185+
} catch (JavaFXLibraryTimeoutException jfxte) {
186186
// timeout already expired, catch exception and jump out
187187
retExcep.set(jfxte);
188188
throw jfxte;
189189

190-
} catch (RuntimeException e){
190+
} catch (RuntimeException e) {
191191
// catch exception and continue trying
192192
retExcep.set(e);
193193
return false;
@@ -227,17 +227,16 @@ public String getKeywordDocumentation(String keywordName) {
227227
return "IOException occurred while reading the documentation file!";
228228
}
229229
} else if (keywordName.equals("__init__")) {
230-
try {
230+
try {
231231
return FileUtils.readFileToString(new File("./src/main/java/libdoc-init-documentation.txt"), "utf-8");
232232
} catch (IOException e) {
233233
e.printStackTrace();
234234
return "IOException occurred while reading the init documentation file!";
235235
}
236236
} else {
237-
try {
237+
try {
238238
return super.getKeywordDocumentation(keywordName);
239-
}
240-
catch (Exception e) {
239+
} catch (Exception e) {
241240
return keywordName;
242241
}
243242
}
@@ -258,6 +257,27 @@ public static JavaFXLibrary getLibraryInstance() throws ScriptException {
258257
}
259258

260259
public static void main(String[] args) throws Exception {
260+
startServer(args);
261+
}
262+
263+
public static void premain(String args) {
264+
TestFxAdapter.isAgent = true;
265+
Thread agentThread = new Thread(() -> {
266+
try {
267+
if (args == null) {
268+
startServer();
269+
} else {
270+
startServer(args);
271+
}
272+
} catch (Exception e) {
273+
e.printStackTrace();
274+
}
275+
});
276+
agentThread.setDaemon(true);
277+
agentThread.start();
278+
}
279+
280+
public static void startServer(String... args) throws Exception {
261281
int port = 8270;
262282
InetAddress ipAddr = InetAddress.getLocalHost();
263283

@@ -266,8 +286,7 @@ public static void main(String[] args) throws Exception {
266286
System.out.println("----------------------------= JavaFXLibrary =-----------------------------");
267287
if (args.length > 0) {
268288
port = Integer.parseInt(args[0]);
269-
}
270-
else {
289+
} else {
271290
System.out.println("RemoteServer for JavaFXLibrary will be started at default port of: " + port + ".\n" +
272291
"If you wish to use another port, restart the library and give port number\n" +
273292
"as an argument.");
@@ -294,4 +313,3 @@ public static void main(String[] args) throws Exception {
294313
}
295314
}
296315
}
297-

src/main/java/javafxlibrary/keywords/AdditionalKeywords/ApplicationLauncher.java

+54-44
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ public class ApplicationLauncher extends TestFxAdapter {
4545
+ "Example:\n"
4646
+ "| Launch JavaFX Application | _javafxlibrary.testapps.MenuApp_ |\n"
4747
+ "| Launch JavaFX Application | _TestApplication.jar_ |\n")
48-
@ArgumentNames({"appName", "*args"})
49-
public void launchJavafxApplication(String appName, String... appArgs) {
48+
@ArgumentNames({ "appName", "*args" })
49+
public void launchJavafxApplication(String appName, String... appArgs) {
5050
try {
5151
RobotLog.info("Starting application:" + appName);
5252
createNewSession(appName, appArgs);
@@ -65,7 +65,7 @@ public void launchJavafxApplication(String appName, String... appArgs) {
6565
+ "Example:\n"
6666
+ "| Launch Swing Application | _javafxlibrary.testapps.SwingApplication |\n"
6767
+ "| Launch Swing Application | _TestApplication.jar_ |\n")
68-
@ArgumentNames({"appName", "*args"})
68+
@ArgumentNames({ "appName", "*args" })
6969
public void launchSwingApplication(String appName, String... appArgs) {
7070
RobotLog.info("Starting application:" + appName);
7171
Class c = getMainClass(appName);
@@ -84,7 +84,7 @@ public void launchSwingApplication(String appName, String... appArgs) {
8484
+ "Example:\n"
8585
+ "| Launch Swing Application In Separate Thread | _javafxlibrary.testapps.SwingApplication |\n"
8686
+ "| Launch Swing Application In Separate Thread | _TestApplication.jar_ |\n")
87-
@ArgumentNames({"appName", "*args"})
87+
@ArgumentNames({ "appName", "*args" })
8888
public void launchSwingApplicationInSeparateThread(String appName, String... appArgs) {
8989
RobotLog.info("Starting application:" + appName);
9090
Class c = getMainClass(appName);
@@ -95,10 +95,11 @@ public void launchSwingApplicationInSeparateThread(String appName, String... app
9595

9696
private Class getMainClass(String appName) {
9797
try {
98-
if (appName.endsWith(".jar"))
98+
if (appName.endsWith(".jar")) {
9999
return getMainClassFromJarFile(appName);
100-
else
100+
} else {
101101
return Class.forName(appName);
102+
}
102103
} catch (ClassNotFoundException e) {
103104
throw new JavaFXLibraryNonFatalException("Unable to launch application: " + appName, e);
104105
}
@@ -112,41 +113,56 @@ private void _addPathToClassPath(String path) {
112113
try {
113114
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
114115
method.setAccessible(true);
115-
method.invoke(classLoader, (new File(path)).toURI().toURL() );
116+
method.invoke(classLoader, (new File(path)).toURI().toURL());
116117

117118
} catch (Exception e) {
118-
throw new JavaFXLibraryFatalException("Problem setting the classpath: " + path , e);
119+
throw new JavaFXLibraryFatalException("Problem setting the classpath: " + path, e);
119120
}
120121
}
121122

122123
@RobotKeyword("Loads given path to classpath.\n\n"
123-
+ "``path`` is the path to add.\n\n"
124-
+ "If directory path has asterisk(*) after directory separator all jar files are added from directory.\n"
125-
+ "\nExample:\n"
126-
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder | \n"
127-
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder${/}* | \n")
128-
@ArgumentNames({"path"})
129-
public void setToClasspath(String path) {
124+
+ "``path`` is the path to add.\n\n"
125+
+ "``failIfNotFound`` is either True or False, default False. In case of False error is written as warning.\n\n"
126+
+ "If directory path has asterisk(*) after directory separator all jar files are added from directory.\n"
127+
+ "\nExample:\n"
128+
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder | \n"
129+
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder${/}* | \n"
130+
+ "| Set To Classpath | C:${/}users${/}my${/}test${/}folder2${/}* | failIfNotFound=${True} | \n")
131+
@ArgumentNames({ "path", "failIfNotFound=False" })
132+
public void setToClasspath(String path, boolean failIfNotFound) {
133+
RobotLog.info("Setting \"" + path + "\" to classpath, failIfNotFound=\"" + failIfNotFound + "\"");
130134
if (path.endsWith("*")) {
131-
path = path.substring(0, path.length() - 1);
132-
RobotLog.info("Adding all jars from directory: " + path);
135+
path = path.substring(0, path.length() - 1);
136+
RobotLog.info("Adding all jars from directory.");
137+
String fullPath = FileSystems.getDefault().getPath(path).normalize().toAbsolutePath().toString();
133138

134-
try {
135-
File directory = new File(path);
136-
File[] fileList = directory.listFiles();
137-
boolean jarsFound = false;
138-
for (File file : Objects.requireNonNull(fileList)) {
139-
if (file.getName().endsWith(".jar")) {
140-
jarsFound = true;
141-
_addPathToClassPath(file.getAbsolutePath());
142-
}
143-
}
144-
if(!jarsFound) throw new JavaFXLibraryNonFatalException("No jar files found from classpath: " + FileSystems.getDefault().getPath(path).normalize().toAbsolutePath().toString());
145-
} catch (NullPointerException e) {
146-
throw new JavaFXLibraryFatalException("Directory not found: " + path + "\n" + e.getMessage(), e);
147-
}
148-
}
149-
else {
139+
try {
140+
File directory = new File(path);
141+
File[] fileList = directory.listFiles();
142+
boolean jarsFound = false;
143+
for (File file : Objects.requireNonNull(fileList)) {
144+
if (file.getName().endsWith(".jar")) {
145+
jarsFound = true;
146+
_addPathToClassPath(file.getAbsolutePath());
147+
}
148+
}
149+
if (!jarsFound) {
150+
String jarsNotFoundError = "No jar files found from classpath: " + fullPath;
151+
if (failIfNotFound) {
152+
throw new JavaFXLibraryNonFatalException(jarsNotFoundError);
153+
} else {
154+
RobotLog.warn(jarsNotFoundError);
155+
}
156+
}
157+
} catch (NullPointerException e) {
158+
String directoryNotFoundError = "Directory not found: " + fullPath;
159+
if (failIfNotFound) {
160+
throw new JavaFXLibraryFatalException(directoryNotFoundError);
161+
} else {
162+
RobotLog.warn(directoryNotFoundError);
163+
}
164+
}
165+
} else {
150166
_addPathToClassPath(path);
151167
}
152168
}
@@ -157,8 +173,9 @@ public void logApplicationClasspath() {
157173
ClassLoader cl = ClassLoader.getSystemClassLoader();
158174
URL[] urls = ((URLClassLoader) cl).getURLs();
159175
RobotLog.info("Printing out classpaths: \n");
160-
for (URL url : urls)
176+
for (URL url : urls) {
161177
RobotLog.info(url.getFile());
178+
}
162179
} catch (Exception e) {
163180
throw new JavaFXLibraryNonFatalException("Unable to log application classpaths", e);
164181
}
@@ -237,7 +254,6 @@ public void clearObjectMap() {
237254
objectMap.clear();
238255
}
239256

240-
241257
@RobotKeyword("Returns the class name of currently active JavaFX Application")
242258
public String getCurrentApplication() {
243259
try {
@@ -247,15 +263,9 @@ public String getCurrentApplication() {
247263
}
248264
}
249265

250-
@Deprecated
251-
@RobotKeyword("*DEPRECATED in version 0.6.0!* Use `Get Current Application` keyword instead.\n\n"
252-
+ "Returns the class name of currently active JavaFX Application\n")
253-
public String currentApplication() {
254-
try {
255-
return getCurrentSessionApplicationName();
256-
} catch (Exception e) {
257-
throw new JavaFXLibraryNonFatalException("Problem getting current application name.", e);
258-
}
266+
@RobotKeyword("Returns if JavaFXLibrary is started as java agent.")
267+
public boolean isJavaAgent() {
268+
return TestFxAdapter.isAgent;
259269
}
260270

261271
}

0 commit comments

Comments
 (0)