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"