diff --git a/.github/actions/upload-coverage/action.yml b/.github/actions/upload-coverage/action.yml index 2678aaf18fe98..faa4d510350d2 100644 --- a/.github/actions/upload-coverage/action.yml +++ b/.github/actions/upload-coverage/action.yml @@ -19,7 +19,8 @@ name: Upload to Codecov with retries description: | - Uploads to codecov with multiple retries as a workaround + Checks that the current repository is public and then + uploads to codecov with multiple retries as a workaround for these issues - https://github.com/codecov/codecov-action/issues/598 - https://github.com/codecov/codecov-action/issues/837 @@ -30,8 +31,26 @@ inputs: runs: using: composite steps: + - name: "Check that repository is public" + id: repo-check + shell: bash + run: | + if [[ "${{ github.server_url }}" != "https://github.com" ]]; then + echo "Not using github.com server ('${{ github.server_url }}'). Skipping uploading of coverage metrics." + echo "passed=false" >> $GITHUB_OUTPUT + exit 0 + fi + REPO_URL="${{ github.server_url }}/${{ github.repository }}" + { + # public repository url will respond to http HEAD request + curl -X HEAD -fs "$REPO_URL" && echo "passed=true" >> $GITHUB_OUTPUT + } || { + echo "$REPO_URL isn't a public repository. Skipping uploading of coverage metrics." + echo "passed=false" >> $GITHUB_OUTPUT + } - name: "Upload to Codecov (attempt #1)" id: codecov-upload-1 + if: steps.repo-check.outputs.passed == 'true' uses: codecov/codecov-action@v3 continue-on-error: true with: diff --git a/.github/workflows/pulsar-ci-flaky.yaml b/.github/workflows/pulsar-ci-flaky.yaml index 6b4da95173ce9..1b17e3ecbc6f2 100644 --- a/.github/workflows/pulsar-ci-flaky.yaml +++ b/.github/workflows/pulsar-ci-flaky.yaml @@ -128,7 +128,6 @@ jobs: uses: ./.github/actions/copy-test-reports - name: Upload to Codecov - if: ${{ github.repository == 'apache/pulsar' }} uses: ./.github/actions/upload-coverage with: flags: unittests diff --git a/.github/workflows/pulsar-ci.yaml b/.github/workflows/pulsar-ci.yaml index 8e08c65d9a191..abb015ed15c8b 100644 --- a/.github/workflows/pulsar-ci.yaml +++ b/.github/workflows/pulsar-ci.yaml @@ -247,7 +247,6 @@ jobs: uses: ./.github/actions/copy-test-reports - name: Upload to Codecov - if: ${{ github.repository == 'apache/pulsar' }} uses: ./.github/actions/upload-coverage with: flags: unittests @@ -377,6 +376,7 @@ jobs: include: - name: Backwards Compatibility group: BACKWARDS_COMPAT + no_coverage: true - name: Cli group: CLI @@ -388,15 +388,18 @@ jobs: group: SHADE_RUN runtime_jdk: 8 setup: ./build/run_integration_group.sh SHADE_BUILD + no_coverage: true - name: Shade on Java 11 group: SHADE_RUN runtime_jdk: 11 setup: ./build/run_integration_group.sh SHADE_BUILD + no_coverage: true - name: Shade on Java 17 group: SHADE_RUN setup: ./build/run_integration_group.sh SHADE_BUILD + no_coverage: true - name: Standalone group: STANDALONE @@ -467,7 +470,15 @@ jobs: - name: Run integration test group '${{ matrix.group }}' run: | - ./build/run_integration_group.sh ${{ matrix.group }} + if [[ "${{ matrix.no_coverage }}" != "true" ]]; then + coverage_args="--coverage" + fi + ./build/run_integration_group.sh ${{ matrix.group }} $coverage_args + + - name: Upload to Codecov + uses: ./.github/actions/upload-coverage + with: + flags: inttests - name: print JVM thread dumps when cancelled if: cancelled() @@ -739,7 +750,12 @@ jobs: - name: Run system test group '${{ matrix.group }}' run: | - ./build/run_integration_group.sh ${{ matrix.group }} + ./build/run_integration_group.sh ${{ matrix.group }} --coverage + + - name: Upload to Codecov + uses: ./.github/actions/upload-coverage + with: + flags: systests - name: print JVM thread dumps when cancelled if: cancelled() diff --git a/build/run_integration_group.sh b/build/run_integration_group.sh index 1ba66fbc93c64..974ad96e419ac 100755 --- a/build/run_integration_group.sh +++ b/build/run_integration_group.sh @@ -27,6 +27,7 @@ set -o errexit JAVA_MAJOR_VERSION="$(java -version 2>&1 |grep " version " | awk -F\" '{ print $2 }' | awk -F. '{ if ($1=="1") { print $2 } else { print $1 } }')" # Used to shade run test on Java 8, because the latest TestNG requires Java 11 or higher. TESTNG_VERSION="7.3.0" +COVERAGE_COLLECTED=0 # lists all active maven modules with given parameters # parses the modules from the "mvn initialize" output @@ -46,15 +47,14 @@ mvn_list_modules() { # 2. runs "mvn -pl [active_modules] -am install [given_params]" to build and install required dependencies # 3. finally runs tests with "mvn -pl [active_modules] test [given_params]" mvn_run_integration_test() { - ( set +x # skip test run if next parameter is "--build-only" - build_only=0 + local build_only=0 if [[ "$1" == "--build-only" ]]; then build_only=1 shift fi - skip_build_deps=0 + local skip_build_deps=0 while [[ "$1" == "--skip-build-deps" ]]; do skip_build_deps=1 shift @@ -78,8 +78,19 @@ mvn_run_integration_test() { else failfast_args="-DtestFailFast=false --fail-at-end" fi + local coverage_args="" + if [[ "$1" == "--coverage" ]]; then + if [ ! -d /tmp/jacocoDir ]; then + mkdir /tmp/jacocoDir + sudo chmod 0777 /tmp/jacocoDir || chmod 0777 /tmp/jacocoDir + fi + coverage_args="-Pcoverage -Dintegrationtest.coverage.enabled=true -Dintegrationtest.coverage.dir=/tmp/jacocoDir" + COVERAGE_COLLECTED=1 + shift + fi + ( cd "$SCRIPT_DIR"/../tests - modules=$(mvn_list_modules -DskipDocker "$@") + local modules=$(mvn_list_modules -DskipDocker "$@") cd .. set -x if [ $skip_build_deps -ne 1 ]; then @@ -90,14 +101,46 @@ mvn_run_integration_test() { if [[ $build_only -ne 1 ]]; then echo "::group::Run tests for " "$@" # use "verify" instead of "test" - mvn -B -ntp -pl "$modules" $failfast_args -DskipDocker -DskipSourceReleaseAssembly=true -Dspotbugs.skip=true -Dlicense.skip=true -Dcheckstyle.skip=true -Drat.skip=true -DredirectTestOutputToFile=false $clean_arg verify "$@" + mvn -B -ntp -pl "$modules" $failfast_args $coverage_args -DskipDocker -DskipSourceReleaseAssembly=true -Dspotbugs.skip=true -Dlicense.skip=true -Dcheckstyle.skip=true -Drat.skip=true -DredirectTestOutputToFile=false $clean_arg verify "$@" echo "::endgroup::" set +x - "$SCRIPT_DIR/pulsar_ci_tool.sh" move_test_reports + "$SCRIPT_DIR/pulsar_ci_tool.sh" move_test_reports || true fi ) } +# creates a jacoco xml report of the jacoco exec files produced in docker containers which have /tmp/jacocoDir mounted as /jacocoDir +# this is used to calculate test coverage for the apache/pulsar code that is run inside the containers in integration tests +# and system tests +produce_integration_test_coverage_xml_report() { + if [[ -d /tmp/jacocoDir && "$OSTYPE" == "linux-gnu"* && -n "$(find /tmp/jacocoDir -name "*.exec" -print -quit)" ]]; then + cd "$GITHUB_WORKSPACE" + local jacoco_xml_file=tests/integration/target/site/jacoco/jacoco_inttests.xml + echo "Creating coverage report to $jacoco_xml_file" + local jacoco_version=$(mvn help:evaluate -Dexpression=jacoco-maven-plugin.version -q -DforceStdout) + set -x + mkdir -p $(dirname $jacoco_xml_file) + # install jacococli.jar command line tool + if [ ! -f /tmp/jacocoDir/jacococli.jar ]; then + curl -sL -o /tmp/jacocoDir/jacococli.jar "https://repo1.maven.org/maven2/org/jacoco/org.jacoco.cli/${jacoco_version}/org.jacoco.cli-${jacoco_version}-nodeps.jar" + fi + # extract the Pulsar jar files from the docker image that was used to run the tests in the docker containers + # the class files used to produce the jacoco exec files are needed in the xml report generation + if [ ! -d /tmp/jacocoDir/pulsar_lib ]; then + mkdir /tmp/jacocoDir/pulsar_lib + docker run --rm -u "$UID:${GID:-"$(id -g)"}" -v /tmp/jacocoDir/pulsar_lib:/pulsar_lib:rw ${PULSAR_TEST_IMAGE_NAME:-apachepulsar/java-test-image:latest} bash -c "cp -p /pulsar/lib/org.apache.pulsar-* /pulsar_lib" + # remove jar file that causes duplicate classes issue + rm /tmp/jacocoDir/pulsar_lib/org.apache.pulsar-bouncy-castle* + fi + # produce jacoco XML coverage report from the exec files and using the extracted jar files + java -jar /tmp/jacocoDir/jacococli.jar report /tmp/jacocoDir/*.exec \ + --classfiles /tmp/jacocoDir/pulsar_lib --encoding UTF-8 --name "Pulsar Integration Tests - coverage in containers" \ + $(find -path "*/src/main/java" -printf "--sourcefiles %P ") \ + --xml $jacoco_xml_file + set +x + fi +} + test_group_shade() { mvn_run_integration_test "$@" -DShadeTests -DtestForkCount=1 -DtestReuseFork=false } @@ -223,6 +266,9 @@ echo "Test Group : $TEST_GROUP" test_group_function_name="test_group_$(echo "$TEST_GROUP" | tr '[:upper:]' '[:lower:]')" if [[ "$(LC_ALL=C type -t "${test_group_function_name}")" == "function" ]]; then eval "$test_group_function_name" "$@" + if [ $COVERAGE_COLLECTED -eq 1 ]; then + produce_integration_test_coverage_xml_report + fi else echo "INVALID TEST GROUP" echo "Available test groups:" diff --git a/codecov.yml b/codecov.yml index 139da33607056..a792887012396 100644 --- a/codecov.yml +++ b/codecov.yml @@ -21,12 +21,17 @@ codecov: require_ci_to_pass: yes notify: # should match the number of builds sending coverage reports - # currently pulsar-ci.yaml contains 9 builds and pulsar-ci-flaky.yaml contains 1 build - after_n_builds: 10 + # pulsar-ci.yaml contains: + # - 9 unit test builds + # - 4 integration test builds (without 'no_coverage: true') + # - 8 system test build + # pulsar-ci-flaky.yaml contains: + # - 1 build + after_n_builds: 22 comment: # should match the number of builds sending coverage reports - after_n_builds: 10 + after_n_builds: 22 layout: "reach, diff, flags, files" behavior: default require_changes: false diff --git a/pom.xml b/pom.xml index e16471e0c9e62..28f9318caef38 100644 --- a/pom.xml +++ b/pom.xml @@ -111,6 +111,8 @@ flexible messaging model and an intuitive client API. true + false + ${project.build.directory} /tmp kill apachepulsar diff --git a/tests/docker-images/latest-version-image/conf/bookie.conf b/tests/docker-images/latest-version-image/conf/bookie.conf index f5e237c3bbab0..07547bcaef6d3 100644 --- a/tests/docker-images/latest-version-image/conf/bookie.conf +++ b/tests/docker-images/latest-version-image/conf/bookie.conf @@ -25,3 +25,4 @@ directory=/pulsar environment=PULSAR_MEM="-Xmx128M -XX:MaxDirectMemorySize=512M",PULSAR_GC="-XX:+UseZGC" command=/pulsar/bin/pulsar bookie user=pulsar +stopwaitsecs=15 diff --git a/tests/docker-images/latest-version-image/conf/broker.conf b/tests/docker-images/latest-version-image/conf/broker.conf index 723e0a24704b1..63be36437741b 100644 --- a/tests/docker-images/latest-version-image/conf/broker.conf +++ b/tests/docker-images/latest-version-image/conf/broker.conf @@ -25,3 +25,4 @@ directory=/pulsar environment=PULSAR_MEM="-Xmx128M",PULSAR_GC="-XX:+UseZGC" command=/pulsar/bin/pulsar broker user=pulsar +stopwaitsecs=15 diff --git a/tests/docker-images/latest-version-image/conf/functions_worker.conf b/tests/docker-images/latest-version-image/conf/functions_worker.conf index 256739501e30a..8072639a0d4a2 100644 --- a/tests/docker-images/latest-version-image/conf/functions_worker.conf +++ b/tests/docker-images/latest-version-image/conf/functions_worker.conf @@ -25,3 +25,4 @@ directory=/pulsar environment=PULSAR_MEM="-Xmx128M",PULSAR_GC="-XX:+UseZGC" command=/pulsar/bin/pulsar functions-worker user=pulsar +stopwaitsecs=15 \ No newline at end of file diff --git a/tests/docker-images/latest-version-image/conf/global-zk.conf b/tests/docker-images/latest-version-image/conf/global-zk.conf index eb991f2999c62..e5ffd2eb9e769 100644 --- a/tests/docker-images/latest-version-image/conf/global-zk.conf +++ b/tests/docker-images/latest-version-image/conf/global-zk.conf @@ -25,3 +25,4 @@ directory=/pulsar environment=PULSAR_MEM="-Xmx128M",PULSAR_GC="-XX:+UseZGC" command=/pulsar/bin/pulsar configuration-store user=pulsar +stopwaitsecs=15 \ No newline at end of file diff --git a/tests/docker-images/latest-version-image/conf/local-zk.conf b/tests/docker-images/latest-version-image/conf/local-zk.conf index 46d8aeb1484b8..c96543db8a865 100644 --- a/tests/docker-images/latest-version-image/conf/local-zk.conf +++ b/tests/docker-images/latest-version-image/conf/local-zk.conf @@ -25,3 +25,4 @@ directory=/pulsar environment=PULSAR_MEM="-Xmx128M",PULSAR_GC="-XX:+UseZGC" command=/pulsar/bin/pulsar zookeeper user=pulsar +stopwaitsecs=15 \ No newline at end of file diff --git a/tests/docker-images/latest-version-image/conf/presto_worker.conf b/tests/docker-images/latest-version-image/conf/presto_worker.conf index 4e4a3ca581468..5a60ea550031c 100644 --- a/tests/docker-images/latest-version-image/conf/presto_worker.conf +++ b/tests/docker-images/latest-version-image/conf/presto_worker.conf @@ -25,3 +25,4 @@ directory=/pulsar environment=PULSAR_MEM="-Xmx128M",PULSAR_GC="-XX:+UseZGC" command=/pulsar/bin/pulsar sql-worker start user=pulsar +stopwaitsecs=15 \ No newline at end of file diff --git a/tests/docker-images/latest-version-image/conf/proxy.conf b/tests/docker-images/latest-version-image/conf/proxy.conf index 91c3d608cb141..343a0f9614e30 100644 --- a/tests/docker-images/latest-version-image/conf/proxy.conf +++ b/tests/docker-images/latest-version-image/conf/proxy.conf @@ -25,3 +25,4 @@ directory=/pulsar environment=PULSAR_MEM="-Xmx128M",PULSAR_GC="-XX:+UseZGC" command=/pulsar/bin/pulsar proxy user=pulsar +stopwaitsecs=15 \ No newline at end of file diff --git a/tests/docker-images/latest-version-image/conf/websocket.conf b/tests/docker-images/latest-version-image/conf/websocket.conf index 7a0fc3e009659..0418c4cbc26a3 100644 --- a/tests/docker-images/latest-version-image/conf/websocket.conf +++ b/tests/docker-images/latest-version-image/conf/websocket.conf @@ -25,3 +25,4 @@ directory=/pulsar environment=PULSAR_MEM="-Xmx128M",PULSAR_GC="-XX:+UseZGC" command=/pulsar/bin/pulsar websocket user=pulsar +stopwaitsecs=15 \ No newline at end of file diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml index 652fc7543500e..d83ce2d891a5c 100644 --- a/tests/integration/pom.xml +++ b/tests/integration/pom.xml @@ -280,7 +280,8 @@ maven-surefire-plugin ${testJacocoAgentArgument} -XX:+ExitOnOutOfMemoryError -Xmx1G -XX:MaxDirectMemorySize=1G - -Dio.netty.leakDetectionLevel=advanced -Dconfluent.version=${confluent.version} + -Dio.netty.leakDetectionLevel=advanced -Dconfluent.version=${confluent.version} -Djacoco.version=${jacoco-maven-plugin.version} + -Dintegrationtest.coverage.enabled=${integrationtest.coverage.enabled} -Dintegrationtest.coverage.dir=${integrationtest.coverage.dir} ${test.additional.args} false diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ChaosContainer.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ChaosContainer.java index 90e6660103a2f..eb0acf33a892c 100644 --- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ChaosContainer.java +++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ChaosContainer.java @@ -63,6 +63,10 @@ protected void beforeStop() { @Override public void stop() { beforeStop(); + doStop(); + } + + protected void doStop() { super.stop(); } diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/PulsarContainer.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/PulsarContainer.java index cc722cc0891f9..b3d6747bf8646 100644 --- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/PulsarContainer.java +++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/PulsarContainer.java @@ -20,11 +20,17 @@ import static java.time.temporal.ChronoUnit.SECONDS; +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; import java.time.Duration; import java.util.Objects; import java.util.UUID; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.pulsar.tests.integration.docker.ContainerExecResult; import org.apache.pulsar.tests.integration.utils.DockerUtils; +import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; @@ -149,6 +155,14 @@ protected void beforeStop() { getContainerId(), "/var/log/pulsar" ); + try { + // stop the "tail -f ..." commands started in afterStart method + // so that shutdown output doesn't clutter logs + execCmd("/usr/bin/pkill", "tail"); + } catch (Exception e) { + // will fail if there's no tail running + log.debug("Cannot run 'pkill tail'", e); + } } } @@ -161,6 +175,28 @@ public void stop() { super.stop(); } + @Override + protected void doStop() { + if (getContainerId() != null) { + if (serviceEntryPoint.equals("bin/pulsar")) { + // attempt graceful shutdown using "docker stop" + dockerClient.stopContainerCmd(getContainerId()) + .withTimeout(15) + .exec(); + } else { + // use "supervisorctl stop all" for graceful shutdown + try { + ContainerExecResult result = execCmd("/usr/bin/supervisorctl", "stop", "all"); + log.info("Stopped supervisor services exit code: {}\nstdout: {}\nstderr: {}", result.getExitCode(), + result.getStdout(), result.getStderr()); + } catch (Exception e) { + log.error("Cannot run 'supervisorctl stop all'", e); + } + } + } + super.doStop(); + } + @Override public String getContainerName() { return clusterName + "-" + hostname; @@ -205,12 +241,52 @@ public void start() { createContainerCmd.withEntrypoint(serviceEntryPoint); }); + if (isCodeCoverageEnabled()) { + configureCodeCoverage(); + } + beforeStart(); super.start(); afterStart(); log.info("[{}] Start pulsar service {} at container {}", getContainerName(), serviceName, getContainerId()); } + protected boolean isCodeCoverageEnabled() { + return Boolean.getBoolean("integrationtest.coverage.enabled"); + } + + protected void configureCodeCoverage() { + File coverageDirectory; + if (System.getProperty("integrationtest.coverage.dir") != null) { + coverageDirectory = new File(System.getProperty("integrationtest.coverage.dir")); + } else { + coverageDirectory = new File("target"); + } + + if (!coverageDirectory.isDirectory()) { + coverageDirectory.mkdirs(); + } + withFileSystemBind(coverageDirectory.getAbsolutePath(), "/jacocoDir", BindMode.READ_WRITE); + + String jacocoVersion = System.getProperty("jacoco.version"); + File jacocoAgentJar = new File(System.getProperty("user.home"), + ".m2/repository/org/jacoco/org.jacoco.agent/" + jacocoVersion + "/" + "org.jacoco.agent-" + + jacocoVersion + "-runtime.jar"); + + if (jacocoAgentJar.isFile()) { + try { + FileUtils.copyFileToDirectory(jacocoAgentJar, coverageDirectory); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + withEnv("OPTS", "-javaagent:/jacocoDir/" + jacocoAgentJar.getName() + + "=destfile=/jacocoDir/jacoco_" + getContainerName() + "_" + System.currentTimeMillis() + ".exec" + + ",includes=org.apache.pulsar.*:org.apache.bookkeeper.mledger.*"); + } else { + log.error("Cannot find jacoco agent jar from '" + jacocoAgentJar.getAbsolutePath() + "'"); + } + } + @Override public boolean equals(Object o) { if (!(o instanceof PulsarContainer)) { diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ZKContainer.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ZKContainer.java index 898e5d241767a..da3fb05a518f4 100644 --- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ZKContainer.java +++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/containers/ZKContainer.java @@ -69,4 +69,9 @@ protected void beforeStop() { ); } } + + @Override + protected boolean isCodeCoverageEnabled() { + return false; + } } diff --git a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/topologies/PulsarCluster.java b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/topologies/PulsarCluster.java index a15a0e56f4afb..fcc0feec6d44f 100644 --- a/tests/integration/src/test/java/org/apache/pulsar/tests/integration/topologies/PulsarCluster.java +++ b/tests/integration/src/test/java/org/apache/pulsar/tests/integration/topologies/PulsarCluster.java @@ -35,7 +35,6 @@ import java.util.Map; import java.util.Objects; import java.util.function.Function; -import java.util.stream.Collectors; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; @@ -369,37 +368,30 @@ public synchronized void stop() { return; } - List containers = new ArrayList<>(); - - containers.addAll(workerContainers.values()); - containers.addAll(brokerContainers.values()); - containers.addAll(bookieContainers.values()); + stopInParallel(workerContainers.values()); if (externalServices != null) { - containers.addAll(externalServices.values()); + stopInParallel(externalServices.values()); } + stopPrestoWorker(); + if (null != proxyContainer) { - containers.add(proxyContainer); + proxyContainer.stop(); } + stopInParallel(brokerContainers.values()); + + stopInParallel(bookieContainers.values()); + if (!sharedCsContainer && null != csContainer) { - containers.add(csContainer); + csContainer.stop(); } if (null != zkContainer) { - containers.add(zkContainer); - } - if (null != prestoWorkerContainer) { - containers.add(prestoWorkerContainer); + zkContainer.stop(); } - containers = containers.parallelStream() - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - containers.parallelStream().forEach(GenericContainer::stop); - try { network.close(); } catch (Exception e) { @@ -407,6 +399,12 @@ public synchronized void stop() { } } + private static void stopInParallel(Collection> containers) { + containers.parallelStream() + .filter(Objects::nonNull) + .forEach(GenericContainer::stop); + } + public void startPrestoWorker() { startPrestoWorker(null, null); }