From 3338469676c184164333fa0f40f49477c83bd87f Mon Sep 17 00:00:00 2001 From: Davide Angelocola Date: Mon, 25 May 2026 08:33:33 +0200 Subject: [PATCH 1/2] feat: add vortex module with from-vortex command Reads Vortex files into typed records via vortex-jni 0.72.0 + Apache Arrow 19.0.0. Generic schema detection at runtime via VectorSchemaRoot; type-switch maps Arrow column types to hosh Values. to-vortex stubbed pending write API. Roundtrip test writes a file with VortexWriter and reads it back via FromVortex. Co-Authored-By: Claude Sonnet 4.6 --- main/pom.xml | 6 + modules/vortex/.jqwik-database | Bin 0 -> 4 bytes modules/vortex/pom.xml | 83 +++++++ .../hosh/modules/vortex/VortexModule.java | 168 ++++++++++++++ modules/vortex/src/main/java/module-info.java | 30 +++ .../META-INF/services/hosh.spi.Module | 1 + .../vortex/VortexModuleFitnessTest.java | 32 +++ .../hosh/modules/vortex/VortexModuleTest.java | 218 ++++++++++++++++++ pom.xml | 33 +++ 9 files changed, 571 insertions(+) create mode 100644 modules/vortex/.jqwik-database create mode 100644 modules/vortex/pom.xml create mode 100644 modules/vortex/src/main/java/hosh/modules/vortex/VortexModule.java create mode 100644 modules/vortex/src/main/java/module-info.java create mode 100644 modules/vortex/src/main/resources/META-INF/services/hosh.spi.Module create mode 100644 modules/vortex/src/test/java/hosh/modules/vortex/VortexModuleFitnessTest.java create mode 100644 modules/vortex/src/test/java/hosh/modules/vortex/VortexModuleTest.java diff --git a/main/pom.xml b/main/pom.xml index 1173a771..f3c2dddd 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -67,6 +67,12 @@ ${project.version} runtime + + hosh + hosh-vortex-module + ${project.version} + runtime + hosh hosh-checksum-module diff --git a/modules/vortex/.jqwik-database b/modules/vortex/.jqwik-database new file mode 100644 index 0000000000000000000000000000000000000000..711006c3d3b5c6d50049e3f48311f3dbe372803d GIT binary patch literal 4 LcmZ4UmVp%j1%Lsc literal 0 HcmV?d00001 diff --git a/modules/vortex/pom.xml b/modules/vortex/pom.xml new file mode 100644 index 00000000..a64c7d58 --- /dev/null +++ b/modules/vortex/pom.xml @@ -0,0 +1,83 @@ + + + + hosh-parent + hosh + 0.2.1-SNAPSHOT + ../../pom.xml + + 4.0.0 + hosh-vortex-module + + + + org.apache.maven.plugins + maven-surefire-plugin + + -javaagent:${mockito.agent.path} --enable-native-access=vortex.jni -Darrow.allocation.manager.type=Unsafe --add-opens=java.base/java.nio=org.apache.arrow.memory.core --add-opens=java.base/java.nio=org.apache.arrow.c + + + + + + + hosh + hosh-spi + ${project.version} + + + dev.vortex + vortex-jni + + + org.apache.arrow + arrow-vector + + + org.apache.arrow + arrow-memory-core + + + org.apache.arrow + arrow-c-data + + + org.apache.arrow + arrow-memory-unsafe + test + + + + hosh + hosh-test-support + ${project.version} + test + + + hosh + hosh-spi-test-support + ${project.version} + test + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + + diff --git a/modules/vortex/src/main/java/hosh/modules/vortex/VortexModule.java b/modules/vortex/src/main/java/hosh/modules/vortex/VortexModule.java new file mode 100644 index 00000000..5c638306 --- /dev/null +++ b/modules/vortex/src/main/java/hosh/modules/vortex/VortexModule.java @@ -0,0 +1,168 @@ +/* + * MIT License + * + * Copyright (c) 2018-2026 Davide Angelocola + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package hosh.modules.vortex; + +import dev.vortex.api.DataSource; +import dev.vortex.api.Partition; +import dev.vortex.api.Scan; +import dev.vortex.api.ScanOptions; +import dev.vortex.api.Session; +import dev.vortex.arrow.ArrowAllocation; +import dev.vortex.jni.NativeLoader; +import hosh.doc.Description; +import hosh.doc.Example; +import hosh.doc.Examples; +import hosh.spi.Command; +import hosh.spi.CommandArguments; +import hosh.spi.CommandName; +import hosh.spi.CommandRegistry; +import hosh.spi.Errors; +import hosh.spi.ExitStatus; +import hosh.spi.InputChannel; +import hosh.spi.Keys; +import hosh.spi.Module; +import hosh.spi.OutputChannel; +import hosh.spi.Records; +import hosh.spi.State; +import hosh.spi.StateAware; +import hosh.spi.Value; +import hosh.spi.Values; +import org.apache.arrow.memory.BufferAllocator; +import org.apache.arrow.vector.BigIntVector; +import org.apache.arrow.vector.BitVector; +import org.apache.arrow.vector.DateDayVector; +import org.apache.arrow.vector.FieldVector; +import org.apache.arrow.vector.Float4Vector; +import org.apache.arrow.vector.Float8Vector; +import org.apache.arrow.vector.IntVector; +import org.apache.arrow.vector.VarCharVector; +import org.apache.arrow.vector.VectorSchemaRoot; +import org.apache.arrow.vector.ipc.ArrowReader; +import org.apache.arrow.vector.types.pojo.Field; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDate; +import java.util.List; + +public class VortexModule implements Module { + + @Override + public void initialize(CommandRegistry registry) { + registry.registerCommand(CommandName.constant("from-vortex"), FromVortex::new); + registry.registerCommand(CommandName.constant("to-vortex"), ToVortex::new); + } + + @Description("read a Vortex file into records, one record per row") + @Examples({ + @Example(description = "read records from a Vortex file", command = "from-vortex data.vortex"), + @Example(description = "read and count records from a Vortex file", command = "from-vortex data.vortex | count"), + }) + public static class FromVortex implements Command, StateAware { + + static { + NativeLoader.loadJni(); + } + + private State state; + + @Override + public void setState(State state) { + this.state = state; + } + + @Override + public ExitStatus run(CommandArguments args, InputChannel in, OutputChannel out, OutputChannel err) { + if (args.size() != 1) { + err.send(Errors.usage("from-vortex file")); + return ExitStatus.error(); + } + Path source = args.get(0).asPath(state); + if (!Files.exists(source)) { + err.send(Errors.message("file not found: %s", source)); + return ExitStatus.error(); + } + if (!Files.isRegularFile(source)) { + err.send(Errors.message("not a regular file: %s", source)); + return ExitStatus.error(); + } + String uri = source.toUri().toString(); + BufferAllocator allocator = ArrowAllocation.rootAllocator(); + try { + DataSource ds = DataSource.open(Session.create(), uri); + Scan scan = ds.scan(ScanOptions.of()); + while (scan.hasNext()) { + Partition partition = scan.next(); + try (ArrowReader reader = partition.scanArrow(allocator)) { + while (reader.loadNextBatch()) { + VectorSchemaRoot root = reader.getVectorSchemaRoot(); + List fields = root.getSchema().getFields(); + int rowCount = root.getRowCount(); + for (int i = 0; i < rowCount; i++) { + Records.Builder builder = Records.builder(); + for (Field field : fields) { + FieldVector vector = root.getVector(field.getName()); + Value value = vector.isNull(i) ? Values.none() : toValue(vector, i); + builder.entry(Keys.of(field.getName()), value); + } + out.send(builder.build()); + } + } + } + } + return ExitStatus.success(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private Value toValue(FieldVector vector, int index) { + return switch (vector) { + case VarCharVector v -> Values.ofText(new String(v.get(index), StandardCharsets.UTF_8)); + case BigIntVector v -> Values.ofNumeric(v.get(index)); + case IntVector v -> Values.ofNumeric(v.get(index)); + case Float8Vector v -> Values.ofText(Double.toString(v.get(index))); + case Float4Vector v -> Values.ofText(Float.toString(v.get(index))); + case DateDayVector v -> Values.ofText(LocalDate.ofEpochDay(v.get(index)).toString()); + case BitVector v -> Values.ofText(v.get(index) != 0 ? "true" : "false"); + default -> Values.ofText(vector.getObject(index).toString()); + }; + } + } + + @Description("write a stream of records to a Vortex file") + @Examples({ + @Example(description = "save ls output to a Vortex file", command = "ls | to-vortex output.vortex"), + }) + public static class ToVortex implements Command { + + @Override + public ExitStatus run(CommandArguments args, InputChannel in, OutputChannel out, OutputChannel err) { + throw new UnsupportedOperationException("to-vortex: write support not yet implemented"); + } + } +} diff --git a/modules/vortex/src/main/java/module-info.java b/modules/vortex/src/main/java/module-info.java new file mode 100644 index 00000000..19550a25 --- /dev/null +++ b/modules/vortex/src/main/java/module-info.java @@ -0,0 +1,30 @@ +/* + * MIT License + * + * Copyright (c) 2018-2026 Davide Angelocola + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +module hosh.modules.vortex { + requires hosh.spi; + requires vortex.jni; + requires org.apache.arrow.vector; + requires org.apache.arrow.memory.core; + requires org.apache.arrow.c; +} diff --git a/modules/vortex/src/main/resources/META-INF/services/hosh.spi.Module b/modules/vortex/src/main/resources/META-INF/services/hosh.spi.Module new file mode 100644 index 00000000..2eb94bcf --- /dev/null +++ b/modules/vortex/src/main/resources/META-INF/services/hosh.spi.Module @@ -0,0 +1 @@ +hosh.modules.vortex.VortexModule diff --git a/modules/vortex/src/test/java/hosh/modules/vortex/VortexModuleFitnessTest.java b/modules/vortex/src/test/java/hosh/modules/vortex/VortexModuleFitnessTest.java new file mode 100644 index 00000000..5761490d --- /dev/null +++ b/modules/vortex/src/test/java/hosh/modules/vortex/VortexModuleFitnessTest.java @@ -0,0 +1,32 @@ +/* + * MIT License + * + * Copyright (c) 2018-2026 Davide Angelocola + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package hosh.modules.vortex; + +import com.tngtech.archunit.junit.AnalyzeClasses; +import hosh.test.fitness.UnitTestsFitnessTest; + +@AnalyzeClasses(packagesOf = VortexModule.class) +class VortexModuleFitnessTest extends UnitTestsFitnessTest { + +} diff --git a/modules/vortex/src/test/java/hosh/modules/vortex/VortexModuleTest.java b/modules/vortex/src/test/java/hosh/modules/vortex/VortexModuleTest.java new file mode 100644 index 00000000..0a2b074e --- /dev/null +++ b/modules/vortex/src/test/java/hosh/modules/vortex/VortexModuleTest.java @@ -0,0 +1,218 @@ +/* + * MIT License + * + * Copyright (c) 2018-2026 Davide Angelocola + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package hosh.modules.vortex; + +import dev.vortex.api.Session; +import dev.vortex.api.VortexWriter; +import dev.vortex.arrow.ArrowAllocation; +import hosh.modules.vortex.VortexModule.FromVortex; +import hosh.modules.vortex.VortexModule.ToVortex; +import hosh.spi.CommandArguments; +import hosh.spi.ExitStatus; +import hosh.spi.InputChannel; +import hosh.spi.Keys; +import hosh.spi.OutputChannel; +import hosh.spi.Records; +import hosh.spi.State; +import hosh.spi.Values; +import hosh.test.support.TemporaryFolder; +import org.apache.arrow.c.ArrowArray; +import org.apache.arrow.c.ArrowSchema; +import org.apache.arrow.c.Data; +import org.apache.arrow.memory.BufferAllocator; +import org.apache.arrow.vector.BigIntVector; +import org.apache.arrow.vector.VarCharVector; +import org.apache.arrow.vector.VectorSchemaRoot; +import org.apache.arrow.vector.types.pojo.ArrowType; +import org.apache.arrow.vector.types.pojo.Field; +import org.apache.arrow.vector.types.pojo.Schema; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import static hosh.spi.test.support.ExitStatusAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.BDDMockito.then; + +class VortexModuleTest { + + @Nested + @ExtendWith(MockitoExtension.class) + class FromVortexTest { + + @RegisterExtension + final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Mock(stubOnly = true) + State state; + + @Mock + InputChannel in; + + @Mock + OutputChannel out; + + @Mock + OutputChannel err; + + FromVortex sut; + + @BeforeEach + void createSut() { + sut = new FromVortex(); + sut.setState(state); + } + + @Test + void missingArg() { + // Given + // (no setup) + // When + ExitStatus result = sut.run(CommandArguments.of(), in, out, err); + // Then + assertThat(result).isError(); + then(in).shouldHaveNoInteractions(); + then(out).shouldHaveNoInteractions(); + then(err).should().send(Records.singleton(Keys.ERROR, Values.ofText("usage: from-vortex file"))); + } + + @Test + void tooManyArgs() { + // Given + // (no setup) + // When + ExitStatus result = sut.run(CommandArguments.of("a.vortex", "b.vortex"), in, out, err); + // Then + assertThat(result).isError(); + then(in).shouldHaveNoInteractions(); + then(out).shouldHaveNoInteractions(); + then(err).should().send(Records.singleton(Keys.ERROR, Values.ofText("usage: from-vortex file"))); + } + + @Test + void fileNotFound() { + // Given + Path missing = temporaryFolder.toPath().resolve("missing.vortex").toAbsolutePath(); + // When + ExitStatus result = sut.run(CommandArguments.of(missing.toString()), in, out, err); + // Then + assertThat(result).isError(); + then(in).shouldHaveNoInteractions(); + then(out).shouldHaveNoInteractions(); + then(err).should().send(Records.singleton(Keys.ERROR, Values.ofText("file not found: " + missing))); + } + + @Test + void notAFile() { + // Given + Path dir = temporaryFolder.toPath().toAbsolutePath(); + // When + ExitStatus result = sut.run(CommandArguments.of(dir.toString()), in, out, err); + // Then + assertThat(result).isError(); + then(in).shouldHaveNoInteractions(); + then(out).shouldHaveNoInteractions(); + then(err).should().send(Records.singleton(Keys.ERROR, Values.ofText("not a regular file: " + dir))); + } + + @Test + void readRecords() throws IOException { + // Given + Path file = temporaryFolder.toPath().resolve("test.vortex").toAbsolutePath(); + writeVortexFile(file); + // When + ExitStatus result = sut.run(CommandArguments.of(file.toString()), in, out, err); + // Then + assertThat(result).isSuccess(); + then(in).shouldHaveNoInteractions(); + then(out).should().send(Records.builder().entry(Keys.of("name"), Values.ofText("alice")).entry(Keys.of("age"), Values.ofNumeric(30)).build()); + then(out).should().send(Records.builder().entry(Keys.of("name"), Values.ofText("bob")).entry(Keys.of("age"), Values.ofNumeric(25)).build()); + then(err).shouldHaveNoInteractions(); + } + + private static void writeVortexFile(Path path) throws IOException { + Schema schema = new Schema(List.of( + Field.notNullable("name", ArrowType.Utf8.INSTANCE), + Field.notNullable("age", new ArrowType.Int(64, true)) + )); + BufferAllocator allocator = ArrowAllocation.rootAllocator(); + String uri = path.toUri().toString(); + try (VortexWriter writer = VortexWriter.create(Session.create(), uri, schema, Map.of(), allocator); + VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator)) { + VarCharVector nameVec = (VarCharVector) root.getVector("name"); + BigIntVector ageVec = (BigIntVector) root.getVector("age"); + nameVec.allocateNew(2); + ageVec.allocateNew(2); + nameVec.setSafe(0, "alice".getBytes(StandardCharsets.UTF_8)); + ageVec.setSafe(0, 30); + nameVec.setSafe(1, "bob".getBytes(StandardCharsets.UTF_8)); + ageVec.setSafe(1, 25); + root.setRowCount(2); + try (ArrowArray arr = ArrowArray.allocateNew(allocator); + ArrowSchema arrowSchema = ArrowSchema.allocateNew(allocator)) { + Data.exportVectorSchemaRoot(allocator, root, null, arr, arrowSchema); + writer.writeBatch(arr.memoryAddress(), arrowSchema.memoryAddress()); + } + } + } + } + + @Nested + @ExtendWith(MockitoExtension.class) + class ToVortexTest { + + @Mock + InputChannel in; + + @Mock + OutputChannel out; + + @Mock + OutputChannel err; + + ToVortex sut; + + @BeforeEach + void createSut() { + sut = new ToVortex(); + } + + @Test + void notYetImplemented() { + assertThatThrownBy(() -> sut.run(CommandArguments.of("output.vortex"), in, out, err)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessage("to-vortex: write support not yet implemented"); + } + } +} diff --git a/pom.xml b/pom.xml index a70e985e..8cb0720c 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,8 @@ 4.0.14 4.2.0 1.0.0.Beta2 + 0.72.0 + 19.0.0 2.1.0 2.1.3 @@ -64,6 +66,7 @@ modules/filesystem modules/formats modules/parquet + modules/vortex modules/checksum main @@ -147,6 +150,11 @@ jqwik ${version.jqwik} + + org.slf4j + slf4j-api + ${version.slf4j} + org.slf4j slf4j-simple @@ -172,6 +180,31 @@ hardwood-core ${version.hardwood} + + dev.vortex + vortex-jni + ${version.vortex} + + + org.apache.arrow + arrow-vector + ${version.arrow} + + + org.apache.arrow + arrow-memory-core + ${version.arrow} + + + org.apache.arrow + arrow-c-data + ${version.arrow} + + + org.apache.arrow + arrow-memory-unsafe + ${version.arrow} + From 584cd891113719557338a171e635f89865bfad3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 08:58:23 +0000 Subject: [PATCH 2/2] build(deps): bump net.jqwik:jqwik from 1.9.3 to 1.10.0 Bumps [net.jqwik:jqwik](https://github.com/jqwik-team/jqwik) from 1.9.3 to 1.10.0. - [Release notes](https://github.com/jqwik-team/jqwik/releases) - [Commits](https://github.com/jqwik-team/jqwik/compare/1.9.3...1.10.0) --- updated-dependencies: - dependency-name: net.jqwik:jqwik dependency-version: 1.10.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8cb0720c..4d722a47 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 5.23.0 4.5 1.4.2 - 1.9.3 + 1.10.0 2.0.17 ${settings.localRepository}/org/mockito/mockito-core/${version.mockito}/mockito-core-${version.mockito}.jar