This is an automated email from the ASF dual-hosted git repository.

sergehuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/master by this push:
     new 796a80c98 UNOMI-937: Stabilize integration tests and align CI with 
build.sh (#764)
796a80c98 is described below

commit 796a80c988c6a44c61195d9b29e954cc16d27527
Author: Serge Huber <[email protected]>
AuthorDate: Thu May 28 10:37:21 2026 +0200

    UNOMI-937: Stabilize integration tests and align CI with build.sh (#764)
---
 .github/workflows/unomi-ci-build-tests.yml         | 20 ++++---
 build.sh                                           | 65 ++++++++++++++++------
 .../test/java/org/apache/unomi/itests/BaseIT.java  |  8 +++
 .../test/java/org/apache/unomi/itests/PatchIT.java | 28 +++++++---
 .../unomi/itests/PropertiesUpdateActionIT.java     |  6 +-
 .../apache/unomi/itests/graphql/GraphQLListIT.java | 31 ++++++++---
 setenv.sh                                          |  9 ++-
 7 files changed, 121 insertions(+), 46 deletions(-)

diff --git a/.github/workflows/unomi-ci-build-tests.yml 
b/.github/workflows/unomi-ci-build-tests.yml
index e629253cd..2533a8b23 100644
--- a/.github/workflows/unomi-ci-build-tests.yml
+++ b/.github/workflows/unomi-ci-build-tests.yml
@@ -31,7 +31,7 @@ jobs:
         sudo apt-get install -y graphviz
         dot -V
     - name: Build and Unit tests
-      run: mvn -U -ntp -e clean install
+      run: ./build.sh --ci
 
   integration-tests:
     name: Execute integration tests
@@ -54,16 +54,22 @@ jobs:
           distribution: 'temurin'
           java-version: '17'
           cache: 'maven'
+      - name: Install GraphViz
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y graphviz
+          dot -V
       - name: Integration tests
+        env:
+          MAVEN_EXTRA_OPTS: >-
+            -Dopensearch.port=${{ matrix.port }}
+            -Delasticsearch.port=${{ matrix.port }}
         run: |
-          FLAGS="-Pintegration-tests"
           if [ "${{ matrix.search-engine }}" = "opensearch" ]; then
-            # Trigger OpenSearch profile activation via property; do not pass 
any -P profile toggles
-            FLAGS="$FLAGS -Duse.opensearch=true"
+            ./build.sh --ci --integration-tests --use-opensearch
+          else
+            ./build.sh --ci --integration-tests
           fi
-          mvn -ntp clean install $FLAGS \
-            -Dopensearch.port=${{ matrix.port }} \
-            -Delasticsearch.port=${{ matrix.port }}
       - name: Archive code coverage logs
         uses: actions/upload-artifact@v4
         if: false # UNOMI-746 Reactivate if necessary
diff --git a/build.sh b/build.sh
index 19dd5d0f6..e6f1ae619 100755
--- a/build.sh
+++ b/build.sh
@@ -19,15 +19,13 @@
 
################################################################################
 
 set -e  # Exit on error
-trap 'handle_error $? $LINENO $BASH_LINENO "$BASH_COMMAND" $(printf "::%s" 
${FUNCNAME[@]:-})' ERR
+# Keep trap arguments small: passing full $BASH_COMMAND can exceed ARG_MAX 
after a failed mvn invocation.
+trap 'handle_error $? $LINENO' ERR
 
 # Error handling function
 handle_error() {
     local exit_code=$1
     local line_no=$2
-    local bash_lineno=$3
-    local last_command=$4
-    local func_trace=$5
 
     cat << "EOF"
      _____ ____  ____   ___  ____
@@ -38,12 +36,8 @@ handle_error() {
 
 EOF
     echo "Error occurred in:"
-    echo "  Command: $last_command"
     echo "  Line: $line_no"
     echo "  Exit code: $exit_code"
-    if [ ! -z "$func_trace" ]; then
-        echo "  Function trace: $func_trace"
-    fi
     exit $exit_code
 }
 
@@ -222,13 +216,23 @@ print_progress() {
     fi
 }
 
+# Non-interactive when run from CI or when explicitly requested (e.g. GitHub 
Actions).
+is_non_interactive() {
+    [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ] || [ 
"${BUILD_NON_INTERACTIVE:-}" = "true" ]
+}
+
 # Function to prompt for continuation
 prompt_continue() {
     local prompt_text="$1"
     if [ -z "$prompt_text" ]; then
         prompt_text="Continue?"
     fi
-    
+
+    if is_non_interactive; then
+        print_status "info" "Non-interactive mode: continuing ($prompt_text)"
+        return 0
+    fi
+
     read -p "$prompt_text (y/N) " -n 1 -r
     echo
     if [[ ! $REPLY =~ ^[Yy]$ ]]; then
@@ -296,6 +300,7 @@ EOF
         echo -e "  ${CYAN}--it-debug-port PORT${NC}       Set integration test 
debug port"
         echo -e "  ${CYAN}--it-debug-suspend${NC}         Suspend integration 
test until debugger connects"
         echo -e "  ${CYAN}--skip-migration-tests${NC}     Skip 
migration-related tests"
+        echo -e "  ${CYAN}--ci${NC}                       CI mode: no Karaf, 
no Maven cache, Maven -B -ntp, non-interactive"
     else
         cat << "EOF"
      _    _ _____ _      ____
@@ -329,6 +334,7 @@ EOF
         echo "  --it-debug-port PORT      Set integration test debug port"
         echo "  --it-debug-suspend        Suspend integration test until 
debugger connects"
         echo "  --skip-migration-tests    Skip migration-related tests"
+        echo "  --ci                      CI mode: no Karaf, no Maven cache, 
Maven -B -ntp, non-interactive"
     fi
 
     echo
@@ -459,6 +465,11 @@ while [ "$1" != "" ]; do
         --skip-migration-tests)
             SKIP_MIGRATION_TESTS=true
             ;;
+        --ci)
+            NO_KARAF=true
+            USE_MAVEN_CACHE=false
+            BUILD_NON_INTERACTIVE=true
+            ;;
         *)
             echo "Unknown option: $1"
             usage
