Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run JS API unit tests and integration tests in the Gradle build #4988

Merged
merged 32 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b048f9c
Hacked together tests
niloc132 Apr 14, 2023
c05823a
Tests build, but do not pass
niloc132 Apr 19, 2023
30d1df4
bad idea: opt in to a huge payload from the server - should instead
niloc132 Sep 28, 2023
47a68cd
quick hack to decrease treemap costs - fix with non-random loading
niloc132 Sep 28, 2023
ea53236
spotless for ci
niloc132 Oct 23, 2023
e8ddd50
fix regression in formatting longs
niloc132 Nov 2, 2023
5f8cb54
integration tests run, fail
niloc132 Nov 2, 2023
a855985
Tests are passing in manual mode, except filter setup
niloc132 Nov 3, 2023
06a17a5
Tidy up tests, disable filter tests for now
niloc132 Nov 3, 2023
354fd48
Add additional integration tests
niloc132 Nov 6, 2023
d8ad542
null values test
niloc132 Nov 6, 2023
9df4859
POtential totals table test
niloc132 Nov 6, 2023
d9da1ca
Attempt at reusing code from gwt-core test
niloc132 Dec 21, 2023
6e6326d
Nearly working tests from gradle, with TODOs
niloc132 Dec 23, 2023
92e6f3a
Checkpoint commit, gwt test tasks pass, check fails
niloc132 Dec 27, 2023
37639a0
Dirty hack to avoid esoco's assumption that compile must run after test
niloc132 Dec 27, 2023
03939d9
Don't run gwt tests with in quick
niloc132 Dec 27, 2023
0d15ac3
Remove unused build file, raise timeout on a test
niloc132 Dec 27, 2023
49b9b95
Merge branch 'main' into js-flight
niloc132 Dec 27, 2023
0d02ff3
Clean up readability, use a registry image
niloc132 Dec 27, 2023
dd54ea8
tidy things up to working in CI
niloc132 Dec 27, 2023
e16cbb7
Revert SubscriptionTableData, WorkerConnection
niloc132 Dec 27, 2023
4af1341
Final cleanup (?)
niloc132 Dec 27, 2023
43a102f
Parameterize port and timeouts, other cleanup
niloc132 Jan 2, 2024
2bab42b
Rework networking so hopefully docker-desktop behaves
niloc132 Jan 2, 2024
d61c783
Add healthcheck, cleanup
niloc132 Jan 2, 2024
a11687d
Clean up forked test runner
niloc132 Jan 2, 2024
e03f3e7
Inline more wd runstyle contents
niloc132 Jan 2, 2024
ab0bb30
Change up timeouts a bit
mofojed Jan 3, 2024
4413dcf
Increase a few more timeouts and make them unique
niloc132 Jan 3, 2024
a0c4f0d
Add missing basic column types
niloc132 Jan 3, 2024
713007d
Fix selenium port mapping
niloc132 Jan 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 6 additions & 21 deletions buildSrc/src/main/groovy/GwtTools.groovy
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import de.esoco.gwt.gradle.GwtLibPlugin
import de.esoco.gwt.gradle.GwtPlugin
import de.esoco.gwt.gradle.extension.GwtExtension
import de.esoco.gwt.gradle.task.GwtCheckTask
import de.esoco.gwt.gradle.task.GwtCompileTask
import groovy.transform.CompileStatic
import org.gradle.api.Project
Expand Down Expand Up @@ -36,6 +37,10 @@ class GwtTools {
GwtCompileTask gwtc ->
applyModuleSettings p, gwtc, module,description
}
p.tasks.withType(GwtCheckTask).configureEach {t ->
t.mustRunAfter(p.tasks.withType(GwtCompileTask))
t.onlyIf { false }
}

return ext
}
Expand Down Expand Up @@ -70,8 +75,6 @@ class GwtTools {
gwtDev && gwtc.doFirst {
gwtc.logger.quiet('Running in gwt dev mode; saving source to {}/dh/src', extras)
}

p.tasks.findByName('gwtCheck')?.enabled = false
}

static void applyDefaults(Project p, GwtExtension gwt, boolean compile = false) {
Expand Down Expand Up @@ -110,31 +113,13 @@ class GwtTools {
maxHeapSize = "1024m"
minHeapSize = "512m"
}

gwt.dev.with {
/** The ip address of the code server. */
bindAddress = "127.0.0.1"
/** The port where the code server will run. */
port = 9876
/** Specifies Java source level ("1.6", "1.7").
sourceLevel = "1.8"
/** The level of logging detail (ERROR, WARN, INFO, TRACE, DEBUG, SPAM, ALL) */
logLevel = "INFO"
/** Emit extra information allow chrome dev tools to display Java identifiers in many placesinstead of JavaScript functions. (NONE, ONLY_METHOD_NAME, ABBREVIATED, FULL) */
methodNameDisplayMode = "NONE"
/** Where to write output files */
war = warPath
// extraArgs = ["-firstArgument", "-secondArgument"]
}


}
}

