diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 4a8a9ecd..5149d6d0 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -8,21 +8,13 @@ updates:
ignore:
- dependency-name: org.elasticsearch.client:elasticsearch-rest-high-level-client
versions:
- - 7.11.x
- - 7.12.x
- - 7.13.x
- - 7.14.x
- - 7.15.x
- - 7.16.x
+ - 7.17.x
+ - 8.x
+ - dependency-name: org.elasticsearch.client:elasticsearch-rest-client
+ versions:
- 7.17.x
- 8.x
- dependency-name: org.elasticsearch:elasticsearch
versions:
- - 7.11.x
- - 7.12.x
- - 7.13.x
- - 7.14.x
- - 7.15.x
- - 7.16.x
- 7.17.x
- 8.x
diff --git a/.github/workflows/maven-matrix.yml b/.github/workflows/maven-matrix.yml
index 69ca6998..6f249b42 100644
--- a/.github/workflows/maven-matrix.yml
+++ b/.github/workflows/maven-matrix.yml
@@ -5,11 +5,15 @@ on:
branches:
- master
- release
+ paths-ignore:
+ - '*.md'
# pull_request to run the pipeline on PRs from external, because "push" does not create this pipeline on external PRs
pull_request:
+ paths-ignore:
+ - '*.md'
schedule:
# * is a special character in YAML so you have to quote this string
- - cron: '30 5 * * *'
+ - cron: '11 16 * * 4'
env:
MVN_CMD: "./mvnw --settings .cicd.settings.xml -e -B -V"
@@ -19,9 +23,9 @@ jobs:
build-and-test-with-jdk:
strategy:
matrix:
- java: [ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 ]
+ java: [ 8, 11, 17, 18, 19 ]
fail-fast: false
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -30,26 +34,26 @@ jobs:
with:
distribution: zulu
java-version: ${{ matrix.java }}
- - name: Cache local Maven repository
- uses: actions/cache@v2
- with:
- path: |
- ~/.m2/repository
- !~/.m2/repository/com/senacor
- ~/.m2/wrapper
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+# - name: Cache local Maven repository
+# uses: actions/cache@v2
+# with:
+# path: |
+# ~/.m2/repository
+# !~/.m2/repository/com/senacor
+# ~/.m2/wrapper
+# key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+# restore-keys: |
+# ${{ runner.os }}-maven-
- name: Build and test with Maven
run: $MVN_CMD install
build-and-test-with-es-version:
strategy:
matrix:
- elasticsearchVersion: [ "8.1.2", "8.0.1", "7.17.2", "7.16.3", "7.15.2", "7.14.2",
+ elasticsearchVersion: [ "8.6.0", "8.5.3", "8.4.3", "8.3.3", "8.2.3", "8.1.3", "8.0.1", "7.17.8", "7.16.3", "7.15.2", "7.14.2",
"7.13.4", "7.12.1", "7.11.2", "7.10.2", "7.9.3", "7.8.1", "7.7.1", "7.6.2", "7.5.2" ]
fail-fast: false
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -58,16 +62,16 @@ jobs:
with:
distribution: zulu
java-version: 11
- - name: Cache local Maven repository
- uses: actions/cache@v3
- with:
- path: |
- ~/.m2/repository
- !~/.m2/repository/com/senacor
- ~/.m2/wrapper
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+# - name: Cache local Maven repository
+# uses: actions/cache@v3
+# with:
+# path: |
+# ~/.m2/repository
+# !~/.m2/repository/com/senacor
+# ~/.m2/wrapper
+# key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+# restore-keys: |
+# ${{ runner.os }}-maven-
- name: Build and test with Maven
run: $MVN_CMD install -DskipTests
- name: elasticsearch test version ${{ matrix.elasticsearchVersion }}
@@ -76,8 +80,8 @@ jobs:
release-dry-run:
# this will just build like the real release job, but not do a release (dry run)
needs: [ build-and-test-with-jdk, build-and-test-with-es-version ]
- if: ${{ github.event_name != 'pull_request' && github.ref != 'refs/heads/release' }}
- runs-on: ubuntu-18.04
+ if: ${{ github.ref != 'refs/heads/release' }}
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -94,16 +98,16 @@ jobs:
with:
distribution: zulu
java-version: 8
- - name: Cache local Maven repository
- uses: actions/cache@v3
- with:
- path: |
- ~/.m2/repository
- !~/.m2/repository/com/senacor
- ~/.m2/wrapper
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+# - name: Cache local Maven repository
+# uses: actions/cache@v3
+# with:
+# path: |
+# ~/.m2/repository
+# !~/.m2/repository/com/senacor
+# ~/.m2/wrapper
+# key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+# restore-keys: |
+# ${{ runner.os }}-maven-
- name: Release to maven central
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
@@ -118,7 +122,7 @@ jobs:
# Release to maven central and create Github release
needs: [ build-and-test-with-jdk, build-and-test-with-es-version ]
if: ${{ github.repository == 'senacor/elasticsearch-evolution' && github.event_name == 'push' && github.ref == 'refs/heads/release' }}
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -135,16 +139,16 @@ jobs:
with:
distribution: zulu
java-version: 8
- - name: Cache local Maven repository
- uses: actions/cache@v3
- with:
- path: |
- ~/.m2/repository
- !~/.m2/repository/com/senacor
- ~/.m2/wrapper
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+# - name: Cache local Maven repository
+# uses: actions/cache@v3
+# with:
+# path: |
+# ~/.m2/repository
+# !~/.m2/repository/com/senacor
+# ~/.m2/wrapper
+# key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+# restore-keys: |
+# ${{ runner.os }}-maven-
- name: Release to maven central
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index f7638d8e..9b1af4a5 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -5,14 +5,20 @@ on:
branches:
- master
- release
+ paths-ignore:
+ - '*.md'
pull_request:
+ paths-ignore:
+ - '*.md'
+ schedule:
+ - cron: '42 16 * * 4'
env:
MVN_CMD: "./mvnw --settings .cicd.settings.xml -e -B -V"
jobs:
code-analysis:
- runs-on: ubuntu-18.04
+ runs-on: ubuntu-20.04
env:
COVERALLS_REPO_TOKEN_EXISTS: ${{ secrets.COVERALLS_REPO_TOKEN != '' }}
steps:
@@ -24,16 +30,21 @@ jobs:
with:
distribution: zulu
java-version: 8
- - name: Cache local Maven repository
- uses: actions/cache@v3
+# - name: Cache local Maven repository
+# uses: actions/cache@v3
+# with:
+# path: |
+# ~/.m2/repository
+# !~/.m2/repository/com/senacor
+# ~/.m2/wrapper
+# key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+# restore-keys: |
+# ${{ runner.os }}-maven-
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
with:
- path: |
- ~/.m2/repository
- !~/.m2/repository/com/senacor
- ~/.m2/wrapper
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+ languages: 'java'
- name: Build and test with Maven
run: $MVN_CMD install
- name: Execute Maven coveralls Plugin
@@ -42,4 +53,6 @@ jobs:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_EVENT_PATH: ${{ github.event_path }}
- run: $MVN_CMD coveralls:report -DrepoToken=$COVERALLS_REPO_TOKEN -DserviceName=GitHub-Actions
\ No newline at end of file
+ run: $MVN_CMD coveralls:report -DrepoToken=$COVERALLS_REPO_TOKEN -DserviceName=GitHub-Actions
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
\ No newline at end of file
diff --git a/README.md b/README.md
index 1f8fceb0..d1bdf996 100644
--- a/README.md
+++ b/README.md
@@ -20,10 +20,10 @@ Successful executed migration scripts will not be executed again!
## 2 Features
-- tested on Java 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 and 18
-- runs on Spring-Boot 2.1, 2.2, 2.3, 2.4, 2.5 and 2.6 (and of course without Spring-Boot)
-- runs on Elasticsearch version 7.5.x - 8.1.x
-- runs on Opensearch version 1.x
+- tested on Java 8, 11, 17, 18 and 19
+- runs on Spring-Boot 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 and 2.7 (and of course without Spring-Boot)
+- runs on Elasticsearch version 7.5.x - 8.4.x
+- runs on Opensearch version 1.x and 2.x
- highly configurable (e.g. location(s) of your migration files, migration files format pattern)
- placeholder substitution in migration scripts
- easily extendable to your needs
@@ -33,8 +33,8 @@ Successful executed migration scripts will not be executed again!
| Compatibility | Spring Boot | Elasticsearch | Opensearch |
|----------------------------------|------------------------------|----------------------|------------|
-| elasticsearch-evolution >= 0.4.0 | 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 | 7.5.x - 8.1.x | 1.x |
-| elasticsearch-evolution >= 0.3.0 | 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 | 7.5.x - 7.17.x | |
+| elasticsearch-evolution >= 0.4.0 | 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 | 7.5.x - 8.4.x | 1.x - 2.x |
+| elasticsearch-evolution 0.3.x | 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 | 7.5.x - 7.17.x | |
| elasticsearch-evolution 0.2.x | 1.5, 2.0, 2.1, 2.2, 2.3, 2.4 | 7.0.x - 7.4.x, 6.8.x | |
NOTE: When you run on Java 11 and using spring-boot 2.2 or 2.3 and you hit [this issue](https://github.com/ronmamo/reflections/issues/279), you have 2 options:
@@ -52,7 +52,7 @@ First add the latest version of Elasticsearch-Evolution spring boot starter as a
com.senacor.elasticsearch.evolution
spring-boot-starter-elasticsearch-evolution
- 0.3.2
+ 0.4.0
```
@@ -76,7 +76,7 @@ First add the latest version of Elasticsearch-Evolution core as a dependency:
com.senacor.elasticsearch.evolution
elasticsearch-evolution-core
- 0.3.2
+ 0.4.0
```
@@ -192,6 +192,8 @@ Elasticsearch-Evolution can be configured to your needs:
- **placeholderSuffix** (default=}): Suffix of placeholders in migration scripts.
- **historyIndex** (default=es_evolution): Name of the history index that will be used by Elasticsearch-Evolution. In this index Elasticsearch-Evolution will persist his internal state and tracks which migration script has already been executed.
- **historyMaxQuerySize** (default=1000): The maximum query size while validating already executed scripts. This query size have to be higher than the total count of your migration scripts.
+- **validateOnMigrate** (default=true): Whether to fail when a previously applied migration script has been modified after it was applied.
+- **baselineVersion** (default=1.0): Version to use as a baseline. versions lower than it will not be applied.
### 5.1 Spring Boot
@@ -286,7 +288,18 @@ ElasticsearchEvolution.configure()
## 6 changelog
-### v0.4.0-SNAPSHOT
+### v0.4.1-SNAPSHOT
+
+- Optimization: Don't acquire lock if no scripts need to be executed ([#172](https://github.com/senacor/elasticsearch-evolution/issues/172))
+- Previously applied migration scripts are now checked for modifications and rejected if they've been modified after they were applied. The old behaviour can be restored by setting the new configuration parameter `validateOnMigrate` to false (default: true) ([#155](https://github.com/senacor/elasticsearch-evolution/issues/155))
+- version updates (spring-boot 2.7.7)
+- added java 19 compatibility tests
+- added spring boot 2.7 compatibility tests
+- added Elasticsearch 8.6, 8.5, 8.4, 8.3, and 8,2 compatibility test
+- added Opensearch 2.3, 2.2, 2.1 and 2.0 compatibility tests
+- It is now possible to set a `baselineVersion` to skip migrations with versions lower than the defined `baselineVersion` ([#164](https://github.com/senacor/elasticsearch-evolution/issues/164))
+
+### v0.4.0
- **breaking change**: drop `org.elasticsearch.client.RestHighLevelClient` and replace with `org.elasticsearch.client.RestClient` (LowLevelClient). This will drop the big transitive dependency `org.elasticsearch:elasticsearch` and opens compatibility to Elasticsearch 8 and OpenSearch.
- version updates (spring-boot 2.6.6)
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..034c7ff2
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,16 @@
+# Security Policy
+
+## Supported Versions
+
+Only the latest version is supported with security updates:
+
+| Version | Supported |
+|---------| ------------------ |
+| 0.4.x | :white_check_mark: |
+| < 0.4 | :x: |
+
+## Reporting a Vulnerability
+
+### Please do not use GitHub issues for security-sensitive communication.
+
+You should contact one of the repository [maintainer](https://github.com/orgs/senacor/teams/elasticsearch-evolution-maintainers) or one of its main [contributor](https://github.com/senacor/elasticsearch-evolution/graphs/contributors) via email (visible in users GitHub profile).
diff --git a/elasticsearch-evolution-core/pom.xml b/elasticsearch-evolution-core/pom.xml
index 3d32865b..1b4cb414 100644
--- a/elasticsearch-evolution-core/pom.xml
+++ b/elasticsearch-evolution-core/pom.xml
@@ -6,7 +6,7 @@
com.senacor.elasticsearch.evolution
elasticsearch-evolution-parent
- 0.4.0
+ 0.4.1
../
elasticsearch-evolution-core
diff --git a/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/ElasticsearchEvolution.java b/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/ElasticsearchEvolution.java
index ef80d791..22cc8567 100644
--- a/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/ElasticsearchEvolution.java
+++ b/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/ElasticsearchEvolution.java
@@ -168,6 +168,8 @@ protected MigrationService createMigrationService() {
10_000,
getRestClient(),
ContentType.parse(getConfig().getDefaultContentType()),
- getConfig().getEncoding());
+ getConfig().getEncoding(),
+ getConfig().getValidateOnMigrate(),
+ getConfig().getBaselineVersion());
}
}
diff --git a/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/api/config/ElasticsearchEvolutionConfig.java b/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/api/config/ElasticsearchEvolutionConfig.java
index 03e410db..d72f6d4f 100644
--- a/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/api/config/ElasticsearchEvolutionConfig.java
+++ b/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/api/config/ElasticsearchEvolutionConfig.java
@@ -1,6 +1,7 @@
package com.senacor.elasticsearch.evolution.core.api.config;
import com.senacor.elasticsearch.evolution.core.ElasticsearchEvolution;
+import com.senacor.elasticsearch.evolution.core.internal.model.MigrationVersion;
import org.elasticsearch.client.RestClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -83,6 +84,17 @@ public class ElasticsearchEvolutionConfig {
*/
private int historyMaxQuerySize = 1_000;
+ /**
+ * Whether to fail when a previously applied migration script has been modified after it was applied.
+ */
+ private boolean validateOnMigrate = true;
+
+ /**
+ * version to use as a baseline.
+ * The baseline version will be the first one applied, the versions below will be ignored.
+ */
+ private String baselineVersion = "1.0";
+
/**
* Loads this configuration into a new ElasticsearchEvolution instance.
*
@@ -124,6 +136,11 @@ public ElasticsearchEvolutionConfig validate() throws IllegalStateException, Nul
}
requireNotBlank(historyIndex, "historyIndex must not be empty");
requireCondition(historyMaxQuerySize, size -> size > 0, "historyMaxQuerySize value '%s' must be greater than 0", historyMaxQuerySize);
+ try {
+ MigrationVersion.fromVersion(baselineVersion);
+ } catch (RuntimeException e) {
+ throw new IllegalArgumentException("baselineVersion is invalid", e);
+ }
}
return this;
}
@@ -236,6 +253,24 @@ public ElasticsearchEvolutionConfig setHistoryMaxQuerySize(int historyMaxQuerySi
return this;
}
+ public boolean getValidateOnMigrate() {
+ return validateOnMigrate;
+ }
+
+ public ElasticsearchEvolutionConfig setValidateOnMigrate(boolean validateOnMigrate) {
+ this.validateOnMigrate = validateOnMigrate;
+ return this;
+ }
+
+ public String getBaselineVersion() {
+ return baselineVersion;
+ }
+
+ public ElasticsearchEvolutionConfig setBaselineVersion(String baselineVersion) {
+ this.baselineVersion = baselineVersion;
+ return this;
+ }
+
@Override
public String toString() {
return "ElasticsearchEvolutionConfig{" +
@@ -251,6 +286,8 @@ public String toString() {
", placeholderReplacement=" + placeholderReplacement +
", historyIndex='" + historyIndex + '\'' +
", historyMaxQuerySize=" + historyMaxQuerySize +
+ ", validateOnMigrate=" + validateOnMigrate +
+ ", baselineVersion='" + baselineVersion + '\'' +
'}';
}
}
diff --git a/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/internal/migration/execution/MigrationServiceImpl.java b/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/internal/migration/execution/MigrationServiceImpl.java
index 5dbfd737..7cf4c554 100644
--- a/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/internal/migration/execution/MigrationServiceImpl.java
+++ b/elasticsearch-evolution-core/src/main/java/com/senacor/elasticsearch/evolution/core/internal/migration/execution/MigrationServiceImpl.java
@@ -37,58 +37,72 @@ public class MigrationServiceImpl implements MigrationService {
private final RestClient restClient;
private final ContentType defaultContentType;
private final Charset encoding;
+ private final boolean validateOnMigrate;
+ private final String baselineVersion;
public MigrationServiceImpl(HistoryRepository historyRepository,
int waitUntilUnlockedMinTimeInMillis,
int waitUntilUnlockedMaxTimeInMillis,
RestClient restClient,
ContentType defaultContentType,
- Charset encoding) {
+ Charset encoding,
+ boolean validateOnMigrate,
+ String baselineVersion) {
this.historyRepository = requireNonNull(historyRepository, "historyRepository must not be null");
this.restClient = requireNonNull(restClient, "restClient must not be null");
this.defaultContentType = requireNonNull(defaultContentType);
this.encoding = requireNonNull(encoding);
+ this.validateOnMigrate = validateOnMigrate;
this.waitUntilUnlockedMinTimeInMillis = requireCondition(waitUntilUnlockedMinTimeInMillis,
min -> min >= 0 && min <= waitUntilUnlockedMaxTimeInMillis,
"waitUntilUnlockedMinTimeInMillis (%s) must not be negative and must not be greater than waitUntilUnlockedMaxTimeInMillis (%s)",
waitUntilUnlockedMinTimeInMillis, waitUntilUnlockedMaxTimeInMillis);
this.waitUntilUnlockedMaxTimeInMillis = waitUntilUnlockedMaxTimeInMillis;
+ this.baselineVersion = baselineVersion;
}
@Override
- public List executePendingScripts(Collection migrationScripts) throws MigrationException {
+ public List executePendingScripts(Collection migrationScripts)
+ throws MigrationException {
+ if (!getPendingScriptsToBeExecuted(migrationScripts).isEmpty()) {
+ return executePendingScriptsWithLock(migrationScripts);
+ } else {
+ return new ArrayList<>();
+ }
+ }
+
+ private List executePendingScriptsWithLock(Collection migrationScripts)
+ throws MigrationException {
List executedScripts = new ArrayList<>();
- if (!migrationScripts.isEmpty()) {
- try {
- historyRepository.createIndexIfAbsent();
- waitUntilUnlocked();
- // set an logical index lock
- if (!historyRepository.lock()) {
- throw new MigrationException("could not lock the elasticsearch-evolution history index");
- }
+ try {
+ historyRepository.createIndexIfAbsent();
+ waitUntilUnlocked();
+ // set a logical index lock
+ if (!historyRepository.lock()) {
+ throw new MigrationException("could not lock the elasticsearch-evolution history index");
+ }
- // get scripts which needs to be executed
- List scriptsToExecute = getPendingScriptsToBeExecuted(migrationScripts);
-
- // now execute scripts and write protocols to history index
- for (ParsedMigrationScript script : scriptsToExecute) {
- // execute scripts
- ExecutionResult res = executeScript(script);
- MigrationScriptProtocol executedScriptProtocol = res.getProtocol();
- logger.info("executed migration script {}", executedScriptProtocol);
- executedScripts.add(executedScriptProtocol);
- // write protocols to history index
- historyRepository.saveOrUpdate(executedScriptProtocol);
- if (res.getError().isPresent()) {
- throw res.getError().get();
- }
- }
- } finally {
- // release logical index lock
- if (!historyRepository.unlock()) {
- throw new MigrationException("could not release the elasticsearch-evolution history index lock! Maybe you have to release it manually.");
+ // get scripts which needs to be executed
+ List scriptsToExecute = getPendingScriptsToBeExecuted(migrationScripts);
+
+ // now execute scripts and write protocols to history index
+ for (ParsedMigrationScript script : scriptsToExecute) {
+ // execute scripts
+ ExecutionResult res = executeScript(script);
+ MigrationScriptProtocol executedScriptProtocol = res.getProtocol();
+ logger.info("executed migration script {}", executedScriptProtocol);
+ executedScripts.add(executedScriptProtocol);
+ // write protocols to history index
+ historyRepository.saveOrUpdate(executedScriptProtocol);
+ if (res.getError().isPresent()) {
+ throw res.getError().get();
}
}
+ } finally {
+ // release logical index lock
+ if (!historyRepository.unlock()) {
+ throw new MigrationException("could not release the elasticsearch-evolution history index lock! Maybe you have to release it manually.");
+ }
}
return executedScripts;
}
@@ -161,8 +175,13 @@ ExecutionResult executeScript(ParsedMigrationScript scriptToExecute) {
* @return list of ordered scripts which must be executed
*/
List getPendingScriptsToBeExecuted(Collection migrationScripts) {
+ if (migrationScripts.isEmpty()) {
+ return new ArrayList<>();
+ }
+
// order migrationScripts by version
List orderedScripts = new ArrayList<>(migrationScripts.stream()
+ .filter(script -> script.getFileNameInfo().getVersion().isAtLeast(baselineVersion))
.collect(Collectors.toMap(
script -> script.getFileNameInfo().getVersion(),
script -> script,
@@ -185,9 +204,20 @@ List getPendingScriptsToBeExecuted(Collection()).when(historyRepository).findAll();
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
ParsedMigrationScript parsedMigrationScript1_1 = createParsedMigrationScript("1.1");
ParsedMigrationScript parsedMigrationScript1_0 = createParsedMigrationScript("1.0");
List parsedMigrationScripts = asList(
@@ -121,7 +128,7 @@ void scriptsAndHistoryInSync_noScriptsWillBeReturned() {
createMigrationScriptProtocol("1.1", true)
))).when(historyRepository).findAll();
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
List parsedMigrationScripts = asList(
createParsedMigrationScript("1.1"),
@@ -142,7 +149,7 @@ void lastHistoryVersionWasFailing_AllScriptsInclFailedWillBeReturned() {
createMigrationScriptProtocol("1.1", false)
))).when(historyRepository).findAll();
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
ParsedMigrationScript parsedMigrationScript1_0 = createParsedMigrationScript("1.0");
ParsedMigrationScript parsedMigrationScript1_1 = createParsedMigrationScript("1.1");
@@ -167,7 +174,7 @@ void moreHistoryVersionsThanScripts_warningIsShownAnNoScriptsWillBeReturned() {
createMigrationScriptProtocol("1.2", false)
))).when(historyRepository).findAll();
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
ParsedMigrationScript parsedMigrationScript1_0 = createParsedMigrationScript("1.0");
ParsedMigrationScript parsedMigrationScript1_1 = createParsedMigrationScript("1.1");
@@ -190,7 +197,7 @@ void outOfOrderExecutionIsNotSupported() {
createMigrationScriptProtocol("1.1", true)
))).when(historyRepository).findAll();
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
ParsedMigrationScript parsedMigrationScript1_0 = createParsedMigrationScript("1.0");
ParsedMigrationScript parsedMigrationScript1_0_1 = createParsedMigrationScript("1.0.1");
@@ -204,6 +211,109 @@ void outOfOrderExecutionIsNotSupported() {
.isInstanceOf(MigrationException.class)
.hasMessage("The logged execution in the Elasticsearch-Evolution history index at position 1 is version 1.1 and in the same position in the given migration scripts is version 1.0.1! Out of order execution is not supported. Or maybe you have added new migration scripts in between or have to cleanup the Elasticsearch-Evolution history index manually");
}
+
+ @Test
+ void failingScriptWasEdited_shouldReturnAllScriptsInclFailing() {
+ doReturn(new TreeSet<>(asList(
+ createMigrationScriptProtocol("1.0", true, 1),
+ createMigrationScriptProtocol("1.1", false, 2)
+ ))).when(historyRepository).findAll();
+ MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
+
+ ParsedMigrationScript parsedMigrationScript1_0 = createParsedMigrationScript("1.0", 1);
+ ParsedMigrationScript parsedMigrationScript1_1 = createParsedMigrationScript("1.1", 3);
+ ParsedMigrationScript parsedMigrationScript1_2 = createParsedMigrationScript("1.2", 4);
+ List parsedMigrationScripts = asList(
+ parsedMigrationScript1_1,
+ parsedMigrationScript1_0,
+ parsedMigrationScript1_2);
+
+ List res = underTest.getPendingScriptsToBeExecuted(parsedMigrationScripts);
+
+ assertThat(res).hasSize(2);
+ assertThat(res.get(0)).isSameAs(parsedMigrationScript1_1);
+ assertThat(res.get(1)).isSameAs(parsedMigrationScript1_2);
+ InOrder order = inOrder(historyRepository);
+ order.verify(historyRepository).findAll();
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test
+ void successfulScriptWasEdited_shouldThrowChecksumMismatchException() {
+ doReturn(new TreeSet<>(asList(
+ createMigrationScriptProtocol("1.0", true, 1),
+ createMigrationScriptProtocol("1.1", true, 2)
+ ))).when(historyRepository).findAll();
+ MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
+
+ ParsedMigrationScript parsedMigrationScript1_0 = createParsedMigrationScript("1.0", 1);
+ ParsedMigrationScript parsedMigrationScript1_1 = createParsedMigrationScript("1.1", 3);
+ List parsedMigrationScripts = asList(
+ parsedMigrationScript1_1,
+ parsedMigrationScript1_0);
+
+ assertThatThrownBy(() -> underTest.getPendingScriptsToBeExecuted(parsedMigrationScripts))
+ .isInstanceOf(MigrationException.class)
+ .hasMessage("The logged execution for the migration script at position 1 (V1.1__1.1.http) " +
+ "has a different checksum from the given migration script! " +
+ "Modifying already-executed scripts is not supported.");
+ }
+
+ @Test
+ void successfulScriptWasEdited_shouldContinueIfValidateOnMigrateIsDisabled() {
+ doReturn(new TreeSet<>(asList(
+ createMigrationScriptProtocol("1.0", true, 1),
+ createMigrationScriptProtocol("1.1", true, 2)
+ ))).when(historyRepository).findAll();
+ MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
+ 0, 0, restClient, defaultContentType, encoding, false, "1.0");
+
+ ParsedMigrationScript parsedMigrationScript1_0 = createParsedMigrationScript("1.0", 1);
+ ParsedMigrationScript parsedMigrationScript1_1 = createParsedMigrationScript("1.1", 3);
+ List parsedMigrationScripts = asList(
+ parsedMigrationScript1_1,
+ parsedMigrationScript1_0);
+
+ List res = underTest.getPendingScriptsToBeExecuted(parsedMigrationScripts);
+
+ assertThat(res).hasSize(0);
+ assertThat(res).isEmpty();
+ InOrder order = inOrder(historyRepository);
+ order.verify(historyRepository).findAll();
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test
+ void usingABaseline_onlyScriptsWithVersionHigherThanBaselineWillBeReturned() {
+ doReturn(new TreeSet<>()).when(historyRepository).findAll();
+ MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
+ 0, 0, restClient, defaultContentType, encoding, true, "2.0");
+
+ List parsedMigrationScripts = asList(
+ createParsedMigrationScript("1.0"),
+ createParsedMigrationScript("2.0"));
+
+ List res = underTest.getPendingScriptsToBeExecuted(parsedMigrationScripts);
+
+ assertThat(res).hasSize(1);
+ assertThat(res).containsOnly(createParsedMigrationScript("2.0"));
+ InOrder order = inOrder(historyRepository);
+ order.verify(historyRepository).findAll();
+ order.verifyNoMoreInteractions();
+ }
+
+ @Test
+ void noPendingScriptsIfMigrationScriptListIsEmpty() {
+ MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
+ 0, 0, restClient, defaultContentType, encoding, true, "2.0");
+
+ List res = underTest.getPendingScriptsToBeExecuted(emptyList());
+
+ assertThat(res).isEmpty();
+ Mockito.verifyNoInteractions(historyRepository);
+ }
}
@Nested
@@ -215,7 +325,7 @@ void OK_resultIsSetCorrect() throws IOException {
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
MigrationScriptProtocol res = underTest.executeScript(script).getProtocol();
@@ -271,7 +381,7 @@ void OK_requestWithBody() throws IOException {
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
MigrationScriptProtocol res = underTest.executeScript(script).getProtocol();
@@ -311,7 +421,7 @@ void OK_requestWithCustomContentTypeAndDefaultCharset() throws IOException {
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
MigrationScriptProtocol res = underTest.executeScript(script).getProtocol();
@@ -350,7 +460,7 @@ void OK_requestWithCustomContentTypeAndCustomCharset() throws IOException {
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
MigrationScriptProtocol res = underTest.executeScript(script).getProtocol();
@@ -390,7 +500,7 @@ void OK_requestWithCustomHeader() throws IOException {
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
MigrationScriptProtocol res = underTest.executeScript(script).getProtocol();
@@ -426,7 +536,7 @@ void executeScript_failed_status(Exception handledError) throws IOException {
doThrow(handledError).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
ExecutionResult res = underTest.executeScript(script);
@@ -445,7 +555,7 @@ void executeScript_failed_status(int httpStatusCode) throws IOException {
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
ExecutionResult res = underTest.executeScript(script);
@@ -467,7 +577,7 @@ void executeScript_OK_status(int httpStatusCode) throws IOException {
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
MigrationScriptProtocol res = underTest.executeScript(script).getProtocol();
@@ -490,7 +600,7 @@ void allOK() throws IOException {
Response responseMock = createResponseMock(200);
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
List res = underTest.executePendingScripts(scripts);
@@ -523,7 +633,7 @@ void firstExecutionFailed() throws IOException {
Response responseMock = createResponseMock(statusCode);
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
assertThatThrownBy(() -> underTest.executePendingScripts(scripts))
.isInstanceOf(MigrationException.class)
@@ -556,7 +666,7 @@ void error_unlockWasNotSuccessful() throws IOException {
Response responseMock = createResponseMock(200);
doReturn(responseMock).when(restClient).performRequest(any());
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
assertThatThrownBy(() -> underTest.executePendingScripts(scripts))
.isInstanceOf(MigrationException.class)
@@ -583,9 +693,10 @@ void error_lockWasNotSuccessful() {
doReturn(false).when(historyRepository).isLocked();
doReturn(false).when(historyRepository).lock();
doReturn(true).when(historyRepository).unlock();
+ doReturn(new TreeSet<>()).when(historyRepository).findAll();
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
assertThatThrownBy(() -> underTest.executePendingScripts(scripts))
.isInstanceOf(MigrationException.class)
@@ -603,7 +714,7 @@ void error_lockWasNotSuccessful() {
@Test
void emptyScriptsCollection() {
MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
- 0, 0, restClient, defaultContentType, encoding);
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
List res = underTest.executePendingScripts(emptyList());
@@ -611,6 +722,26 @@ void emptyScriptsCollection() {
InOrder order = inOrder(historyRepository, restClient);
order.verifyNoMoreInteractions();
}
+
+ @Test
+ void noPendingScripts_shouldNotLockRepository() {
+ List scripts = asList(
+ createParsedMigrationScript("1.0"),
+ createParsedMigrationScript("1.1"));
+ doReturn(new TreeSet<>(asList(
+ createMigrationScriptProtocol("1.0", true),
+ createMigrationScriptProtocol("1.1", true)
+ ))).when(historyRepository).findAll();
+ MigrationServiceImpl underTest = new MigrationServiceImpl(historyRepository,
+ 0, 0, restClient, defaultContentType, encoding, true, "1.0");
+
+ List res = underTest.executePendingScripts(scripts);
+
+ assertThat(res).isEmpty();
+ InOrder order = inOrder(historyRepository, restClient);
+ order.verify(historyRepository).findAll();
+ order.verifyNoMoreInteractions();
+ }
}
private Response createResponseMock(int statusCode) {
@@ -622,9 +753,13 @@ private Response createResponseMock(int statusCode) {
}
private MigrationScriptProtocol createMigrationScriptProtocol(String version, boolean success) {
+ return createMigrationScriptProtocol(version, success, 1);
+ }
+
+ private MigrationScriptProtocol createMigrationScriptProtocol(String version, boolean success, int checksum) {
return new MigrationScriptProtocol()
.setVersion(version)
- .setChecksum(1)
+ .setChecksum(checksum)
.setSuccess(success)
.setLocked(true)
.setDescription(version)
@@ -632,13 +767,17 @@ private MigrationScriptProtocol createMigrationScriptProtocol(String version, bo
}
private ParsedMigrationScript createParsedMigrationScript(String version) {
+ return createParsedMigrationScript(version, 1);
+ }
+
+ private ParsedMigrationScript createParsedMigrationScript(String version, int checksum) {
return new ParsedMigrationScript()
.setFileNameInfo(
new FileNameInfoImpl(fromVersion(version), version, createDefaultScriptName(version)))
- .setChecksum(1)
+ .setChecksum(checksum)
.setMigrationScriptRequest(new MigrationScriptRequest()
- .setHttpMethod(DELETE)
- .setPath("/"));
+ .setHttpMethod(DELETE)
+ .setPath("/"));
}
private String createDefaultScriptName(String version) {
diff --git a/elasticsearch-evolution-core/src/test/java/com/senacor/elasticsearch/evolution/core/test/EmbeddedElasticsearchExtension.java b/elasticsearch-evolution-core/src/test/java/com/senacor/elasticsearch/evolution/core/test/EmbeddedElasticsearchExtension.java
index bf38a722..b6379d52 100644
--- a/elasticsearch-evolution-core/src/test/java/com/senacor/elasticsearch/evolution/core/test/EmbeddedElasticsearchExtension.java
+++ b/elasticsearch-evolution-core/src/test/java/com/senacor/elasticsearch/evolution/core/test/EmbeddedElasticsearchExtension.java
@@ -1,5 +1,6 @@
package com.senacor.elasticsearch.evolution.core.test;
+import com.github.dockerjava.api.command.InspectContainerResponse;
import lombok.Builder;
import lombok.NonNull;
import lombok.Value;
@@ -18,6 +19,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.SocketUtils;
+import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
import org.testcontainers.utility.DockerImageName;
@@ -28,6 +30,7 @@
import static com.senacor.elasticsearch.evolution.core.test.EmbeddedElasticsearchExtension.SearchContainer.ofElasticsearch;
import static com.senacor.elasticsearch.evolution.core.test.EmbeddedElasticsearchExtension.SearchContainer.ofOpensearch;
+import static java.time.Duration.ofMinutes;
import static org.elasticsearch.client.RequestOptions.DEFAULT;
/**
@@ -41,26 +44,21 @@ public class EmbeddedElasticsearchExtension implements TestInstancePostProcessor
private static final Logger logger = LoggerFactory.getLogger(EmbeddedElasticsearchExtension.class);
private static final Namespace NAMESPACE = Namespace.create(ExtensionContext.class);
private static final SortedSet SUPPORTED_SEARCH_VERSIONS = Collections.unmodifiableSortedSet(new TreeSet<>(Arrays.asList(
- ofOpensearch("1.3.1"),
- ofOpensearch("1.2.4"),
- ofOpensearch("1.1.0"),
- ofOpensearch("1.0.1"),
-
- ofElasticsearch("8.1.2"),
+ ofOpensearch("2.4.1"),
+ ofOpensearch("2.3.0"),
+ ofOpensearch("2.2.1"),
+ ofOpensearch("2.1.0"),
+ ofOpensearch("2.0.1"),
+ ofOpensearch("1.3.7"),
+
+ ofElasticsearch("8.6.0"),
+ ofElasticsearch("8.5.3"),
+ ofElasticsearch("8.4.3"),
+ ofElasticsearch("8.3.3"),
+ ofElasticsearch("8.2.3"),
+ ofElasticsearch("8.1.3"),
ofElasticsearch("8.0.1"),
- ofElasticsearch("7.17.2"),
- ofElasticsearch("7.16.3"),
- ofElasticsearch("7.15.2"),
- ofElasticsearch("7.14.2"),
- ofElasticsearch("7.13.4"),
- ofElasticsearch("7.12.1"),
- ofElasticsearch("7.11.2"),
- ofElasticsearch("7.10.2"),
- ofElasticsearch("7.9.3"),
- ofElasticsearch("7.8.1"),
- ofElasticsearch("7.7.1"),
- ofElasticsearch("7.6.2"),
- ofElasticsearch("7.5.2")
+ ofElasticsearch("7.17.8")
)));
@Override
@@ -81,11 +79,30 @@ private static ElasticsearchContainer createElasticsearchContainer(SearchContain
logger.info("creating ElasticsearchContainer for {} ...", searchContainer.getInfo());
ElasticsearchContainer container = new ElasticsearchContainer(DockerImageName.parse(searchContainer.getContainerImage())
.asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch")
- .withTag(searchContainer.getVersion()))
- .withEnv(searchContainer.getEnv());
+ .withTag(searchContainer.getVersion())) {
+ @Override
+ protected void containerIsStarted(InspectContainerResponse containerInfo) {
+ // since testcontainers 1.17 it detects if ES 8.x is running and copies a certificate in this case
+ // but we don't want security
+ }
+ }
+ .withEnv(searchContainer.getEnv())
+ .withEnv("cluster.routing.allocation.disk.watermark.low", "97%")
+ .withEnv("cluster.routing.allocation.disk.watermark.high", "98%")
+ .withEnv("cluster.routing.allocation.disk.watermark.flood_stage", "99%");
+ // SocketUtils replacement: https://github.com/spring-projects/spring-framework/issues/28210
+ // https://github.com/spring-cloud/spring-cloud-function/issues/825
+ // https://github.com/spring-cloud/spring-cloud-deployer-local/pull/214
int httpPort = SocketUtils.findAvailableTcpPort(5000, 30000);
int transportPort = SocketUtils.findAvailableTcpPort(30001, 65535);
container.setPortBindings(Arrays.asList(httpPort + ":9200", transportPort + ":" + searchContainer.transportPort));
+// container.setWaitStrategy(new HttpWaitStrategy()
+// .forPort(9200)
+// .forStatusCodeMatching(response -> response == HTTP_OK || response == HTTP_UNAUTHORIZED)
+// .withStartupTimeout(ofMinutes(5)));
+ container.setWaitStrategy(new LogMessageWaitStrategy()
+ .withRegEx(".*(\"message\":\\s?\"started[\\s?|\"].*|] started\n$)")
+ .withStartupTimeout(ofMinutes(15)));
start(container, searchContainer.getInfo());
logger.info("ElasticsearchContainer {} started with HttpPort={} and TransportTcpPort={}!",
searchContainer.getInfo(),
@@ -177,7 +194,7 @@ public static SearchContainer ofOpensearch(String version) {
return SearchContainer.builder()
.vendor("Opensearch")
.vendorShort("OS")
- .containerImage("opensearchproject/opensearch")
+ .containerImage("quay.io/xtermi2/opensearch")
.version(version)
.env(ImmutableMap.of(
"OPENSEARCH_JAVA_OPTS", "-Xms128m -Xmx128m",
diff --git a/pom.xml b/pom.xml
index 96f6886a..08f8eeac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,12 +5,12 @@
com.senacor.elasticsearch.evolution
elasticsearch-evolution-parent
- 0.4.0
+ 0.4.1
pom
org.springframework.boot
spring-boot-dependencies
- 2.6.6
+ 2.7.7
elasticsearch-evolution
@@ -94,19 +94,19 @@
4.3.0
- 0.8.8-SNAPSHOT
+ 0.8.8
3.0.1
- 3.3.2
- 1.6.12
+ 3.4.1
+ 1.6.13
2.11.0
7.5.2
0.9.12
- 1.16.3
- 1.18.22
+ 1.17.5
+ 1.18.24
diff --git a/spring-boot-starter-elasticsearch-evolution/pom.xml b/spring-boot-starter-elasticsearch-evolution/pom.xml
index cd4fd13b..4bc54773 100644
--- a/spring-boot-starter-elasticsearch-evolution/pom.xml
+++ b/spring-boot-starter-elasticsearch-evolution/pom.xml
@@ -6,7 +6,7 @@
com.senacor.elasticsearch.evolution
elasticsearch-evolution-parent
- 0.4.0
+ 0.4.1
../
spring-boot-starter-elasticsearch-evolution
diff --git a/tests/migration-scripts/pom.xml b/tests/migration-scripts/pom.xml
index f85402b3..cbfde333 100644
--- a/tests/migration-scripts/pom.xml
+++ b/tests/migration-scripts/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.senacor.elasticsearch.evolution
migration-scripts
- 0.4.0
+ 0.4.1
jar containing migration files
jar
diff --git a/tests/pom.xml b/tests/pom.xml
index 2e7fd876..57505ef6 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -6,7 +6,7 @@
com.senacor.elasticsearch.evolution
elasticsearch-evolution-parent
- 0.4.0
+ 0.4.1
../
tests
@@ -19,6 +19,7 @@
migration-scripts
+ test-spring-boot-2.7
test-spring-boot-2.6
test-spring-boot-2.5-scriptsInJarFile
test-spring-boot-2.4
diff --git a/tests/test-spring-boot-2.1-scriptsInJarFile/pom.xml b/tests/test-spring-boot-2.1-scriptsInJarFile/pom.xml
index 568c3057..b389d10e 100644
--- a/tests/test-spring-boot-2.1-scriptsInJarFile/pom.xml
+++ b/tests/test-spring-boot-2.1-scriptsInJarFile/pom.xml
@@ -10,7 +10,7 @@
com.senacor.elasticsearch.evolution
test-spring-boot-2.1-scriptsInJarFile
- 0.4.0
+ 0.4.1
Demo project for Spring Boot
@@ -18,7 +18,7 @@
2.11.0
7.5.2
- 1.16.3
+ 1.17.5
@@ -85,7 +85,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.8-SNAPSHOT
+ 0.8.8
prepare-agent
diff --git a/tests/test-spring-boot-2.1-scriptsInJarFile/src/main/java/com/senacor/elasticsearch/evolution/springboot23/Application.java b/tests/test-spring-boot-2.1-scriptsInJarFile/src/main/java/com/senacor/elasticsearch/evolution/springboot21/Application.java
similarity index 82%
rename from tests/test-spring-boot-2.1-scriptsInJarFile/src/main/java/com/senacor/elasticsearch/evolution/springboot23/Application.java
rename to tests/test-spring-boot-2.1-scriptsInJarFile/src/main/java/com/senacor/elasticsearch/evolution/springboot21/Application.java
index 6eec1242..a4c1aa3b 100644
--- a/tests/test-spring-boot-2.1-scriptsInJarFile/src/main/java/com/senacor/elasticsearch/evolution/springboot23/Application.java
+++ b/tests/test-spring-boot-2.1-scriptsInJarFile/src/main/java/com/senacor/elasticsearch/evolution/springboot21/Application.java
@@ -1,4 +1,4 @@
-package com.senacor.elasticsearch.evolution.springboot23;
+package com.senacor.elasticsearch.evolution.springboot21;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot23/ApplicationTests.java b/tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot21/ApplicationTests.java
similarity index 72%
rename from tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot23/ApplicationTests.java
rename to tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot21/ApplicationTests.java
index d04a22e7..50f66bc8 100644
--- a/tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot23/ApplicationTests.java
+++ b/tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot21/ApplicationTests.java
@@ -1,5 +1,6 @@
-package com.senacor.elasticsearch.evolution.springboot23;
+package com.senacor.elasticsearch.evolution.springboot21;
+import com.github.dockerjava.api.command.InspectContainerResponse;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.junit.Test;
@@ -42,10 +43,19 @@ static class Config {
public ElasticsearchContainer elasticsearchContainer(@Value("${elasticsearch.version:7.5.2}") String esVersion) {
ElasticsearchContainer container = new ElasticsearchContainer(DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
- .withTag(esVersion))
+ .withTag(esVersion)) {
+ @Override
+ protected void containerIsStarted(InspectContainerResponse containerInfo) {
+ // since testcontainers 1.17 it detects if ES 8.x is running and copies a certificate in this case
+ // but we don't want security
+ }
+ }
.withEnv("ES_JAVA_OPTS", "-Xms128m -Xmx128m")
// since elasticsearch 8 security / https is enabled per default - but for testing it should be disabled
- .withEnv("xpack.security.enabled", "false");
+ .withEnv("xpack.security.enabled", "false")
+ .withEnv("cluster.routing.allocation.disk.watermark.low", "97%")
+ .withEnv("cluster.routing.allocation.disk.watermark.high", "98%")
+ .withEnv("cluster.routing.allocation.disk.watermark.flood_stage", "99%");
container.setPortBindings(Collections.singletonList(ELASTICSEARCH_PORT + ":9200"));
container.start();
return container;
diff --git a/tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot23/EsUtils.java b/tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot21/EsUtils.java
similarity index 97%
rename from tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot23/EsUtils.java
rename to tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot21/EsUtils.java
index bde1f552..49eae087 100644
--- a/tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot23/EsUtils.java
+++ b/tests/test-spring-boot-2.1-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot21/EsUtils.java
@@ -1,4 +1,4 @@
-package com.senacor.elasticsearch.evolution.springboot23;
+package com.senacor.elasticsearch.evolution.springboot21;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/tests/test-spring-boot-2.2/pom.xml b/tests/test-spring-boot-2.2/pom.xml
index 39a2ff19..ec2c995b 100644
--- a/tests/test-spring-boot-2.2/pom.xml
+++ b/tests/test-spring-boot-2.2/pom.xml
@@ -10,7 +10,7 @@
com.senacor.elasticsearch.evolution
test-spring-boot-2.2
- 0.4.0
+ 0.4.1
Demo project for Spring Boot
@@ -18,7 +18,7 @@
2.11.0
7.5.2
- 1.16.3
+ 1.17.5
@@ -78,7 +78,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.8-SNAPSHOT
+ 0.8.8
prepare-agent
diff --git a/tests/test-spring-boot-2.2/src/test/java/com/senacor/elasticsearch/evolution/springboot22/ApplicationTests.java b/tests/test-spring-boot-2.2/src/test/java/com/senacor/elasticsearch/evolution/springboot22/ApplicationTests.java
index d8ca6dec..2b48d2c7 100644
--- a/tests/test-spring-boot-2.2/src/test/java/com/senacor/elasticsearch/evolution/springboot22/ApplicationTests.java
+++ b/tests/test-spring-boot-2.2/src/test/java/com/senacor/elasticsearch/evolution/springboot22/ApplicationTests.java
@@ -1,5 +1,6 @@
package com.senacor.elasticsearch.evolution.springboot22;
+import com.github.dockerjava.api.command.InspectContainerResponse;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.Test;
@@ -39,10 +40,19 @@ static class Config {
public ElasticsearchContainer elasticsearchContainer(@Value("${elasticsearch.version:7.5.2}") String esVersion) {
ElasticsearchContainer container = new ElasticsearchContainer(DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
- .withTag(esVersion))
+ .withTag(esVersion)) {
+ @Override
+ protected void containerIsStarted(InspectContainerResponse containerInfo) {
+ // since testcontainers 1.17 it detects if ES 8.x is running and copies a certificate in this case
+ // but we don't want security
+ }
+ }
.withEnv("ES_JAVA_OPTS", "-Xms128m -Xmx128m")
// since elasticsearch 8 security / https is enabled per default - but for testing it should be disabled
- .withEnv("xpack.security.enabled", "false");
+ .withEnv("xpack.security.enabled", "false")
+ .withEnv("cluster.routing.allocation.disk.watermark.low", "97%")
+ .withEnv("cluster.routing.allocation.disk.watermark.high", "98%")
+ .withEnv("cluster.routing.allocation.disk.watermark.flood_stage", "99%");
container.setPortBindings(Collections.singletonList(ELASTICSEARCH_PORT + ":9200"));
container.start();
return container;
diff --git a/tests/test-spring-boot-2.3/pom.xml b/tests/test-spring-boot-2.3/pom.xml
index dd16fe6c..bad92a97 100644
--- a/tests/test-spring-boot-2.3/pom.xml
+++ b/tests/test-spring-boot-2.3/pom.xml
@@ -10,7 +10,7 @@
com.senacor.elasticsearch.evolution
test-spring-boot-2.3
- 0.4.0
+ 0.4.1
Demo project for Spring Boot
@@ -18,7 +18,7 @@
2.11.0
7.5.2
- 1.16.3
+ 1.17.5
@@ -78,7 +78,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.8-SNAPSHOT
+ 0.8.8
prepare-agent
diff --git a/tests/test-spring-boot-2.3/src/test/java/com/senacor/elasticsearch/evolution/springboot23/ApplicationTests.java b/tests/test-spring-boot-2.3/src/test/java/com/senacor/elasticsearch/evolution/springboot23/ApplicationTests.java
index b5a0a557..8a97507f 100644
--- a/tests/test-spring-boot-2.3/src/test/java/com/senacor/elasticsearch/evolution/springboot23/ApplicationTests.java
+++ b/tests/test-spring-boot-2.3/src/test/java/com/senacor/elasticsearch/evolution/springboot23/ApplicationTests.java
@@ -1,5 +1,6 @@
package com.senacor.elasticsearch.evolution.springboot23;
+import com.github.dockerjava.api.command.InspectContainerResponse;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.Test;
@@ -39,10 +40,19 @@ static class Config {
public ElasticsearchContainer elasticsearchContainer(@Value("${elasticsearch.version:7.5.2}") String esVersion) {
ElasticsearchContainer container = new ElasticsearchContainer(DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
- .withTag(esVersion))
+ .withTag(esVersion)) {
+ @Override
+ protected void containerIsStarted(InspectContainerResponse containerInfo) {
+ // since testcontainers 1.17 it detects if ES 8.x is running and copies a certificate in this case
+ // but we don't want security
+ }
+ }
.withEnv("ES_JAVA_OPTS", "-Xms128m -Xmx128m")
// since elasticsearch 8 security / https is enabled per default - but for testing it should be disabled
- .withEnv("xpack.security.enabled", "false");
+ .withEnv("xpack.security.enabled", "false")
+ .withEnv("cluster.routing.allocation.disk.watermark.low", "97%")
+ .withEnv("cluster.routing.allocation.disk.watermark.high", "98%")
+ .withEnv("cluster.routing.allocation.disk.watermark.flood_stage", "99%");
container.setPortBindings(Collections.singletonList(ELASTICSEARCH_PORT + ":9200"));
container.start();
return container;
diff --git a/tests/test-spring-boot-2.4/pom.xml b/tests/test-spring-boot-2.4/pom.xml
index 15a336a5..3bba5b25 100644
--- a/tests/test-spring-boot-2.4/pom.xml
+++ b/tests/test-spring-boot-2.4/pom.xml
@@ -10,7 +10,7 @@
com.senacor.elasticsearch.evolution
test-spring-boot-2.4
- 0.4.0
+ 0.4.1
Demo project for Spring Boot
@@ -18,7 +18,7 @@
2.11.0
7.5.2
- 1.16.3
+ 1.17.5
@@ -78,7 +78,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.8-SNAPSHOT
+ 0.8.8
prepare-agent
diff --git a/tests/test-spring-boot-2.4/src/test/java/com/senacor/elasticsearch/evolution/springboot24/ApplicationTests.java b/tests/test-spring-boot-2.4/src/test/java/com/senacor/elasticsearch/evolution/springboot24/ApplicationTests.java
index a0e5e59c..e379f8b1 100644
--- a/tests/test-spring-boot-2.4/src/test/java/com/senacor/elasticsearch/evolution/springboot24/ApplicationTests.java
+++ b/tests/test-spring-boot-2.4/src/test/java/com/senacor/elasticsearch/evolution/springboot24/ApplicationTests.java
@@ -1,5 +1,6 @@
package com.senacor.elasticsearch.evolution.springboot24;
+import com.github.dockerjava.api.command.InspectContainerResponse;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.Test;
@@ -39,10 +40,19 @@ static class Config {
public ElasticsearchContainer elasticsearchContainer(@Value("${elasticsearch.version:7.5.2}") String esVersion) {
ElasticsearchContainer container = new ElasticsearchContainer(DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
- .withTag(esVersion))
+ .withTag(esVersion)) {
+ @Override
+ protected void containerIsStarted(InspectContainerResponse containerInfo) {
+ // since testcontainers 1.17 it detects if ES 8.x is running and copies a certificate in this case
+ // but we don't want security
+ }
+ }
.withEnv("ES_JAVA_OPTS", "-Xms128m -Xmx128m")
// since elasticsearch 8 security / https is enabled per default - but for testing it should be disabled
- .withEnv("xpack.security.enabled", "false");
+ .withEnv("xpack.security.enabled", "false")
+ .withEnv("cluster.routing.allocation.disk.watermark.low", "97%")
+ .withEnv("cluster.routing.allocation.disk.watermark.high", "98%")
+ .withEnv("cluster.routing.allocation.disk.watermark.flood_stage", "99%");
container.setPortBindings(Collections.singletonList(ELASTICSEARCH_PORT + ":9200"));
container.start();
return container;
diff --git a/tests/test-spring-boot-2.5-scriptsInJarFile/pom.xml b/tests/test-spring-boot-2.5-scriptsInJarFile/pom.xml
index 15e0f2c0..ec09bf0e 100644
--- a/tests/test-spring-boot-2.5-scriptsInJarFile/pom.xml
+++ b/tests/test-spring-boot-2.5-scriptsInJarFile/pom.xml
@@ -5,12 +5,12 @@
org.springframework.boot
spring-boot-starter-parent
- 2.5.11
+ 2.5.14
com.senacor.elasticsearch.evolution
test-spring-boot-2.5-scriptsInJarFile
- 0.4.0
+ 0.4.1
Demo project for Spring Boot
@@ -18,7 +18,7 @@
2.11.0
7.5.2
- 1.16.3
+ 1.17.5
@@ -85,7 +85,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.8-SNAPSHOT
+ 0.8.8
prepare-agent
diff --git a/tests/test-spring-boot-2.5-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot25/ApplicationTest.java b/tests/test-spring-boot-2.5-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot25/ApplicationTest.java
index 6352ee93..b6de4253 100644
--- a/tests/test-spring-boot-2.5-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot25/ApplicationTest.java
+++ b/tests/test-spring-boot-2.5-scriptsInJarFile/src/test/java/com/senacor/elasticsearch/evolution/springboot25/ApplicationTest.java
@@ -1,5 +1,6 @@
package com.senacor.elasticsearch.evolution.springboot25;
+import com.github.dockerjava.api.command.InspectContainerResponse;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.Test;
@@ -39,10 +40,19 @@ static class Config {
public ElasticsearchContainer elasticsearchContainer(@Value("${elasticsearch.version:7.5.2}") String esVersion) {
ElasticsearchContainer container = new ElasticsearchContainer(DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
- .withTag(esVersion))
+ .withTag(esVersion)) {
+ @Override
+ protected void containerIsStarted(InspectContainerResponse containerInfo) {
+ // since testcontainers 1.17 it detects if ES 8.x is running and copies a certificate in this case
+ // but we don't want security
+ }
+ }
.withEnv("ES_JAVA_OPTS", "-Xms128m -Xmx128m")
// since elasticsearch 8 security / https is enabled per default - but for testing it should be disabled
- .withEnv("xpack.security.enabled", "false");
+ .withEnv("xpack.security.enabled", "false")
+ .withEnv("cluster.routing.allocation.disk.watermark.low", "97%")
+ .withEnv("cluster.routing.allocation.disk.watermark.high", "98%")
+ .withEnv("cluster.routing.allocation.disk.watermark.flood_stage", "99%");
container.setPortBindings(Collections.singletonList(ELASTICSEARCH_PORT + ":9200"));
container.start();
return container;
diff --git a/tests/test-spring-boot-2.6/pom.xml b/tests/test-spring-boot-2.6/pom.xml
index 0225149e..63b56300 100644
--- a/tests/test-spring-boot-2.6/pom.xml
+++ b/tests/test-spring-boot-2.6/pom.xml
@@ -5,12 +5,12 @@
org.springframework.boot
spring-boot-starter-parent
- 2.6.6
+ 2.6.14
com.senacor.elasticsearch.evolution
test-spring-boot-2.6
- 0.4.0
+ 0.4.1
Demo project for Spring Boot
@@ -18,7 +18,7 @@
2.11.0
7.5.2
- 1.16.3
+ 1.17.5
@@ -78,7 +78,7 @@
org.jacoco
jacoco-maven-plugin
- 0.8.8-SNAPSHOT
+ 0.8.8
prepare-agent
diff --git a/tests/test-spring-boot-2.6/src/main/java/com/senacor/elasticsearch/evolution/springboot24/Application.java b/tests/test-spring-boot-2.6/src/main/java/com/senacor/elasticsearch/evolution/springboot26/Application.java
similarity index 82%
rename from tests/test-spring-boot-2.6/src/main/java/com/senacor/elasticsearch/evolution/springboot24/Application.java
rename to tests/test-spring-boot-2.6/src/main/java/com/senacor/elasticsearch/evolution/springboot26/Application.java
index 6778bd46..ac199c30 100644
--- a/tests/test-spring-boot-2.6/src/main/java/com/senacor/elasticsearch/evolution/springboot24/Application.java
+++ b/tests/test-spring-boot-2.6/src/main/java/com/senacor/elasticsearch/evolution/springboot26/Application.java
@@ -1,4 +1,4 @@
-package com.senacor.elasticsearch.evolution.springboot24;
+package com.senacor.elasticsearch.evolution.springboot26;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot24/ApplicationTests.java b/tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot26/ApplicationTests.java
similarity index 71%
rename from tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot24/ApplicationTests.java
rename to tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot26/ApplicationTests.java
index cc5f8b5a..d8cd75ea 100644
--- a/tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot24/ApplicationTests.java
+++ b/tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot26/ApplicationTests.java
@@ -1,5 +1,6 @@
-package com.senacor.elasticsearch.evolution.springboot24;
+package com.senacor.elasticsearch.evolution.springboot26;
+import com.github.dockerjava.api.command.InspectContainerResponse;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.Test;
@@ -39,10 +40,19 @@ static class Config {
public ElasticsearchContainer elasticsearchContainer(@Value("${elasticsearch.version:7.5.2}") String esVersion) {
ElasticsearchContainer container = new ElasticsearchContainer(DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch")
- .withTag(esVersion))
+ .withTag(esVersion)) {
+ @Override
+ protected void containerIsStarted(InspectContainerResponse containerInfo) {
+ // since testcontainers 1.17 it detects if ES 8.x is running and copies a certificate in this case
+ // but we don't want security
+ }
+ }
.withEnv("ES_JAVA_OPTS", "-Xms128m -Xmx128m")
// since elasticsearch 8 security / https is enabled per default - but for testing it should be disabled
- .withEnv("xpack.security.enabled", "false");
+ .withEnv("xpack.security.enabled", "false")
+ .withEnv("cluster.routing.allocation.disk.watermark.low", "97%")
+ .withEnv("cluster.routing.allocation.disk.watermark.high", "98%")
+ .withEnv("cluster.routing.allocation.disk.watermark.flood_stage", "99%");
container.setPortBindings(Collections.singletonList(ELASTICSEARCH_PORT + ":9200"));
container.start();
return container;
diff --git a/tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot24/EsUtils.java b/tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot26/EsUtils.java
similarity index 97%
rename from tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot24/EsUtils.java
rename to tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot26/EsUtils.java
index 93ad5096..31d618ff 100644
--- a/tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot24/EsUtils.java
+++ b/tests/test-spring-boot-2.6/src/test/java/com/senacor/elasticsearch/evolution/springboot26/EsUtils.java
@@ -1,4 +1,4 @@
-package com.senacor.elasticsearch.evolution.springboot24;
+package com.senacor.elasticsearch.evolution.springboot26;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/tests/test-spring-boot-2.7/pom.xml b/tests/test-spring-boot-2.7/pom.xml
new file mode 100644
index 00000000..195a8d1b
--- /dev/null
+++ b/tests/test-spring-boot-2.7/pom.xml
@@ -0,0 +1,107 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.7
+
+
+ com.senacor.elasticsearch.evolution
+ test-spring-boot-2.7
+ 0.4.1
+ Demo project for Spring Boot
+
+
+ 1.8
+
+ 2.11.0
+ 7.5.2
+ 1.17.5
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ ${project.groupId}
+ spring-boot-starter-elasticsearch-evolution
+ ${project.version}
+
+
+
+
+ org.testcontainers
+ elasticsearch
+ ${testcontainers.elasticsearch.version}
+ test
+
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+ test
+
+
+
+
+
+ oss.sonatype.org-snapshot
+ https://oss.sonatype.org/content/repositories/snapshots
+
+ false
+
+
+ true
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+ 0.8.8
+
+
+ prepare-agent
+
+ prepare-agent
+
+
+
+ report
+ post-integration-test
+
+ report
+
+
+
+
+
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
+
diff --git a/tests/test-spring-boot-2.7/src/main/java/com/senacor/elasticsearch/evolution/springboot27/Application.java b/tests/test-spring-boot-2.7/src/main/java/com/senacor/elasticsearch/evolution/springboot27/Application.java
new file mode 100644
index 00000000..a22e3a8b
--- /dev/null
+++ b/tests/test-spring-boot-2.7/src/main/java/com/senacor/elasticsearch/evolution/springboot27/Application.java
@@ -0,0 +1,14 @@
+package com.senacor.elasticsearch.evolution.springboot27;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+
+}
\ No newline at end of file
diff --git a/tests/test-spring-boot-2.7/src/main/resources/es/migration/V001.00__createTemplateWithIndexMapping.http b/tests/test-spring-boot-2.7/src/main/resources/es/migration/V001.00__createTemplateWithIndexMapping.http
new file mode 100644
index 00000000..fbd7df47
--- /dev/null
+++ b/tests/test-spring-boot-2.7/src/main/resources/es/migration/V001.00__createTemplateWithIndexMapping.http
@@ -0,0 +1,35 @@
+PUT _template/test_1
+Content-Type: application/json
+
+{
+ "index_patterns" : [
+ "test_*"
+ ],
+ "order" : 1,
+ "version" : 1,
+ "settings" : {
+ "number_of_shards" : 1
+ },
+ "mappings" : {
+ "dynamic" : "strict",
+ "properties" : {
+ "doc" : {
+ "dynamic" : false,
+ "properties" : {}
+ },
+ "searchable" : {
+ "dynamic" : false,
+ "properties" : {
+ "version" : {
+ "type" : "keyword",
+ "ignore_above" : 20,
+ "similarity" : "boolean"
+ },
+ "locked" : {
+ "type" : "boolean"
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/test-spring-boot-2.7/src/main/resources/es/migration/V001.01__addDocument.http b/tests/test-spring-boot-2.7/src/main/resources/es/migration/V001.01__addDocument.http
new file mode 100644
index 00000000..4f18ba0a
--- /dev/null
+++ b/tests/test-spring-boot-2.7/src/main/resources/es/migration/V001.01__addDocument.http
@@ -0,0 +1,17 @@
+PUT /test_1/_doc/1?refresh
+Content-Type: application/json
+
+{
+ "searchable": {
+ "version": "1",
+ "locked": false
+ },
+ "doc": {
+ "version": "1",
+ "locked": false,
+ "success": true,
+ "a": "a a a",
+ "b": true,
+ "c": "c"
+ }
+}
\ No newline at end of file
diff --git a/tests/test-spring-boot-2.7/src/test/java/com/senacor/elasticsearch/evolution/springboot27/ApplicationTests.java b/tests/test-spring-boot-2.7/src/test/java/com/senacor/elasticsearch/evolution/springboot27/ApplicationTests.java
new file mode 100644
index 00000000..40a4e773
--- /dev/null
+++ b/tests/test-spring-boot-2.7/src/test/java/com/senacor/elasticsearch/evolution/springboot27/ApplicationTests.java
@@ -0,0 +1,66 @@
+package com.senacor.elasticsearch.evolution.springboot27;
+
+import com.github.dockerjava.api.command.InspectContainerResponse;
+import org.apache.http.HttpHost;
+import org.elasticsearch.client.RestClient;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.testcontainers.elasticsearch.ElasticsearchContainer;
+import org.testcontainers.utility.DockerImageName;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest(properties = {"spring.elasticsearch.uris=http://localhost:" + ApplicationTests.ELASTICSEARCH_PORT})
+class ApplicationTests {
+
+ static final int ELASTICSEARCH_PORT = 18773;
+
+ @Autowired
+ private EsUtils esUtils;
+
+ @Test
+ void contextLoads() {
+ esUtils.refreshIndices();
+
+ List documents = esUtils.fetchAllDocuments("test_1");
+
+ assertThat(documents).hasSize(1);
+ }
+
+ @TestConfiguration
+ static class Config {
+ @Bean(destroyMethod = "stop")
+ public ElasticsearchContainer elasticsearchContainer(@Value("${elasticsearch.version:7.5.2}") String esVersion) {
+ ElasticsearchContainer container = new ElasticsearchContainer(DockerImageName
+ .parse("docker.elastic.co/elasticsearch/elasticsearch")
+ .withTag(esVersion)) {
+ @Override
+ protected void containerIsStarted(InspectContainerResponse containerInfo) {
+ // since testcontainers 1.17 it detects if ES 8.x is running and copies a certificate in this case
+ // but we don't want security
+ }
+ }
+ .withEnv("ES_JAVA_OPTS", "-Xms128m -Xmx128m")
+ // since elasticsearch 8 security / https is enabled per default - but for testing it should be disabled
+ .withEnv("xpack.security.enabled", "false")
+ .withEnv("cluster.routing.allocation.disk.watermark.low", "97%")
+ .withEnv("cluster.routing.allocation.disk.watermark.high", "98%")
+ .withEnv("cluster.routing.allocation.disk.watermark.flood_stage", "99%");
+ container.setPortBindings(Collections.singletonList(ELASTICSEARCH_PORT + ":9200"));
+ container.start();
+ return container;
+ }
+
+ @Bean
+ public EsUtils esUtils(ElasticsearchContainer elasticsearchContainer) {
+ return new EsUtils(RestClient.builder(HttpHost.create(elasticsearchContainer.getHttpHostAddress())).build());
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/test-spring-boot-2.7/src/test/java/com/senacor/elasticsearch/evolution/springboot27/EsUtils.java b/tests/test-spring-boot-2.7/src/test/java/com/senacor/elasticsearch/evolution/springboot27/EsUtils.java
new file mode 100644
index 00000000..9c550f6a
--- /dev/null
+++ b/tests/test-spring-boot-2.7/src/test/java/com/senacor/elasticsearch/evolution/springboot27/EsUtils.java
@@ -0,0 +1,72 @@
+package com.senacor.elasticsearch.evolution.springboot27;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.io.IOUtils;
+import org.elasticsearch.client.Request;
+import org.elasticsearch.client.Response;
+import org.elasticsearch.client.RestClient;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * @author Andreas Keefer
+ */
+public class EsUtils {
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ private final RestClient restClient;
+
+ public EsUtils(RestClient restClient) {
+ this.restClient = restClient;
+ }
+
+ public void refreshIndices() {
+ try {
+ restClient.performRequest(new Request("GET", "/_refresh"));
+ } catch (IOException e) {
+ throw new IllegalStateException("refreshIndices failed", e);
+ }
+ }
+
+ public List fetchAllDocuments(String index) {
+ try {
+ Request post = new Request("POST", "/" + index + "/_search");
+ post.setJsonEntity("{" +
+ " \"query\": {" +
+ " \"match_all\": {}" +
+ " }" +
+ "}");
+ Response response = restClient.performRequest(post);
+ int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode < 200 || statusCode >= 300) {
+ throw new IllegalStateException("fetchAllDocuments(" + index + ") failed with HTTP status " +
+ statusCode + ": " + response.toString());
+ }
+ String body = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
+
+ return parseDocuments(body)
+ .collect(Collectors.toList());
+ } catch (IOException e) {
+ throw new IllegalStateException("fetchAllDocuments(" + index + ") failed", e);
+ }
+ }
+
+ private Stream parseDocuments(String body) {
+ try {
+ JsonNode jsonNode = OBJECT_MAPPER.readTree(body);
+ return StreamSupport.stream(jsonNode.get("hits").get("hits").spliterator(), false)
+ .map(hitNode -> hitNode.get("_source"))
+ .map(JsonNode::toString);
+ } catch (IOException e) {
+ throw new IllegalStateException("parseDocuments failed. body=" + body, e);
+ }
+ }
+}
+