diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb0de95457..5b8341303b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,10 @@ on: - cron: "0 3 * * 0" workflow_dispatch: +concurrency: # cancel older workflows when a new push is done on a branch + group: \({{ github.workflow }}-\){{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: CI_REGISTRY_IMAGE: ghcr.io/webhare/platform CI_COMMIT_SHA: ${{ github.sha }} diff --git a/.github/workflows/devcontainer.yml b/.github/workflows/devcontainer.yml new file mode 100644 index 0000000000..727215b6bd --- /dev/null +++ b/.github/workflows/devcontainer.yml @@ -0,0 +1,40 @@ +name: WebHare Devcontainer + +on: + schedule: + - cron: "0 4 * * 1-5" + workflow_dispatch: #Note that this won't work until the default branch has devcontainer.yml + push: + branches: #Use feature/devcontainer- branches for development + - feature/devcontainer-* + +concurrency: # cancel older workflows when a new push is done on a branch + group: \({{ github.workflow }}-\){{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + builddocker: + name: Build Docker + # See https://github.com/actions/runner-images + runs-on: ubuntu-26.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Build Docker in devcontainer + run: addons/tests/test-devcontainer-builddocker.sh + + make-install: + name: Make install + # See https://github.com/actions/runner-images + runs-on: ubuntu-26.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Run make install in devcontainer + run: addons/tests/test-devcontainer-make-install.sh diff --git a/.gitignore b/.gitignore index 4afd407cc4..49bc194c59 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,6 @@ /whtree/modules/platform/generated/ /vendor/.*.lock -/vendor/wh-current-emscripten-version # We ignore .vscode as c_cpp_properties.json, launch.json and tasks.json aren't standardized (yet) accross developers /.vscode/* diff --git a/.gitmodules b/.gitmodules index 1a5934d74b..93f56e225c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "vendor/libxml2"] path = vendor/libxml2 url = https://github.com/GNOME/libxml2.git -[submodule "vendor/emsdk"] - path = vendor/emsdk - url = https://github.com/emscripten-core/emsdk.git [submodule "whtree/modules/platform/js/certbot/vendor/acme"] path = whtree/modules/platform/js/certbot/vendor/acme url = https://github.com/WebHare/acme.git diff --git a/addons/docker-build/Dockerfile b/addons/docker-build/Dockerfile index a4e3e267bb..6372d060fb 100644 --- a/addons/docker-build/Dockerfile +++ b/addons/docker-build/Dockerfile @@ -43,12 +43,13 @@ ENV \ WEBHARE_CHECKEDOUT_TO=/opt/wh \ WHBUILD_EMSCRIPTEN_VERSION=$WHBUILD_EMSCRIPTEN_VERSION -# Add vendor stuff (needed for emsdk) +# Add vendor stuff (use to be for emsdk, but we still seem to need it?) COPY vendor/ /opt/wh/vendor/ # Base image setup RUN --mount=type=bind,source=addons/docker-build/setup-base-shared.sh,target=/setup-base-shared.sh \ --mount=type=bind,source=addons/docker-build/setup-builder.sh,target=/setup-builder.sh \ + --mount=type=bind,source=addons/docker-build/setup-emsdk.sh,target=/setup-emsdk.sh \ --mount=type=cache,id=builderdownloads,target=/tmp/downloads \ --mount=type=cache,id=baseimage3,sharing=locked,target=/var/cache/dnf \ /bin/bash /setup-builder.sh # 2024-08-19 @@ -75,7 +76,7 @@ RUN --mount=type=bind,source=/ap,target=/mnt/ap \ RUN --mount=type=tmpfs,target=/opt/whbuild \ --mount=type=tmpfs,target=/tmp \ --mount=type=cache,id=compile,target=/tmp/compile \ - /bin/bash -c ". /opt/wh/vendor/emsdk/emsdk_env.sh && /opt/wh/builder/make.sh install" + /opt/wh/builder/make.sh install ################# STAGE devcontainer @@ -97,14 +98,15 @@ ENV \ # Expose usual WebHare hostingports EXPOSE 13684 -# emscripten, pdfbox and tika installed by makefile (because they write to /opt/wh) +# pdfbox and tika installed by makefile (because they write to /opt/wh) # Base image setup RUN --mount=type=bind,source=addons/docker-build/setup-base-shared.sh,target=/setup-base-shared.sh \ --mount=type=bind,source=addons/docker-build/setup-builder.sh,target=/setup-builder.sh \ + --mount=type=bind,source=addons/docker-build/setup-emsdk.sh,target=/setup-emsdk.sh \ --mount=type=cache,id=builderdownloads,target=/tmp/downloads \ --mount=type=cache,id=baseimage3,sharing=locked,target=/var/cache/dnf \ - /bin/bash /setup-builder.sh --skip-emscripten # 2024-08-19 + /bin/bash /setup-builder.sh # 2024-08-19 ARG WHBUILD_ASSETROOT diff --git a/addons/docker-build/build-functions.sh b/addons/docker-build/build-functions.sh deleted file mode 100644 index a9bf588e2f..0000000000 --- a/addons/docker-build/build-functions.sh +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash diff --git a/addons/docker-build/builddocker.sh b/addons/docker-build/builddocker.sh index c6836c5a8c..8a71f31912 100755 --- a/addons/docker-build/builddocker.sh +++ b/addons/docker-build/builddocker.sh @@ -86,6 +86,14 @@ get_finaltag "${FINALTAGARGS[@]}" list_finaltag if [ -n "$USEPODMAN" ]; then + if ! hash -r podman 2>/dev/null; then + if [ "$WEBHARE_IN_CONTAINER" == "1" ]; then + dnf install -y podman fuse-overlayfs + else + die "Podman not installed on host" + fi + fi + podman -v buildah -v 2>/dev/null || echo "buildah not installed on host" DOCKERBUILDARGS+=(--layers) @@ -112,8 +120,8 @@ fi echo "" echo "Packaging source tree for the WebHare runner" -# Prune empty directories -find "$WEBHARE_CHECKEDOUT_TO" -type d -empty -delete +# Prune empty directories in whtree. The rest is only used in the builder image so not relevant +find "$WEBHARE_CHECKEDOUT_TO"/whtree -type d -empty -delete || true if [ -z "$NOPULL" ]; then DOCKERBUILDARGS+=(--pull) diff --git a/addons/docker-build/run-devcontainer.sh b/addons/docker-build/run-devcontainer.sh index 76dd7ff7df..b335608fed 100755 --- a/addons/docker-build/run-devcontainer.sh +++ b/addons/docker-build/run-devcontainer.sh @@ -4,9 +4,14 @@ set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1 +# To reduce interference when sharing a wh tree, isolate currentinstall (multiple WHs will write to it) and isolate node_modules (mac&linux require different binaries) + podman run \ --rm \ --privileged \ -ti \ -v "$(pwd)/../..":/opt/wh \ - localhost/webhare/platform:devcontainer + -v "devcontainer-currentinstall":/opt/wh/whtree/currentinstall \ + -v "devcontainer-node_modules":/opt/wh/whtree/node_modules \ + localhost/webhare/platform:devcontainer \ + "$@" diff --git a/addons/docker-build/setup-base-shared.sh b/addons/docker-build/setup-base-shared.sh index bd3749bd7b..c538880233 100644 --- a/addons/docker-build/setup-base-shared.sh +++ b/addons/docker-build/setup-base-shared.sh @@ -1,5 +1,6 @@ # shellcheck shell=bash +######################################## POSTGRES # postgres key & repository - https://www.postgresql.org/download/linux/redhat/ dnf install -y "https://download.postgresql.org/pub/repos/yum/reporpms/EL-10-$(uname -m)/pgdg-redhat-repo-latest.noarch.rpm" diff --git a/addons/docker-build/setup-builder.sh b/addons/docker-build/setup-builder.sh index 0421940c37..7d89281ef2 100755 --- a/addons/docker-build/setup-builder.sh +++ b/addons/docker-build/setup-builder.sh @@ -17,18 +17,6 @@ # Fail on any error set -eo pipefail -SKIP_EMSCRIPTEN= -while [[ $1 =~ ^-.* ]]; do - if [ "$1" == "--skip-emscripten" ]; then - SKIP_EMSCRIPTEN=1 - else - echo "Illegal option $1" - exit 1 - fi - shift -done - - if [ -z "$WHBUILD_DOWNLOADCACHE" ]; then echo WHBUILD_DOWNLOADCACHE not set exit 1 @@ -77,14 +65,4 @@ PACKAGES=( dnf install -y "${PACKAGES[@]}" source "${BASH_SOURCE%/*}/setup-base-shared.sh" - -if [ -z "$SKIP_EMSCRIPTEN" ]; then - if [ -z "$WHBUILD_EMSCRIPTEN_VERSION" ]; then - echo "WHBUILD_EMSCRIPTEN_VERSION not set" - exit 1; - fi - - /opt/wh/vendor/emsdk/emsdk install "$WHBUILD_EMSCRIPTEN_VERSION" - /opt/wh/vendor/emsdk/emsdk activate "$WHBUILD_EMSCRIPTEN_VERSION" - echo "$WHBUILD_EMSCRIPTEN_VERSION" > /opt/wh/vendor/wh-current-emscripten-version -fi +"${BASH_SOURCE%/*}/setup-emsdk.sh" diff --git a/addons/docker-build/setup-emsdk.sh b/addons/docker-build/setup-emsdk.sh new file mode 100755 index 0000000000..39a9dce252 --- /dev/null +++ b/addons/docker-build/setup-emsdk.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -eo pipefail + +if [ -z "$WHBUILD_EMSCRIPTEN_VERSION" ]; then + echo "WHBUILD_EMSCRIPTEN_VERSION not set" + exit 1; +fi +if [ -z "$WEBHARE_BUILDDIR" ]; then + echo "WEBHARE_BUILDDIR not set" + exit 1 +fi + +if [ "$WEBHARE_IN_CONTAINER" == "1" ]; then + WHBUILD_EMSDK_ROOT="/opt/emsdk" +else + WHBUILD_EMSDK_ROOT="$WEBHARE_BUILDDIR/emsdk" +fi + +VERSIONFILE="$WHBUILD_EMSDK_ROOT/current-emscripten-version" + +if [ "$WHBUILD_EMSCRIPTEN_VERSION" != "$(cat "$VERSIONFILE" 2> /dev/null || true)" ]; then + # maybe toplevel should set a WHBUILD_VENDORDIR, poiting to BUILDDIR on Mac but /opt/ in containers + + if [ -d "$WHBUILD_EMSDK_ROOT/.git" ]; then + git -C "$WHBUILD_EMSDK_ROOT" pull + else + git clone https://github.com/emscripten-core/emsdk.git "$WHBUILD_EMSDK_ROOT" + fi + + cd "$WHBUILD_EMSDK_ROOT" + + "$WHBUILD_EMSDK_ROOT/emsdk" install "$WHBUILD_EMSCRIPTEN_VERSION" + "$WHBUILD_EMSDK_ROOT/emsdk" activate "$WHBUILD_EMSCRIPTEN_VERSION" + + echo "$WHBUILD_EMSCRIPTEN_VERSION" > "$VERSIONFILE" +fi diff --git a/addons/tests/test-devcontainer-builddocker.sh b/addons/tests/test-devcontainer-builddocker.sh new file mode 100755 index 0000000000..6a6aeb9c95 --- /dev/null +++ b/addons/tests/test-devcontainer-builddocker.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")"/../.. || exit 1 + +addons/docker-build/build-devcontainer.sh +addons/docker-build/run-devcontainer.sh wh builddocker --podman --build-arg --net=host diff --git a/addons/tests/test-devcontainer-make-install.sh b/addons/tests/test-devcontainer-make-install.sh new file mode 100755 index 0000000000..8bcfe6a874 --- /dev/null +++ b/addons/tests/test-devcontainer-make-install.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")"/../.. || exit 1 + +addons/docker-build/build-devcontainer.sh +addons/docker-build/run-devcontainer.sh wh make install diff --git a/builder/base_makefile b/builder/base_makefile index 2aa3d03563..996cd2952a 100644 --- a/builder/base_makefile +++ b/builder/base_makefile @@ -212,7 +212,7 @@ DRAWLIB_STATIC_LIBS= DRAWLIB_BASE_LIBS+=jpeg EMCC?=emcc -EMSCRIPTEN_VERSION_FILE := $(SRCDIR)/vendor/wh-current-emscripten-version +EMSCRIPTEN_VERSION_FILE := $(WHBUILD_EMSDK_ROOT)/current-emscripten-version ifeq ($(BUILDSYSTEM),gcc) ifeq ($(CXX),clang++) diff --git a/builder/make.sh b/builder/make.sh index 5de5b66bcb..ce38252aee 100755 --- a/builder/make.sh +++ b/builder/make.sh @@ -142,28 +142,33 @@ if [ -z "$WEBHARE_IN_DOCKER" ] || [ -n "$WHBUILD_DEVCONTAINER" ]; then # Not a d if ! /bin/bash "$WEBHARE_CHECKEDOUT_TO/addons/docker-build/setup-tika.sh" "$WHBUILD_ASSETROOT" 3.3.0; then echo "setup-tika failed" fi - rm -rf "$WEBHARE_CHECKEDOUT_TO/whtree/modules/system/data/engines" fi -# Is emsdk installed? -if [ -z "$WEBHARE_IN_DOCKER" ] || [ -n "$WHBUILD_DEVCONTAINER" ]; then - [ -x "$WEBHARE_CHECKEDOUT_TO/vendor/emsdk/emsdk" ] || git -C "$WEBHARE_CHECKEDOUT_TO" submodule update --init --recursive - [ -x "$WEBHARE_CHECKEDOUT_TO/vendor/emsdk/emsdk" ] || die "Submodule vendor/emsdk not present" - # TODO skip if already activated. need to support version checks then - # TODO can we ensure wasm-clean is invoked (ideally set a proper dep) whenever emsdk is updated? - - if [ "$WHBUILD_EMSCRIPTEN_VERSION" != "$(cat "$WEBHARE_CHECKEDOUT_TO/vendor/wh-current-emscripten-version" 2> /dev/null)" ]; then - "$WEBHARE_CHECKEDOUT_TO/vendor/emsdk/emsdk" install "$WHBUILD_EMSCRIPTEN_VERSION" - "$WEBHARE_CHECKEDOUT_TO/vendor/emsdk/emsdk" activate "$WHBUILD_EMSCRIPTEN_VERSION" - echo "$WHBUILD_EMSCRIPTEN_VERSION" > "$WEBHARE_CHECKEDOUT_TO/vendor/wh-current-emscripten-version" - fi +# Remove old version file (2026-09-24) +if [ -f "$WEBHARE_CHECKEDOUT_TO/vendor/wh-current-emscripten-version" ]; then + rm "$WEBHARE_CHECKEDOUT_TO/vendor/wh-current-emscripten-version" + rm -rf "$WEBHARE_CHECKEDOUT_TO/vendor/emsdk" +fi - if [ -z "$DEBUGMAKE" ] && [ -z "$EMSDK_QUIET" ]; then - export EMSDK_QUIET=1 - fi - source "$WEBHARE_CHECKEDOUT_TO/vendor/emsdk/emsdk_env.sh" +# ============ emsdk installation & configuration ===================== +# TODO can we ensure wasm-clean is invoked (ideally set a proper dep) whenever emsdk is updated? +# let emsdk check versions and upgrade if needed. note that addons/ is not present in the build steps of +[ -f "$WEBHARE_CHECKEDOUT_TO"/addons/docker-build/setup-emsdk.sh ] && "$WEBHARE_CHECKEDOUT_TO"/addons/docker-build/setup-emsdk.sh + +if [ -z "$DEBUGMAKE" ] && [ -z "$EMSDK_QUIET" ]; then + export EMSDK_QUIET=1 fi +if [ "$WEBHARE_IN_CONTAINER" == "1" ]; then + WHBUILD_EMSDK_ROOT="/opt/emsdk" +else + WHBUILD_EMSDK_ROOT="$WEBHARE_BUILDDIR/emsdk" +fi +export WHBUILD_EMSDK_ROOT + +# shellcheck disable=SC1091 +source "$WHBUILD_EMSDK_ROOT/emsdk_env.sh" + # Convert version number to 5 digit style used in C++/HareScript (GetWebHareVersionNumber) if [[ $WEBHARE_VERSION =~ ^([0-9]{1})\.([0-9]{1,2})\.([0-9]{1,2})$ ]]; then VERSIONMAJOR="${BASH_REMATCH[1]}" diff --git a/doc/from-source.md b/doc/from-source.md index 38b8075dca..d1b5cc6fdd 100644 --- a/doc/from-source.md +++ b/doc/from-source.md @@ -69,12 +69,21 @@ If you're getting an error that openjdk isn't notarized, you can go to System Pr "Allow anyway" on the General tab to enable it. ## Build using devcontainer & podman +The devcontainer can be used to build WebHare container images + ```bash -wh builddocker --podman --devcontainer -podman run --rm -ti -v ~/projects/webhare:/opt/wh --device /dev/fuse --net host --privileged localhost/webhare/platform:developcontainer /bin/bash -wh builddocker --podman +addons/docker-build/build-devcontainer.sh +addons/docker-build/run-devcontainer.sh +wh builddocker --podman --build-arg --net=host ``` +or to build WebHare from source + +```bash +addons/docker-build/build-devcontainer.sh +addons/docker-build/run-devcontainer.sh +wh make install +``` ## Building for docker ```bash diff --git a/vendor/emsdk b/vendor/emsdk deleted file mode 160000 index 15915cad55..0000000000 --- a/vendor/emsdk +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 15915cad554b707837024dc2758b6a1c5b94b036 diff --git a/whtree/modules/consilio/lib/whfscatalog.whlib b/whtree/modules/consilio/lib/whfscatalog.whlib index 0d6ce3dc28..daef093651 100644 --- a/whtree/modules/consilio/lib/whfscatalog.whlib +++ b/whtree/modules/consilio/lib/whfscatalog.whlib @@ -11,6 +11,7 @@ LOADLIB "wh::util/algorithms.whlib"; LOADLIB "mod::consilio/lib/api.whlib"; LOADLIB "mod::consilio/lib/catalogs.whlib"; +LOADLIB "mod::system/lib/services.whlib"; LOADLIB "mod::system/lib/internal/webhareconstants.whlib"; @@ -34,7 +35,6 @@ INTEGER ARRAY FUNCTION GetIndexedWHFSObjectsForFolder(INTEGER folderid) */ PUBLIC MACRO ReindexWHFSChanges(RECORD ARRAY to_reindex, RECORD options DEFAULTSTO DEFAULT RECORD) { - RECORD ARRAY results; options := ValidateOptions([ __eventid := "", __debug := FALSE, __progress := FALSE, refresh := TRUE ], options); IF(NOT ObjectExists(publisher_fsobjects_source)) @@ -78,11 +78,16 @@ PUBLIC MACRO ReindexWHFSChanges(RECORD ARRAY to_reindex, RECORD options DEFAULTS IF (options.__debug) Print(`To update: ${EncodeJSON(to_update)}\nTo delete: ${EncodeJSON(to_delete)}\n`); + IF (IsDebugTagEnabled("consilio:whfscatalog")) + LogDebug("consilio:whfscatalog", "ReindexWHFSChanges", CELL[ to_update, to_delete ]); DATETIME now := GetCurrentDateTime(); FOREVERY (INTEGER objid FROM to_delete) { - publisher_fsobjects_source->DeleteGroup("fsobj_" || objid, [ foreground := TRUE ]); + TRY + publisher_fsobjects_source->DeleteGroup("fsobj_" || objid, [ foreground := TRUE ]); + CATCH (OBJECT e) + LogHareScriptException(e, [ info := [ context := "consilio:whfscatalog", to_delete := objid ] ]); IF(options.__progress) Print(`Deleting ${#objid+1}/${Length(to_delete)}: #${objid}\r`); } @@ -91,15 +96,14 @@ PUBLIC MACRO ReindexWHFSChanges(RECORD ARRAY to_reindex, RECORD options DEFAULTS FOREVERY (INTEGER objid FROM to_update) { - publisher_fsobjects_source->ReindexGroup("fsobj_" || objid, [ foreground := TRUE ]); + TRY + publisher_fsobjects_source->ReindexGroup("fsobj_" || objid, [ foreground := TRUE ]); + CATCH (OBJECT e) + LogHareScriptException(e, [ info := [ context := "consilio:whfscatalog", to_update := objid ] ]); IF(options.__progress) Print(`Updating ${#objid+1}/${Length(to_update)}: #${objid}\r`); } - // Sort the results: first the requested ids in the order they're supplied, then other ids sorted ascending - INTEGER ARRAY orgids := SELECT AS INTEGER ARRAY id FROM to_reindex; - results := SELECT * FROM results ORDER BY SearchElement(orgids, objid) + 1 ?? objid; - IF(options.__progress AND Length(to_update) > 0) Print(`\n`); diff --git a/whtree/modules/publisher/scripts/internal/consiliohandler.whscr b/whtree/modules/publisher/scripts/internal/consiliohandler.whscr index 0da684e715..79e132a1f2 100644 --- a/whtree/modules/publisher/scripts/internal/consiliohandler.whscr +++ b/whtree/modules/publisher/scripts/internal/consiliohandler.whscr @@ -103,6 +103,8 @@ MACRO OnFolderEvent(STRING event, RECORD ARRAY messages) MACRO OnIndexRequest(STRING event, RECORD ARRAY msgs) { + IF (IsDebugTagEnabled("consilio:whfscatalog")) + LogDebug("consilio:whfscatalog", "OnIndexRequest", CELL[ event, msgs ]); PrintDebug("Got index request '" || event || "'"); EnsurePublisherWHFSIndex(); diff --git a/whtree/modules/system/lib/internal/cluster/logwriter.whlib b/whtree/modules/system/lib/internal/cluster/logwriter.whlib index 458ccfb38f..29ea82dec1 100644 --- a/whtree/modules/system/lib/internal/cluster/logwriter.whlib +++ b/whtree/modules/system/lib/internal/cluster/logwriter.whlib @@ -1,7 +1,6 @@ reg.asynccontext) this->reg.callback(rec.event, rec.msgs); + CATCH (OBJECT e) + LogNoticeException("script-error", "", e, DEFAULT RECORD); FINALLY __internal_forbidden_broadcasts := oldlist; } diff --git a/whtree/modules/webhare_testsuite/lib/webservicetest.whlib b/whtree/modules/webhare_testsuite/lib/webservicetest.whlib index c3e207cfee..a5d4d2d4ac 100644 --- a/whtree/modules/webhare_testsuite/lib/webservicetest.whlib +++ b/whtree/modules/webhare_testsuite/lib/webservicetest.whlib @@ -103,6 +103,7 @@ PUBLIC RECORD FUNCTION RPC_CrashTest(STRING type) { CASE "abort" { ABORT("boem"); } CASE "throw" { THROW NEW Exception("boem"); } + CASE "invalidargs" { THROW NEW RPCInvalidArgsException("boem"); } CASE "terminate" { TerminateScript(); } } ABORT("Unknown abort type '" || type || "'"); diff --git a/whtree/modules/webhare_testsuite/tests/baselibs/hsengine/test_ipc.whscr b/whtree/modules/webhare_testsuite/tests/baselibs/hsengine/test_ipc.whscr index a50f62f98f..7ef4398c9a 100644 --- a/whtree/modules/webhare_testsuite/tests/baselibs/hsengine/test_ipc.whscr +++ b/whtree/modules/webhare_testsuite/tests/baselibs/hsengine/test_ipc.whscr @@ -140,6 +140,9 @@ MACRO OnEventCallbackS(STRING event, RECORD data) MACRO OnEventCallbackM(STRING event, RECORD ARRAY data) { INSERT [ type := "event-multiple", event := event, data := data ] INTO cbs AT END; + FOREVERY (RECORD rec FROM data) + IF (CellExists(rec, "EXC")) + THROW NEW Exception(rec.exc); } MACRO OnHandleCallback(INTEGER handle, OBJECT port) @@ -230,6 +233,24 @@ MACRO CallbackTest() UnregisterCallback(cbhandle); DoCallbackHandling(AddTimeToDate(250, GetCurrentDateTime())); TestEQ(DEFAULT RECORD ARRAY, cbs); + + // STORY: exception broke callback handler + cbhandle := RegisterMultiEventCallback("hs:test", PTR OnEventCallbackM); + RawBroadcastEvent("hs:test", [ a := 1 ]); + DoCallbackHandling(AddTimeToDate(250, GetCurrentDateTime())); + RawBroadcastEvent("hs:test", [ exc := "test exception" ]); + DoCallbackHandling(AddTimeToDate(250, GetCurrentDateTime())); + TestEQ([ [ type := "event-multiple", event := "hs:test", data := [ [ a := 1] ] ] + , [ type := "event-multiple", event := "hs:test", data := [ [ exc := "test exception" ] ] ] + ], cbs); + RawBroadcastEvent("hs:test", [ a := 2 ]); + DoCallbackHandling(AddTimeToDate(250, GetCurrentDateTime())); + TestEQ([ [ type := "event-multiple", event := "hs:test", data := [ [ a := 1] ] ] + , [ type := "event-multiple", event := "hs:test", data := [ [ exc := "test exception" ] ] ] + , [ type := "event-multiple", event := "hs:test", data := [ [ a := 2] ] ] + ], cbs); + UnregisterCallback(cbhandle); + cbs := DEFAULT RECORD ARRAY; } MACRO ImmediateBroadcastCallbackTest() diff --git a/whtree/modules/webhare_testsuite/tests/wh/webserver/remoting/test_jsonrpc.whscr b/whtree/modules/webhare_testsuite/tests/wh/webserver/remoting/test_jsonrpc.whscr index b03540ff66..9454121eb8 100644 --- a/whtree/modules/webhare_testsuite/tests/wh/webserver/remoting/test_jsonrpc.whscr +++ b/whtree/modules/webhare_testsuite/tests/wh/webserver/remoting/test_jsonrpc.whscr @@ -1,6 +1,7 @@ browser->GetHTTPStatusCode()); } +MACRO TestInvalidArgs() +{ + RECORD port := testfw->GetLocalhostWebinterface(); + STRING url := "http://127.0.0.1:" || port.portnumber || "/wh_services/webhare_testsuite/testnoauth"; + BLOB request := StringToBlob(EncodeJSON([method:="crashtest", params:=["invalidargs"], id:=5])); + RECORD ARRAY headers := + [ [ field := "Content-Type", value := "application/json" ] + ]; + + //testfw->browser has the 'etr' debug flag set. The trace should still be hidden + TestEq(FALSE, testfw->browser->PostWebPageBlob(url, headers, request)); + TestEq(400, testfw->browser->GetHTTPStatusCode()); + TestEq(FALSE, RecordExists(DecodeJSONBlob(testfw->browser->content).error.data)); + + //A browser without the 'etr' debug flag should get a 400 too + OBJECT browser := NEW WebBrowser; + TestEq(FALSE, browser->PostWebPageBlob(url, headers, request)); + TestEq(400, browser->GetHTTPStatusCode()); + browser->Close(); +} + MACRO TestJSONRPC() { RECORD port := testfw->GetLocalhostWebinterface(); @@ -166,6 +188,7 @@ MACRO TestOrigin() } RunTestFramework([ PTR TestBadRequest + , PTR TestInvalidArgs , PTR TestJSONRPC , PTR TestOrigin , PTR TestJSONRPC_JS