static void addGeneratedSources(Project project, GwtCompileTask gwtc) {
if (project.configurations.getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME).dependencies) {
(gwtc.src as ConfigurableFileCollection).from(
(project.tasks.getByName(JavaPlugin.COMPILE_JAVA_TASK_NAME) as JavaCompile).options.annotationProcessorGeneratedSourcesDirectory
(project.tasks.getByName(JavaPlugin.COMPILE_JAVA_TASK_NAME) as JavaCompile).options.generatedSourceOutputDirectory
)
}
project.configurations.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME).allDependencies.withType(ProjectDependency)*.dependencyProject*.each {
Expand Down
33 changes: 0 additions & 33 deletions gradle/web-gwt-test.gradle

This file was deleted.

85 changes: 83 additions & 2 deletions web/client-api/client-api.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import com.bmuschko.gradle.docker.tasks.container.DockerCreateContainer
import com.bmuschko.gradle.docker.tasks.container.DockerRemoveContainer
import com.bmuschko.gradle.docker.tasks.container.DockerStartContainer
import io.deephaven.tools.docker.WaitForHealthyContainer

plugins {
id 'io.deephaven.project.register'
id 'io.deephaven.deephaven-in-docker'
}

apply from: "$rootDir/gradle/web-client.gradle"
Expand All @@ -8,6 +14,7 @@ configurations {
js
dts
typescriptDoclet
testImplementation.extendsFrom junit
}

dependencies {
Expand All @@ -20,6 +27,8 @@ dependencies {
implementation 'com.vertispan.nio:gwt-nio:1.0-alpha-1'

js project(path: ':proto:raw-js-openapi', configuration: 'js')

testImplementation 'org.seleniumhq.selenium:selenium-remote-driver:4.16.1'
}
Classpaths.inheritElemental(project, 'elemental2-core', 'implementation')
Classpaths.inheritElemental(project, 'elemental2-promise', 'implementation')
Expand Down Expand Up @@ -57,6 +66,78 @@ artifacts {
}
}

project.tasks.getByName('quick').dependsOn project.tasks.withType(de.esoco.gwt.gradle.task.GwtCompileTask)
def gwtUnitTest = tasks.register('gwtUnitTest', Test) { t ->
t.systemProperties = [
'gwt.args': "-runStyle HtmlUnit -ea -style PRETTY -war ${layout.buildDirectory.dir('unitTest-war').get().asFile.absolutePath}",
'gwt.persistentunitcachedir':layout.buildDirectory.dir('unitTest-unitCache').get().asFile.absolutePath,
]
t.include '**/ClientUnitTestSuite.class'
t.useJUnit()
t.scanForTestClasses = false
}

// start a grpc-api server
String randomSuffix = UUID.randomUUID().toString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we doing this? Is this safe to do? Seems like this would mess up gradle caching?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would yes, but we are doing this all over for naming docker containers, so that you don't accidentally collide in parallel runs, or separate checkouts, etc. Since this is just for tests, we're not concerned with "oh these tests passed last time, so I'm not even going to run them this time" for integration tests.

deephavenDocker {
envVars.set([
'START_OPTS':'-Xmx512m -DAuthHandlers=io.deephaven.auth.AnonymousAuthenticationHandler'
])
containerName.set "dh-server-for-js-${randomSuffix}"
networkName.set "js-test-network-${randomSuffix}"
}

def seleniumContainerId = "selenium-${randomSuffix}"

def createSelenium = tasks.register('createSelenium', DockerCreateContainer) { t ->
t.containerName.set(seleniumContainerId)
t.targetImageId('selenium/standalone-firefox:4.16.1-20231219')// TODO create a registry entry for this
t.hostConfig.shmSize.set(2L * 1024 * 1024 * 1024)
t.hostConfig.portBindings.set(['4444:4444', '7900:7900'])//TODO don't expose 7900, and make 4444 dynamic
t.hostConfig.network.set('host')
}
def startSelenium = tasks.register('startSelenium', DockerStartContainer) {t ->
t.dependsOn(createSelenium)
t.containerId.set(seleniumContainerId)
}
def seleniumHealthy = project.tasks.register('seleniumHealthy', WaitForHealthyContainer) { task ->
task.dependsOn startSelenium

task.awaitStatusTimeout.set 120
task.checkInterval.set 100
Comment on lines +126 to +127
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side note - really confusing that awaitStatusTimeout is in seconds, and checkInterval is in ms.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed... can go back and rewrite those, but I vote not today. This is code taken from the upstream docker-gradle plugin, and we didn't customize it further.


apply from: "$rootDir/gradle/web-gwt-test.gradle"
task.containerId.set(seleniumContainerId)
}
def stopSelenium = project.tasks.register('stopSelenium', DockerRemoveContainer) { task ->
task.dependsOn startSelenium
task.targetContainerId seleniumContainerId
task.force.set true
task.removeVolumes.set true
}
// before/after:
// docker run -d -p 4444:4444 -p 7900:7900 --shm-size="2g" --net=host selenium/standalone-firefox:4.16.1-20231219

def gwtIntegrationTest = tasks.register('gwtIntegrationTest', Test) { t ->
t.dependsOn(deephavenDocker.portTask, seleniumHealthy)
t.finalizedBy(deephavenDocker.endTask, stopSelenium)
doFirst {
def webdriverUrl = 'http://localhost:4444/'
t.systemProperty('gwt.args', "-runStyle io.deephaven.web.junit.RunStyleRemoteWebDriver:${webdriverUrl}?firefox -ea -style PRETTY -setProperty dh.server=http://localhost:${deephavenDocker.port.get()} -war ${layout.buildDirectory.dir('integrationTest-war').get().asFile.absolutePath}")
t.classpath += tasks.getByName('gwtCompile').src
}
t.finalizedBy(deephavenDocker.endTask)
t.systemProperties = [
'gwt.persistentunitcachedir':layout.buildDirectory.dir('integrationTest-unitCache').get().asFile.absolutePath,
]
t.include '**/ClientIntegrationTestSuite.class'
t.useJUnit()
t.scanForTestClasses = false
}

tasks.named('check').configure {
dependsOn(gwtUnitTest, gwtIntegrationTest)
}

test {
// Configure jvm-only tests to not run any GWT-only tests
exclude '**/*TestGwt.class', '**/*TestSuite.class'
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import jsinterop.annotations.JsIgnore;
import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
niloc132 marked this conversation as resolved.
Show resolved Hide resolved

import java.util.Arrays;
import java.util.HashMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import io.deephaven.web.client.api.batch.TableConfig;
import io.deephaven.web.client.api.console.JsVariableType;
import io.deephaven.web.client.api.filter.FilterCondition;
import io.deephaven.web.client.api.filter.FilterValue;
import io.deephaven.web.client.api.input.JsInputTable;
import io.deephaven.web.client.api.lifecycle.HasLifecycle;
import io.deephaven.web.client.api.state.StateCache;
Expand All @@ -71,6 +72,8 @@
import io.deephaven.web.shared.fu.JsProvider;
import io.deephaven.web.shared.fu.JsRunnable;
import io.deephaven.web.shared.fu.RemoverFn;
import javaemul.internal.annotations.DoNotAutobox;
import jsinterop.annotations.JsIgnore;
import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsNullable;
import jsinterop.annotations.JsOptional;
Expand Down Expand Up @@ -594,6 +597,11 @@ public JsArray<FilterCondition> applyFilter(FilterCondition[] filter) {
@TsUnion
@JsType(name = "?", namespace = JsPackage.GLOBAL, isNative = true)
public interface CustomColumnArgUnionType {
@JsOverlay
static CustomColumnArgUnionType of(@DoNotAutobox Object value) {
return Js.cast(value);
}

@JsOverlay
default boolean isString() {
return (Object) this instanceof String;
Expand Down Expand Up @@ -1762,8 +1770,8 @@ public void handleSnapshot(TableTicket handle, TableSnapshot snapshot) {
viewportRows.size());
}


protected void processSnapshot() {
@JsIgnore
public void processSnapshot() {
niloc132 marked this conversation as resolved.
Show resolved Hide resolved
try {
if (debounce == null) {
JsLog.debug("Skipping snapshot b/c debounce is null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,7 @@ private void flush() {
// TODO #188 support minUpdateIntervalMs
double serializationOptionsOffset = BarrageSubscriptionOptions
.createBarrageSubscriptionOptions(subscriptionReq, ColumnConversionMode.Stringify, true, 1000,
0, 0);
0, 1_000_000_000);
niloc132 marked this conversation as resolved.
Show resolved Hide resolved
double tableTicketOffset =
BarrageSubscriptionRequest.createTicketVector(subscriptionReq, state.getHandle().getTicket());
BarrageSubscriptionRequest.startBarrageSubscriptionRequest(subscriptionReq);
Expand Down
Loading
Loading