Skip to content

Commit 599cf57

Browse files
jakobbraunmorazow
andauthored
#8 Added test setup for debugging in UDFs (#9)
* #8 Added test setup for debugging in UDFs Co-authored-by: Muhammet Orazov <m.orazow@gmail.com>
1 parent 1a34f85 commit 599cf57

File tree

10 files changed

+248
-16
lines changed

10 files changed

+248
-16
lines changed

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,30 @@ This repository contains tools for debugging UDFs.
1010
Install as maven dependency.
1111
You can get the dependency declaration by clicking the maven badge above.
1212

13+
## Typical Usage
14+
15+
Typically, you use this package together with [test-db-builder-java](https://github.com/exasol/test-db-builder-java) and [exasol-testcontainers](https://github.com/exasol/exasol-testcontainers) as follows:
16+
17+
```java
18+
final UdfTestSetup udfTestSetup = new UdfTestSetup(getTestHostIp());
19+
final ExasolObjectFactory testDbBuilder = new ExasolObjectFactory(EXASOL.createConnection(),
20+
ExasolObjectConfiguration.builder().withJvmOptions(udfTestSetup.getJvmOptions()).build());
21+
```
22+
23+
## Modules
24+
25+
This package contains multiple modules that you can enable on runtime by setting the corresponding system property to `true`.
26+
Typically, you do so by appending `-D<PROPERTY_NAME>="true"` to your JVM call.
27+
28+
29+
### Debugging
30+
31+
System property: `test.debug`
32+
33+
This module instructs the UDF JVMs to connect to a Java debugger listening on the default port 8000 on you machine, running the tests.
34+
35+
1336
## Additional Information
1437

1538
* [Changelog](doc/changes/changelog.md)
16-
* [Dependencies](NOTICE)
39+
* [Dependencies](NOTICE)

doc/changes/changes_0.2.0.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
# udf-debugging-java 0.2.0, released 2020-XX-XX
1+
# udf-debugging-java 0.2.0, released 2020-10-28
22

3-
Code name:
3+
Code name: Test setup for UDF debugging
44

55
## Features / Enhancements
66

77
* #5: Sonar Cloud setup
88
* #6: Changed default value of getSelectionThatIsSentToTheAdapter to empty string
9+
* #8: Added test setup for debugging in UDFs
910

1011
## Dependency Updates:
1112

pom.xml

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@
121121
<version>${jacoco.version}</version>
122122
<scope>test</scope>
123123
</dependency>
124+
<dependency>
125+
<groupId>org.slf4j</groupId>
126+
<artifactId>slf4j-api</artifactId>
127+
<version>1.7.30</version>
128+
<scope>compile</scope>
129+
</dependency>
124130
</dependencies>
125131
<build>
126132
<plugins>
@@ -362,19 +368,20 @@
362368
<configuration>
363369
<noticeTemplate>NOTICE.template</noticeTemplate>
364370
365-
<licenseMapping>
366-
<param>https://source.jasig.org/licenses/license-mappings.xml</param>
367-
</licenseMapping>
368-
</configuration>
369-
<executions>
370-
<execution>
371-
<phase>package</phase>
372-
<goals>
373-
<goal>check</goal>
374-
</goals>
375-
</execution>
376-
</executions>
377-
</plugin>-->
371+
<licenseMapping>
372+
<param>https://source.jasig.org/licenses/license-mappings.xml</param>
373+
</licenseMapping>
374+
</configuration>
375+
<executions>
376+
<execution>
377+
<phase>package</phase>
378+
<goals>
379+
<goal>check</goal>
380+
</goals>
381+
</execution>
382+
</executions>
383+
</plugin>
384+
-->
378385
</plugins>
379386
<testResources>
380387
<testResource>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.exasol.udfdebugging;
2+
3+
import java.util.stream.Stream;
4+
5+
public interface Module {
6+
7+
public Stream<String> getJvmOptions();
8+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.exasol.udfdebugging;
2+
3+
public interface ModuleFactory {
4+
5+
/**
6+
* Get if this module is enabled by system property.
7+
*
8+
* @return {@code true} if this module is enabled
9+
*/
10+
public boolean isEnabled();
11+
12+
/**
13+
* Get the name of the property to enable this module.
14+
*
15+
* @return name of the property to enable this module
16+
*/
17+
public String getModulePropertyName();
18+
19+
/**
20+
* Build the {@link Module}.
21+
*
22+
* @param testHostIpAddress IP address of the host running this UDF Test Setup under which UDFs can reach it
23+
* @return built {@link Module}
24+
*/
25+
public Module buildModule(final String testHostIpAddress);
26+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.exasol.udfdebugging;
2+
3+
import java.util.List;
4+
import java.util.stream.Collectors;
5+
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
9+
import com.exasol.udfdebugging.modules.debugging.DebuggingModuleFactory;
10+
11+
/**
12+
* Test setup for testing UDFs in the database.
13+
*/
14+
public class UdfTestSetup {
15+
private static final List<ModuleFactory> AVAILABLE_MODULES = List.of(new DebuggingModuleFactory());
16+
private static final Logger LOGGER = LoggerFactory.getLogger(UdfTestSetup.class);
17+
private final List<Module> enabledModules;
18+
19+
/**
20+
* Create a new instance of {@link UdfTestSetup}.
21+
*
22+
* @param testHostIpAddress IP address of the host running this UDF Test Setup under which UDFs can reach it
23+
*/
24+
public UdfTestSetup(final String testHostIpAddress) {
25+
this.enabledModules = AVAILABLE_MODULES.stream().filter(ModuleFactory::isEnabled)
26+
.map(moduleFactory -> moduleFactory.buildModule(testHostIpAddress)).collect(Collectors.toList());
27+
printInfoMessage();
28+
}
29+
30+
/**
31+
* Get JVM options required for this setup.
32+
*
33+
* @return array of JVM options
34+
*/
35+
public String[] getJvmOptions() {
36+
return this.enabledModules.stream().flatMap(Module::getJvmOptions).toArray(String[]::new);
37+
}
38+
39+
private void printInfoMessage() {
40+
if (LOGGER.isInfoEnabled()) {
41+
LOGGER.info(getInfoMessage());
42+
}
43+
}
44+
45+
private String getInfoMessage() {
46+
final StringBuilder messageBuilder = new StringBuilder("Udf Test Setup Configuration:\n");
47+
AVAILABLE_MODULES.forEach(module -> {
48+
messageBuilder.append(module.getModulePropertyName());
49+
messageBuilder.append(":\t");
50+
messageBuilder.append(module.isEnabled() ? "enabled" : "disabled");
51+
messageBuilder.append("\n");
52+
});
53+
return messageBuilder.toString();
54+
}
55+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.exasol.udfdebugging.modules;
2+
3+
import com.exasol.udfdebugging.Module;
4+
import com.exasol.udfdebugging.ModuleFactory;
5+
6+
/**
7+
* Abstract basis for {@link Module}.
8+
*/
9+
public abstract class AbstractModuleFactory implements ModuleFactory {
10+
private final String moduleProperty;
11+
12+
/**
13+
* Create a new instance of {@link AbstractModuleFactory}.
14+
*
15+
* @param moduleName name of the module
16+
*/
17+
protected AbstractModuleFactory(final String moduleName) {
18+
this.moduleProperty = "test." + moduleName;
19+
}
20+
21+
@Override
22+
public final boolean isEnabled() {
23+
return System.getProperty(this.moduleProperty, "false").equals("true");
24+
}
25+
26+
@Override
27+
public String getModulePropertyName() {
28+
return this.moduleProperty;
29+
}
30+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.exasol.udfdebugging.modules.debugging;
2+
3+
import java.util.stream.Stream;
4+
5+
import com.exasol.udfdebugging.Module;
6+
7+
public class DebuggingModule implements Module {
8+
public static final String DEBUGGING_PORT = "8000";
9+
private final String testHostIpAddress;
10+
11+
/**
12+
* Create a new instance of {@link DebuggingModule}.
13+
*
14+
* @param testHostIpAddress IP address of the host running this UDF Test Setup under which UDFs can reach it
15+
*/
16+
public DebuggingModule(final String testHostIpAddress) {
17+
this.testHostIpAddress = testHostIpAddress;
18+
}
19+
20+
@Override
21+
public Stream<String> getJvmOptions() {
22+
return Stream.of("-agentlib:jdwp=transport=dt_socket,server=n,address=" + this.testHostIpAddress + ":"
23+
+ DEBUGGING_PORT + ",suspend=y");
24+
}
25+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.exasol.udfdebugging.modules.debugging;
2+
3+
import com.exasol.udfdebugging.Module;
4+
import com.exasol.udfdebugging.modules.AbstractModuleFactory;
5+
6+
public class DebuggingModuleFactory extends AbstractModuleFactory {
7+
/**
8+
* Create a new instance of {@link DebuggingModuleFactory}.
9+
*/
10+
public DebuggingModuleFactory() {
11+
super("debug");
12+
}
13+
14+
@Override
15+
public Module buildModule(final String testHostIpAddress) {
16+
return new DebuggingModule(testHostIpAddress);
17+
}
18+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.exasol.udfdebugging;
2+
3+
import static org.hamcrest.CoreMatchers.hasItem;
4+
import static org.hamcrest.CoreMatchers.not;
5+
import static org.hamcrest.MatcherAssert.assertThat;
6+
7+
import java.util.Arrays;
8+
import java.util.List;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
class UdfTestSetupTest {
13+
public static final String DEBUG_PROPERTY = "test.debug";
14+
private static final String EXPECTED_DEBUG_JVM_OPTION = "-agentlib:jdwp=transport=dt_socket,server=n,address=1.2.3.4:8000,suspend=y";
15+
16+
@Test
17+
void testDebuggingEnabled() {
18+
System.setProperty(DEBUG_PROPERTY, "true");
19+
final UdfTestSetup udfTestSetup = new UdfTestSetup("1.2.3.4");
20+
final List<String> jvmOptions = Arrays.asList(udfTestSetup.getJvmOptions());
21+
assertThat(jvmOptions, hasItem(EXPECTED_DEBUG_JVM_OPTION));
22+
}
23+
24+
@Test
25+
void testDebuggingIsDisabledByDefault() {
26+
System.clearProperty(DEBUG_PROPERTY);
27+
final UdfTestSetup udfTestSetup = new UdfTestSetup("1.2.3.4");
28+
final List<String> jvmOptions = Arrays.asList(udfTestSetup.getJvmOptions());
29+
assertThat(jvmOptions, not(hasItem(EXPECTED_DEBUG_JVM_OPTION)));
30+
}
31+
32+
@Test
33+
void testDebuggingDisabled() {
34+
System.setProperty(DEBUG_PROPERTY, "false");
35+
final UdfTestSetup udfTestSetup = new UdfTestSetup("1.2.3.4");
36+
final List<String> jvmOptions = Arrays.asList(udfTestSetup.getJvmOptions());
37+
assertThat(jvmOptions, not(hasItem(EXPECTED_DEBUG_JVM_OPTION)));
38+
}
39+
}

0 commit comments

Comments
 (0)