@@ -770,6 +781,11 @@ check_requirements() {
 MVN_CMD="mvn"
 MVN_OPTS=""
 
+# CI / non-interactive: no download progress UI, batch mode (matches former 
workflow mvn -ntp)
+if is_non_interactive; then
+    MVN_OPTS="$MVN_OPTS -B -ntp"
+fi
+
 # Add Maven debug option
 if [ "$MAVEN_DEBUG" = true ]; then
     MVN_OPTS="$MVN_OPTS -X"
@@ -784,10 +800,14 @@ if [ "$MAVEN_OFFLINE" = true ]; then
     # Warn if purge cache is enabled with offline mode
     if [ "$PURGE_MAVEN_CACHE" = true ]; then
         echo "Warning: Purging Maven cache while in offline mode may cause 
build failures"
-        read -p "Continue anyway? (y/N) " -n 1 -r
-        echo
-        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
-            exit 1
+        if is_non_interactive; then
+            print_status "warning" "Non-interactive mode: continuing despite 
purge + offline"
+        else
+            read -p "Continue anyway? (y/N) " -n 1 -r
+            echo
+            if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+                exit 1
+            fi
         fi
     fi
 fi
@@ -797,13 +817,22 @@ if [ "$USE_MAVEN_CACHE" = false ]; then
     MVN_OPTS="$MVN_OPTS -Dmaven.build.cache.enabled=false"
 fi
 
+# Extra Maven options (e.g. CI matrix ports: -Delasticsearch.port=9400)
+if [ -n "${MAVEN_EXTRA_OPTS:-}" ]; then
+    MVN_OPTS="$MVN_OPTS $MAVEN_EXTRA_OPTS"
+fi
+
 # Verify Maven settings
 if [ ! -f ~/.m2/settings.xml ]; then
     echo "Warning: Maven settings.xml not found at ~/.m2/settings.xml"
-    read -p "Continue anyway? (y/N) " -n 1 -r
-    echo
-    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
-        exit 1
+    if is_non_interactive; then
+        print_status "info" "Non-interactive mode: continuing without 
~/.m2/settings.xml"
+    else
+        read -p "Continue anyway? (y/N) " -n 1 -r
+        echo
+        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+            exit 1
+        fi
     fi
 fi
 
@@ -900,6 +929,7 @@ if [ "$HAS_COLORS" -eq 1 ]; then
 else
     echo "Running: $MVN_CMD clean $MVN_OPTS"
 fi
+# shellcheck disable=SC2086
 $MVN_CMD clean $MVN_OPTS || {
     print_status "error" "Maven clean failed"
     exit 1
@@ -911,6 +941,7 @@ if [ "$HAS_COLORS" -eq 1 ]; then
 else
     echo "Running: $MVN_CMD install $MVN_OPTS"
 fi
+# shellcheck disable=SC2086
 $MVN_CMD install $MVN_OPTS || {
     print_status "error" "Maven install failed"
     exit 1
diff --git a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java 
b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
index 1c1bd6f8c..676639b0d 100644
--- a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
@@ -467,6 +467,14 @@ public abstract class BaseIT extends KarafTestSupport {
         return value;
     }
 
+    protected void waitForProfileProperty(String profileId, String 
propertyName, Object expected)
+            throws InterruptedException {
+        keepTrying("Profile " + profileId + " property " + propertyName + " 
not updated",
+                () -> profileService.load(profileId),
+                profile -> profile != null && 
java.util.Objects.equals(expected, profile.getProperty(propertyName)),
+                DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+    }
+
     protected <T> void waitForNullValue(String failMessage, Supplier<T> call, 
int timeout, int retries) throws InterruptedException {
         int count = 0;
         while (call.get() != null) {
diff --git a/itests/src/test/java/org/apache/unomi/itests/PatchIT.java 
b/itests/src/test/java/org/apache/unomi/itests/PatchIT.java
index 098a03ad2..828262ccc 100644
--- a/itests/src/test/java/org/apache/unomi/itests/PatchIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/PatchIT.java
@@ -38,7 +38,7 @@ public class PatchIT extends BaseIT {
     private Logger LOGGER = LoggerFactory.getLogger(PatchIT.class);
 
     @Test
-    public void testPatch() throws IOException {
+    public void testPatch() throws IOException, InterruptedException {
         PropertyType company = profileService.getPropertyType("company");
 
         try {
@@ -49,7 +49,10 @@ public class PatchIT extends BaseIT {
 
             profileService.refresh();
 
-            newCompany = profileService.getPropertyType("company");
+            newCompany = keepTrying("Failed waiting for patched property type",
+                    () -> profileService.getPropertyType("company"),
+                    pt -> pt != null && "foo".equals(pt.getDefaultValue()),
+                    DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
             Assert.assertEquals("foo", newCompany.getDefaultValue());
         } finally {
             profileService.setPropertyType(company);
@@ -57,7 +60,7 @@ public class PatchIT extends BaseIT {
     }
 
     @Test
-    public void testOverride() throws IOException {
+    public void testOverride() throws IOException, InterruptedException {
         PropertyType gender = profileService.getPropertyType("gender");
 
         try {
@@ -68,7 +71,10 @@ public class PatchIT extends BaseIT {
 
             profileService.refresh();
 
-            newGender = profileService.getPropertyType("gender");
+            newGender = keepTrying("Failed waiting for patched property type",
+                    () -> profileService.getPropertyType("gender"),
+                    pt -> pt != null && "foo".equals(pt.getDefaultValue()),
+                    DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
             Assert.assertEquals("foo", newGender.getDefaultValue());
         } finally {
             profileService.setPropertyType(gender);
@@ -86,8 +92,8 @@ public class PatchIT extends BaseIT {
 
             profileService.refresh();
 
-            PropertyType newIncome = profileService.getPropertyType("income");
-            Assert.assertNull(newIncome);
+            waitForNullValue("Failed waiting for property type removal",
+                    () -> profileService.getPropertyType("income"), 
DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
         } finally {
             profileService.setPropertyType(income);
         }
@@ -105,7 +111,10 @@ public class PatchIT extends BaseIT {
 
             definitionsService.refresh();
 
-            ConditionType newFormCondition = 
definitionsService.getConditionType("formEventCondition");
+            ConditionType newFormCondition = keepTrying("Failed waiting for 
patched condition type",
+                    () -> 
definitionsService.getConditionType("formEventCondition"),
+                    ct -> ct != null && 
!ct.getMetadata().getSystemTags().contains("profileTags"),
+                    DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
             
Assert.assertFalse(newFormCondition.getMetadata().getSystemTags().contains("profileTags"));
         } finally {
             definitionsService.setConditionType(formCondition);
@@ -124,7 +133,10 @@ public class PatchIT extends BaseIT {
 
             definitionsService.refresh();
 
-            ActionType newMailAction = 
definitionsService.getActionType("sendMailAction");
+            ActionType newMailAction = keepTrying("Failed waiting for patched 
action type",
+                    () -> definitionsService.getActionType("sendMailAction"),
+                    at -> at != null && 
!at.getMetadata().getSystemTags().contains("availableToEndUser"),
+                    DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
             
Assert.assertFalse(newMailAction.getMetadata().getSystemTags().contains("availableToEndUser"));
         } finally {
             definitionsService.setActionType(mailAction);
diff --git 
a/itests/src/test/java/org/apache/unomi/itests/PropertiesUpdateActionIT.java 
b/itests/src/test/java/org/apache/unomi/itests/PropertiesUpdateActionIT.java
index a1e340680..1bc731e42 100644
--- a/itests/src/test/java/org/apache/unomi/itests/PropertiesUpdateActionIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/PropertiesUpdateActionIT.java
@@ -97,11 +97,12 @@ public class PropertiesUpdateActionIT extends BaseIT {
         LOGGER.info("Changes of the event : {}", changes);
 
         Assert.assertTrue(changes > 0);
+        // Current profile on the event is updated in memory; do not poll 
persistence here.
         Assert.assertEquals("UPDATED FIRST NAME CURRENT PROFILE", 
profile.getProperty("firstName"));
     }
 
     @Test
-    public void testUpdateProperties_NotCurrentProfile() {
+    public void testUpdateProperties_NotCurrentProfile() throws 
InterruptedException {
         Profile profile = profileService.load(PROFILE_TARGET_TEST_ID);
         Profile profileToUpdate = profileService.load(PROFILE_TEST_ID);
         Assert.assertNull(profileToUpdate.getProperty("firstName"));
@@ -117,8 +118,7 @@ public class PropertiesUpdateActionIT extends BaseIT {
         updateProperties.setProperty(UpdatePropertiesAction.TARGET_TYPE_KEY, 
"profile");
         eventService.send(updateProperties);
 
-        profileToUpdate = profileService.load(PROFILE_TEST_ID);
-        Assert.assertEquals("UPDATED FIRST NAME", 
profileToUpdate.getProperty("firstName"));
+        waitForProfileProperty(PROFILE_TEST_ID, "firstName", "UPDATED FIRST 
NAME");
     }
 
     @Test
diff --git 
a/itests/src/test/java/org/apache/unomi/itests/graphql/GraphQLListIT.java 
b/itests/src/test/java/org/apache/unomi/itests/graphql/GraphQLListIT.java
index 96a6eb986..139c19063 100644
--- a/itests/src/test/java/org/apache/unomi/itests/graphql/GraphQLListIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/graphql/GraphQLListIT.java
@@ -77,15 +77,28 @@ public class GraphQLListIT extends BaseGraphQLIT {
 
             refreshPersistence(UserList.class);
 
-            Thread.sleep(6000);
-
-            try (CloseableHttpResponse response = 
post("graphql/list/find-lists.json")) {
-                final ResponseContext context = 
ResponseContext.parse(response.getEntity());
-
-                Assert.assertEquals(1, ((Integer) 
context.getValue("data.cdp.findLists.totalCount")).intValue());
-                Assert.assertEquals("testListId", 
context.getValue("data.cdp.findLists.edges[0].node.id"));
-                Assert.assertEquals(profile.getItemId(), 
context.getValue("data.cdp.findLists.edges[0].node.active.edges[0].node.cdp_profileIDs[0].id"));
-            }
+            final ResponseContext findListsContext = keepTrying("Failed 
waiting for profile in list query",
+                    () -> {
+                        try (CloseableHttpResponse response = 
post("graphql/list/find-lists.json")) {
+                            return ResponseContext.parse(response.getEntity());
+                        } catch (Exception e) {
+                            return null;
+                        }
+                    },
+                    context -> {
+                        if (context == null) {
+                            return false;
+                        }
+                        Integer totalCount = (Integer) 
context.getValue("data.cdp.findLists.totalCount");
+                        if (totalCount == null || totalCount != 1) {
+                            return false;
+                        }
+                        Object profileId = 
context.getValue("data.cdp.findLists.edges[0].node.active.edges[0].node.cdp_profileIDs[0].id");
+                        return profile.getItemId().equals(profileId);
+                    },
+                    DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+
+            Assert.assertEquals("testListId", 
findListsContext.getValue("data.cdp.findLists.edges[0].node.id"));
 
             try (CloseableHttpResponse response = 
post("graphql/list/delete-list.json")) {
                 final ResponseContext context = 
ResponseContext.parse(response.getEntity());
diff --git a/setenv.sh b/setenv.sh
index dd042c07f..aa780461e 100755
--- a/setenv.sh
+++ b/setenv.sh
@@ -17,8 +17,13 @@
 #    limitations under the License.
 #
 
################################################################################
-export UNOMI_VERSION=`mvn 
org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate 
-Dexpression=project.version | grep -Ev '(^\[|Download\w+:)'`
-echo Detected project version=$UNOMI_VERSION
+# Quiet evaluate: avoid capturing Maven download lines into the environment 
(breaks CI with ARG_MAX).
+export UNOMI_VERSION="$(mvn -B -q -DforceStdout help:evaluate 
-Dexpression=project.version -DinteractiveMode=false 2>/dev/null)"
+if [ -z "$UNOMI_VERSION" ]; then
+    echo "Failed to detect project version from Maven" >&2
+    exit 1
+fi
+echo "Detected project version=$UNOMI_VERSION"
 export KARAF_VERSION=4.4.8
 # Uncomment the following line if you need Apache Unomi to start automatically 
at the first start
 # export KARAF_OPTS="-Dunomi.autoStart=true"

Reply via email to