diff --git a/LICENSE b/LICENSE
index 46167007c6de..efb46dab44da 100644
--- a/LICENSE
+++ b/LICENSE
@@ -227,7 +227,6 @@ This product includes code from Apache Parquet.
* DynMethods.java
* DynConstructors.java
-* AssertHelpers.java
* IOUtil.java readFully and tests
* ByteBufferInputStream implementations and tests
diff --git a/api/src/test/java/org/apache/iceberg/AssertHelpers.java b/api/src/test/java/org/apache/iceberg/AssertHelpers.java
deleted file mode 100644
index a1cf1b20797e..000000000000
--- a/api/src/test/java/org/apache/iceberg/AssertHelpers.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.iceberg;
-
-import java.util.concurrent.Callable;
-import org.apache.avro.AvroRuntimeException;
-import org.apache.avro.generic.GenericRecord;
-import org.assertj.core.api.AbstractThrowableAssert;
-import org.assertj.core.api.Assertions;
-import org.assertj.core.api.ThrowableAssert;
-
-/**
- * This class is deprecated. Please use {@link
- * Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)} directly as shown below:
- *
- *
- * Assertions.assertThatThrownBy(() -> throwingCallable)
- * .isInstanceOf(ExpectedException.class)
- * .hasMessage(expectedErrorMsg)
- *
- *
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)} directly
- * as it provides a more fluent way of asserting on exceptions.
- */
-@Deprecated
-public class AssertHelpers {
-
- private AssertHelpers() {}
-
- /**
- * A convenience method to avoid a large number of @Test(expected=...) tests
- *
- * @param message A String message to describe this assertion
- * @param expected An Exception class that the Runnable should throw
- * @param containedInMessage A String that should be contained by the thrown exception's message
- * @param callable A Callable that is expected to throw the exception
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)}
- * directly as it provides a more fluent way of asserting on exceptions.
- */
- @Deprecated
- public static void assertThrows(
- String message,
- Class extends Exception> expected,
- String containedInMessage,
- Callable callable) {
- AbstractThrowableAssert, ? extends Throwable> check =
- Assertions.assertThatThrownBy(callable::call).as(message).isInstanceOf(expected);
- if (null != containedInMessage) {
- check.hasMessageContaining(containedInMessage);
- }
- }
-
- /**
- * A convenience method to avoid a large number of @Test(expected=...) tests
- *
- * @param message A String message to describe this assertion
- * @param expected An Exception class that the Runnable should throw
- * @param containedInMessage A String that should be contained by the thrown exception's message
- * @param runnable A Runnable that is expected to throw the runtime exception
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)}
- * directly as it provides a more fluent way of asserting on exceptions.
- */
- @Deprecated
- public static void assertThrows(
- String message,
- Class extends Exception> expected,
- String containedInMessage,
- Runnable runnable) {
- AbstractThrowableAssert, ? extends Throwable> check =
- Assertions.assertThatThrownBy(runnable::run).as(message).isInstanceOf(expected);
- if (null != containedInMessage) {
- check.hasMessageContaining(containedInMessage);
- }
- }
-
- /**
- * A convenience method to avoid a large number of @Test(expected=...) tests
- *
- * @param message A String message to describe this assertion
- * @param expected An Exception class that the Runnable should throw
- * @param callable A Callable that is expected to throw the exception
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)}
- * directly as it provides a more fluent way of asserting on exceptions.
- */
- @Deprecated
- public static void assertThrows(
- String message, Class extends Exception> expected, Callable callable) {
- assertThrows(message, expected, null, callable);
- }
-
- /**
- * A convenience method to avoid a large number of @Test(expected=...) tests
- *
- * @param message A String message to describe this assertion
- * @param expected An Exception class that the Runnable should throw
- * @param runnable A Runnable that is expected to throw the runtime exception
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)}
- * directly as it provides a more fluent way of asserting on exceptions.
- */
- @Deprecated
- public static void assertThrows(
- String message, Class extends Exception> expected, Runnable runnable) {
- assertThrows(message, expected, null, runnable);
- }
-
- /**
- * A convenience method to assert the cause of thrown exception.
- *
- * @param message A String message to describe this assertion
- * @param expected An Exception class that the cause of the Runnable should throw
- * @param containedInMessage A String that should be contained by the cause of the thrown
- * exception's message
- * @param runnable A Runnable that is expected to throw the runtime exception
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)}
- * directly as it provides a more fluent way of asserting on exceptions.
- */
- @Deprecated
- public static void assertThrowsCause(
- String message,
- Class extends Exception> expected,
- String containedInMessage,
- Runnable runnable) {
- Assertions.assertThatThrownBy(runnable::run)
- .as(message)
- .getCause()
- .isInstanceOf(expected)
- .hasMessageContaining(containedInMessage);
- }
-
- /**
- * A convenience method to assert both the thrown exception and the cause of thrown exception.
- *
- * @param message A String message to describe this assertion
- * @param expected An Exception class that the Runnable should throw
- * @param expectedContainedInMessage A String that should be contained by the thrown exception's
- * message, will be skipped if null.
- * @param cause An Exception class that the cause of the Runnable should throw
- * @param causeContainedInMessage A String that should be contained by the cause of the thrown
- * exception's message, will be skipped if null.
- * @param runnable A Runnable that is expected to throw the runtime exception
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)}
- * directly as it provides a more fluent way of asserting on exceptions.
- */
- @Deprecated
- public static void assertThrowsWithCause(
- String message,
- Class extends Exception> expected,
- String expectedContainedInMessage,
- Class extends Exception> cause,
- String causeContainedInMessage,
- Runnable runnable) {
- AbstractThrowableAssert, ?> chain =
- Assertions.assertThatThrownBy(runnable::run).as(message).isInstanceOf(expected);
-
- if (expectedContainedInMessage != null) {
- chain = chain.hasMessageContaining(expectedContainedInMessage);
- }
-
- chain = chain.getCause().isInstanceOf(cause);
- if (causeContainedInMessage != null) {
- chain.hasMessageContaining(causeContainedInMessage);
- }
- }
-
- /**
- * A convenience method to check if an Avro field is empty.
- *
- * @param record The record to read from
- * @param field The name of the field
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)}
- * directly as it provides a more fluent way of asserting on exceptions.
- */
- @Deprecated
- public static void assertEmptyAvroField(GenericRecord record, String field) {
- AssertHelpers.assertThrows(
- "Not a valid schema field: " + field, AvroRuntimeException.class, () -> record.get(field));
- }
-
- /**
- * Same as {@link AssertHelpers#assertThrowsCause}, but this method compares root cause.
- *
- * @deprecated Use {@link Assertions#assertThatThrownBy(ThrowableAssert.ThrowingCallable)}
- * directly as it provides a more fluent way of asserting on exceptions.
- */
- @Deprecated
- public static void assertThrowsRootCause(
- String message,
- Class extends Exception> expected,
- String containedInMessage,
- Runnable runnable) {
- Assertions.assertThatThrownBy(runnable::run)
- .as(message)
- .getRootCause()
- .isInstanceOf(expected)
- .hasMessageContaining(containedInMessage);
- }
-}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAddFilesProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAddFilesProcedure.java
index a48deae7421f..aab2ae65d010 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAddFilesProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAddFilesProcedure.java
@@ -34,7 +34,6 @@
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumWriter;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.TableProperties;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
@@ -48,6 +47,7 @@
import org.apache.spark.sql.types.Metadata;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
+import org.assertj.core.api.Assertions;
import org.joda.time.DateTime;
import org.junit.After;
import org.junit.Assert;
@@ -688,23 +688,23 @@ public void invalidDataImport() {
createIcebergTable("id Integer, name String, dept String, subdept String");
- AssertHelpers.assertThrows(
- "Should forbid adding of partitioned data to unpartitioned table",
- IllegalArgumentException.class,
- "Cannot use partition filter with an unpartitioned table",
- () ->
- scalarSql(
- "CALL %s.system.add_files('%s', '`parquet`.`%s`', map('id', 1))",
- catalogName, tableName, fileTableDir.getAbsolutePath()));
-
- AssertHelpers.assertThrows(
- "Should forbid adding of partitioned data to unpartitioned table",
- IllegalArgumentException.class,
- "Cannot add partitioned files to an unpartitioned table",
- () ->
- scalarSql(
- "CALL %s.system.add_files('%s', '`parquet`.`%s`')",
- catalogName, tableName, fileTableDir.getAbsolutePath()));
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql(
+ "CALL %s.system.add_files('%s', '`parquet`.`%s`', map('id', 1))",
+ catalogName, tableName, fileTableDir.getAbsolutePath()))
+ .as("Should forbid adding of partitioned data to unpartitioned table")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot use partition filter with an unpartitioned table");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql(
+ "CALL %s.system.add_files('%s', '`parquet`.`%s`')",
+ catalogName, tableName, fileTableDir.getAbsolutePath()))
+ .as("Should forbid adding of partitioned data to unpartitioned table")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot add partitioned files to an unpartitioned table");
}
@Test
@@ -714,23 +714,24 @@ public void invalidDataImportPartitioned() {
createIcebergTable(
"id Integer, name String, dept String, subdept String", "PARTITIONED BY (id)");
- AssertHelpers.assertThrows(
- "Should forbid adding with a mismatching partition spec",
- IllegalArgumentException.class,
- "is greater than the number of partitioned columns",
- () ->
- scalarSql(
- "CALL %s.system.add_files('%s', '`parquet`.`%s`', map('x', '1', 'y', '2'))",
- catalogName, tableName, fileTableDir.getAbsolutePath()));
-
- AssertHelpers.assertThrows(
- "Should forbid adding with partition spec with incorrect columns",
- IllegalArgumentException.class,
- "specified partition filter refers to columns that are not partitioned",
- () ->
- scalarSql(
- "CALL %s.system.add_files('%s', '`parquet`.`%s`', map('dept', '2'))",
- catalogName, tableName, fileTableDir.getAbsolutePath()));
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql(
+ "CALL %s.system.add_files('%s', '`parquet`.`%s`', map('x', '1', 'y', '2'))",
+ catalogName, tableName, fileTableDir.getAbsolutePath()))
+ .as("Should forbid adding with a mismatching partition spec")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("is greater than the number of partitioned columns");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql(
+ "CALL %s.system.add_files('%s', '`parquet`.`%s`', map('dept', '2'))",
+ catalogName, tableName, fileTableDir.getAbsolutePath()))
+ .as("Should forbid adding with partition spec with incorrect columns")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(
+ "specified partition filter refers to columns that are not partitioned");
}
@Test
@@ -782,18 +783,19 @@ public void duplicateDataPartitioned() {
+ "partition_filter => map('id', 1))",
catalogName, tableName, sourceTableName);
- AssertHelpers.assertThrows(
- "Should not allow adding duplicate files",
- IllegalStateException.class,
- "Cannot complete import because data files to be imported already"
- + " exist within the target table",
- () ->
- scalarSql(
- "CALL %s.system.add_files("
- + "table => '%s', "
- + "source_table => '%s', "
- + "partition_filter => map('id', 1))",
- catalogName, tableName, sourceTableName));
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql(
+ "CALL %s.system.add_files("
+ + "table => '%s', "
+ + "source_table => '%s', "
+ + "partition_filter => map('id', 1))",
+ catalogName, tableName, sourceTableName))
+ .as("Should not allow adding duplicate files")
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageContaining(
+ "Cannot complete import because data files to be imported already"
+ + " exist within the target table");
}
@Test
@@ -841,14 +843,16 @@ public void duplicateDataUnpartitioned() {
sql("CALL %s.system.add_files('%s', '%s')", catalogName, tableName, sourceTableName);
- AssertHelpers.assertThrows(
- "Should not allow adding duplicate files",
- IllegalStateException.class,
- "Cannot complete import because data files to be imported already"
- + " exist within the target table",
- () ->
- scalarSql(
- "CALL %s.system.add_files('%s', '%s')", catalogName, tableName, sourceTableName));
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql(
+ "CALL %s.system.add_files('%s', '%s')",
+ catalogName, tableName, sourceTableName))
+ .as("Should not allow adding duplicate files")
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageContaining(
+ "Cannot complete import because data files to be imported already"
+ + " exist within the target table");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAlterTableSchema.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAlterTableSchema.java
index c993c213dc5e..acbf5c7a632d 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAlterTableSchema.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAlterTableSchema.java
@@ -19,9 +19,9 @@
package org.apache.iceberg.spark.extensions;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Table;
import org.apache.iceberg.relocated.com.google.common.collect.Sets;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
@@ -77,17 +77,16 @@ public void testSetInvalidIdentifierFields() {
Table table = validationCatalog.loadTable(tableIdent);
Assert.assertTrue(
"Table should start without identifier", table.schema().identifierFieldIds().isEmpty());
- AssertHelpers.assertThrows(
- "should not allow setting unknown fields",
- IllegalArgumentException.class,
- "not found in current schema or added columns",
- () -> sql("ALTER TABLE %s SET IDENTIFIER FIELDS unknown", tableName));
-
- AssertHelpers.assertThrows(
- "should not allow setting optional fields",
- IllegalArgumentException.class,
- "not a required field",
- () -> sql("ALTER TABLE %s SET IDENTIFIER FIELDS id2", tableName));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s SET IDENTIFIER FIELDS unknown", tableName))
+ .as("should not allow setting unknown fields")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("not found in current schema or added columns");
+
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s SET IDENTIFIER FIELDS id2", tableName))
+ .as("should not allow setting optional fields")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("not a required field");
}
@Test
@@ -140,23 +139,23 @@ public void testDropInvalidIdentifierFields() {
Table table = validationCatalog.loadTable(tableIdent);
Assert.assertTrue(
"Table should start without identifier", table.schema().identifierFieldIds().isEmpty());
- AssertHelpers.assertThrows(
- "should not allow dropping unknown fields",
- IllegalArgumentException.class,
- "field unknown not found",
- () -> sql("ALTER TABLE %s DROP IDENTIFIER FIELDS unknown", tableName));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s DROP IDENTIFIER FIELDS unknown", tableName))
+ .as("should not allow dropping unknown fields")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("field unknown not found");
sql("ALTER TABLE %s SET IDENTIFIER FIELDS id", tableName);
- AssertHelpers.assertThrows(
- "should not allow dropping a field that is not an identifier",
- IllegalArgumentException.class,
- "data is not an identifier field",
- () -> sql("ALTER TABLE %s DROP IDENTIFIER FIELDS data", tableName));
-
- AssertHelpers.assertThrows(
- "should not allow dropping a nested field that is not an identifier",
- IllegalArgumentException.class,
- "location.lon is not an identifier field",
- () -> sql("ALTER TABLE %s DROP IDENTIFIER FIELDS location.lon", tableName));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s DROP IDENTIFIER FIELDS data", tableName))
+ .as("should not allow dropping a field that is not an identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("data is not an identifier field");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s DROP IDENTIFIER FIELDS location.lon", tableName))
+ .as("should not allow dropping a nested field that is not an identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("location.lon is not an identifier field");
}
}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAncestorsOfProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAncestorsOfProcedure.java
index ae591821e21a..13fa96d1e08a 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAncestorsOfProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestAncestorsOfProcedure.java
@@ -20,10 +20,10 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Table;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.spark.sql.AnalysisException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Test;
@@ -147,22 +147,20 @@ public void testAncestorOfUsingNamedArgs() {
@Test
public void testInvalidAncestorOfCases() {
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.ancestors_of()", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier for parameter 'table'",
- () -> sql("CALL %s.system.ancestors_of('')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type for snapshot_id: cannot cast",
- () -> sql("CALL %s.system.ancestors_of('%s', 1.1)", catalogName, tableIdent));
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.ancestors_of()", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.ancestors_of('')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier for parameter 'table'");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.ancestors_of('%s', 1.1)", catalogName, tableIdent))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type for snapshot_id: cannot cast");
}
}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestBranchDDL.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestBranchDDL.java
index e6ac4cfc4dac..8f3e88f3c811 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestBranchDDL.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestBranchDDL.java
@@ -23,7 +23,6 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Snapshot;
import org.apache.iceberg.SnapshotRef;
import org.apache.iceberg.Table;
@@ -86,11 +85,11 @@ public void testCreateBranch() throws NoSuchTableException {
Assert.assertEquals(TimeUnit.DAYS.toMillis(maxSnapshotAge), ref.maxSnapshotAgeMs().longValue());
Assert.assertEquals(TimeUnit.DAYS.toMillis(maxRefAge), ref.maxRefAgeMs().longValue());
- AssertHelpers.assertThrows(
- "Cannot create an existing branch",
- IllegalArgumentException.class,
- "Ref b1 already exists",
- () -> sql("ALTER TABLE %s CREATE BRANCH %s", tableName, branchName));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s CREATE BRANCH %s", tableName, branchName))
+ .as("Cannot create an existing branch")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Ref b1 already exists");
}
@Test
@@ -196,12 +195,14 @@ public void testCreateBranchUseCustomMinSnapshotsToKeepAndMaxSnapshotAge()
Assert.assertEquals(TimeUnit.DAYS.toMillis(maxSnapshotAge), ref.maxSnapshotAgeMs().longValue());
Assert.assertNull(ref.maxRefAgeMs());
- AssertHelpers.assertThrows(
- "Illegal statement",
- IcebergParseException.class,
- "no viable alternative at input 'WITH SNAPSHOT RETENTION'",
- () ->
- sql("ALTER TABLE %s CREATE BRANCH %s WITH SNAPSHOT RETENTION", tableName, branchName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "ALTER TABLE %s CREATE BRANCH %s WITH SNAPSHOT RETENTION",
+ tableName, branchName))
+ .as("Illegal statement")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("no viable alternative at input 'WITH SNAPSHOT RETENTION'");
}
@Test
@@ -217,26 +218,27 @@ public void testCreateBranchUseCustomMaxRefAge() throws NoSuchTableException {
Assert.assertNull(ref.maxSnapshotAgeMs());
Assert.assertEquals(TimeUnit.DAYS.toMillis(maxRefAge), ref.maxRefAgeMs().longValue());
- AssertHelpers.assertThrows(
- "Illegal statement",
- IcebergParseException.class,
- "mismatched input",
- () -> sql("ALTER TABLE %s CREATE BRANCH %s RETAIN", tableName, branchName));
-
- AssertHelpers.assertThrows(
- "Illegal statement",
- IcebergParseException.class,
- "mismatched input",
- () -> sql("ALTER TABLE %s CREATE BRANCH %s RETAIN %s DAYS", tableName, branchName, "abc"));
-
- AssertHelpers.assertThrows(
- "Illegal statement",
- IcebergParseException.class,
- "mismatched input 'SECONDS' expecting {'DAYS', 'HOURS', 'MINUTES'}",
- () ->
- sql(
- "ALTER TABLE %s CREATE BRANCH %s RETAIN %d SECONDS",
- tableName, branchName, maxRefAge));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s CREATE BRANCH %s RETAIN", tableName, branchName))
+ .as("Illegal statement")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql("ALTER TABLE %s CREATE BRANCH %s RETAIN %s DAYS", tableName, branchName, "abc"))
+ .as("Illegal statement")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "ALTER TABLE %s CREATE BRANCH %s RETAIN %d SECONDS",
+ tableName, branchName, maxRefAge))
+ .as("Illegal statement")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input 'SECONDS' expecting {'DAYS', 'HOURS', 'MINUTES'}");
}
@Test
@@ -258,11 +260,11 @@ public void testDropBranch() throws NoSuchTableException {
@Test
public void testDropBranchDoesNotExist() {
- AssertHelpers.assertThrows(
- "Cannot perform drop branch on branch which does not exist",
- IllegalArgumentException.class,
- "Branch does not exist: nonExistingBranch",
- () -> sql("ALTER TABLE %s DROP BRANCH %s", tableName, "nonExistingBranch"));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s DROP BRANCH %s", tableName, "nonExistingBranch"))
+ .as("Cannot perform drop branch on branch which does not exist")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Branch does not exist: nonExistingBranch");
}
@Test
@@ -271,29 +273,26 @@ public void testDropBranchFailsForTag() throws NoSuchTableException {
Table table = insertRows();
table.manageSnapshots().createTag(tagName, table.currentSnapshot().snapshotId()).commit();
- AssertHelpers.assertThrows(
- "Cannot perform drop branch on tag",
- IllegalArgumentException.class,
- "Ref b1 is a tag not a branch",
- () -> sql("ALTER TABLE %s DROP BRANCH %s", tableName, tagName));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s DROP BRANCH %s", tableName, tagName))
+ .as("Cannot perform drop branch on tag")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Ref b1 is a tag not a branch");
}
@Test
public void testDropBranchNonConformingName() {
- AssertHelpers.assertThrows(
- "Non-conforming branch name",
- IcebergParseException.class,
- "mismatched input '123'",
- () -> sql("ALTER TABLE %s DROP BRANCH %s", tableName, "123"));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s DROP BRANCH %s", tableName, "123"))
+ .as("Non-conforming branch name")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input '123'");
}
@Test
public void testDropMainBranchFails() {
- AssertHelpers.assertThrows(
- "Cannot drop the main branch",
- IllegalArgumentException.class,
- "Cannot remove main branch",
- () -> sql("ALTER TABLE %s DROP BRANCH main", tableName));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s DROP BRANCH main", tableName))
+ .as("Cannot drop the main branch")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot remove main branch");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestCallStatementParser.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestCallStatementParser.java
index 9c2233ccb791..c0f7ff1f8f9b 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestCallStatementParser.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestCallStatementParser.java
@@ -22,7 +22,6 @@
import java.sql.Timestamp;
import java.time.Instant;
import java.util.List;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.Lists;
import org.apache.spark.sql.SparkSession;
@@ -38,6 +37,7 @@
import org.apache.spark.sql.catalyst.plans.logical.PositionalArgument;
import org.apache.spark.sql.types.DataType;
import org.apache.spark.sql.types.DataTypes;
+import org.assertj.core.api.Assertions;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -144,11 +144,10 @@ public void testCallWithVarSubstitution() throws ParseException {
@Test
public void testCallParseError() {
- AssertHelpers.assertThrows(
- "Should fail with a sensible parse error",
- IcebergParseException.class,
- "missing '(' at 'radish'",
- () -> parser.parsePlan("CALL cat.system radish kebab"));
+ Assertions.assertThatThrownBy(() -> parser.parsePlan("CALL cat.system radish kebab"))
+ .as("Should fail with a sensible parse error")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("missing '(' at 'radish'");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestChangelogTable.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestChangelogTable.java
index cc81b4b3d323..3b6ac57cc03e 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestChangelogTable.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestChangelogTable.java
@@ -18,7 +18,6 @@
*/
package org.apache.iceberg.spark.extensions;
-import static org.apache.iceberg.AssertHelpers.assertThrows;
import static org.apache.iceberg.TableProperties.FORMAT_VERSION;
import static org.apache.iceberg.TableProperties.MANIFEST_MERGE_ENABLED;
import static org.apache.iceberg.TableProperties.MANIFEST_MIN_MERGE_COUNT;
@@ -35,6 +34,7 @@
import org.apache.iceberg.spark.source.SparkChangelogTable;
import org.apache.spark.sql.DataFrameReader;
import org.apache.spark.sql.Row;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
@@ -202,10 +202,11 @@ public void testTimeRangeValidation() {
Snapshot snap3 = table.currentSnapshot();
long rightAfterSnap3 = waitUntilAfter(snap3.timestampMillis());
- assertThrows(
- "Should fail if start time is after end time",
- IllegalArgumentException.class,
- () -> changelogRecords(snap3.timestampMillis(), snap2.timestampMillis()));
+ Assertions.assertThatThrownBy(
+ () -> changelogRecords(snap3.timestampMillis(), snap2.timestampMillis()))
+ .as("Should fail if start time is after end time")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Cannot set start-timestamp to be greater than end-timestamp for changelogs");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestCherrypickSnapshotProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestCherrypickSnapshotProcedure.java
index 7309a176b922..cbecfcef3ed6 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestCherrypickSnapshotProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestCherrypickSnapshotProcedure.java
@@ -22,7 +22,6 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Snapshot;
import org.apache.iceberg.Table;
import org.apache.iceberg.exceptions.ValidationException;
@@ -32,6 +31,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchProcedureException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Test;
@@ -161,43 +161,42 @@ public void testCherrypickSnapshotRefreshesRelationCache() {
public void testCherrypickInvalidSnapshot() {
sql("CREATE TABLE %s (id bigint NOT NULL, data string) USING iceberg", tableName);
- AssertHelpers.assertThrows(
- "Should reject invalid snapshot id",
- ValidationException.class,
- "Cannot cherry-pick unknown snapshot ID",
- () -> sql("CALL %s.system.cherrypick_snapshot('%s', -1L)", catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.cherrypick_snapshot('%s', -1L)", catalogName, tableIdent))
+ .as("Should reject invalid snapshot id")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot cherry-pick unknown snapshot ID");
}
@Test
public void testInvalidCherrypickSnapshotCases() {
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () -> sql("CALL %s.system.cherrypick_snapshot('n', table => 't', 1L)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.cherrypick_snapshot('n', 't', 1L)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.cherrypick_snapshot('t')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.cherrypick_snapshot('', 1L)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type for snapshot_id: cannot cast",
- () -> sql("CALL %s.system.cherrypick_snapshot('t', 2.2)", catalogName));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.cherrypick_snapshot('n', table => 't', 1L)", catalogName))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.cherrypick_snapshot('n', 't', 1L)", catalogName))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.cherrypick_snapshot('t')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.cherrypick_snapshot('', 1L)", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.cherrypick_snapshot('t', 2.2)", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type for snapshot_id: cannot cast");
}
}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestConflictValidation.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestConflictValidation.java
index 6fcbf1f903be..7d183167572d 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestConflictValidation.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestConflictValidation.java
@@ -20,7 +20,6 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.IsolationLevel;
import org.apache.iceberg.Table;
import org.apache.iceberg.exceptions.ValidationException;
@@ -31,6 +30,7 @@
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
import org.apache.spark.sql.functions;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -69,21 +69,24 @@ public void testOverwriteFilterSerializableIsolation() throws Exception {
// Validating from previous snapshot finds conflicts
Dataset conflictingDf = spark.createDataFrame(records, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting new data files should throw exception",
- ValidationException.class,
- "Found conflicting files that can contain records matching ref(name=\"id\") == 1:",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
- .overwrite(functions.col("id").equalTo(1));
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
+ .option(
+ SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
+ .overwrite(functions.col("id").equalTo(1));
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting new data files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found conflicting files that can contain records matching ref(name=\"id\") == 1:");
// Validating from latest snapshot should succeed
table.refresh();
@@ -111,21 +114,23 @@ public void testOverwriteFilterSerializableIsolation2() throws Exception {
// Validating from previous snapshot finds conflicts
List conflictingRecords = Lists.newArrayList(new SimpleRecord(1, "a"));
Dataset conflictingDf = spark.createDataFrame(conflictingRecords, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting new delete files should throw exception",
- ValidationException.class,
- "Found new conflicting delete files that can apply to records matching ref(name=\"id\") == 1:",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SNAPSHOT.toString())
- .overwrite(functions.col("id").equalTo(1));
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
+ .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SNAPSHOT.toString())
+ .overwrite(functions.col("id").equalTo(1));
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting new delete files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found new conflicting delete files that can apply to records matching ref(name=\"id\") == 1:");
// Validating from latest snapshot should succeed
table.refresh();
@@ -149,21 +154,24 @@ public void testOverwriteFilterSerializableIsolation3() throws Exception {
// Validating from previous snapshot finds conflicts
List conflictingRecords = Lists.newArrayList(new SimpleRecord(1, "a"));
Dataset conflictingDf = spark.createDataFrame(conflictingRecords, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting deleted data files should throw exception",
- ValidationException.class,
- "Found conflicting deleted files that can contain records matching ref(name=\"id\") == 1:",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
- .overwrite(functions.col("id").equalTo(1));
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
+ .option(
+ SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
+ .overwrite(functions.col("id").equalTo(1));
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting deleted data files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found conflicting deleted files that can contain records matching ref(name=\"id\") == 1:");
// Validating from latest snapshot should succeed
table.refresh();
@@ -184,20 +192,23 @@ public void testOverwriteFilterNoSnapshotIdValidation() throws Exception {
// Validating from no snapshot id defaults to beginning snapshot id and finds conflicts
Dataset conflictingDf = spark.createDataFrame(records, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting new data files should throw exception",
- ValidationException.class,
- "Found conflicting files that can contain records matching ref(name=\"id\") == 1:",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
- .overwrite(functions.col("id").equalTo(1));
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(
+ SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
+ .overwrite(functions.col("id").equalTo(1));
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting new data files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found conflicting files that can contain records matching ref(name=\"id\") == 1:");
// Validating from latest snapshot should succeed
table.refresh();
@@ -225,21 +236,23 @@ public void testOverwriteFilterSnapshotIsolation() throws Exception {
// Validating from previous snapshot finds conflicts
List conflictingRecords = Lists.newArrayList(new SimpleRecord(1, "a"));
Dataset conflictingDf = spark.createDataFrame(conflictingRecords, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting new delete files should throw exception",
- ValidationException.class,
- "Found new conflicting delete files that can apply to records matching ref(name=\"id\") == 1:",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SNAPSHOT.toString())
- .overwrite(functions.col("id").equalTo(1));
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
+ .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SNAPSHOT.toString())
+ .overwrite(functions.col("id").equalTo(1));
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting new delete files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found new conflicting delete files that can apply to records matching ref(name=\"id\") == 1:");
// Validating from latest snapshot should succeed
table.refresh();
@@ -278,21 +291,24 @@ public void testOverwritePartitionSerializableIsolation() throws Exception {
// Validating from previous snapshot finds conflicts
Dataset conflictingDf = spark.createDataFrame(records, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting deleted data files should throw exception",
- ValidationException.class,
- "Found conflicting files that can contain records matching partitions [id=1]",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
- .overwritePartitions();
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
+ .option(
+ SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
+ .overwritePartitions();
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting deleted data files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found conflicting files that can contain records matching partitions [id=1]");
// Validating from latest snapshot should succeed
table.refresh();
@@ -318,21 +334,23 @@ public void testOverwritePartitionSnapshotIsolation() throws Exception {
// Validating from previous snapshot finds conflicts
Dataset conflictingDf = spark.createDataFrame(records, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting deleted data files should throw exception",
- ValidationException.class,
- "Found new conflicting delete files that can apply to records matching [id=1]",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SNAPSHOT.toString())
- .overwritePartitions();
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
+ .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SNAPSHOT.toString())
+ .overwritePartitions();
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting deleted data files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found new conflicting delete files that can apply to records matching [id=1]");
// Validating from latest snapshot should succeed
table.refresh();
@@ -357,21 +375,23 @@ public void testOverwritePartitionSnapshotIsolation2() throws Exception {
spark.createDataFrame(records, SimpleRecord.class).coalesce(1).writeTo(tableName).append();
Dataset conflictingDf = spark.createDataFrame(records, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting deleted data files should throw exception",
- ValidationException.class,
- "Found conflicting deleted files that can apply to records matching [id=1]",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SNAPSHOT.toString())
- .overwritePartitions();
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(SparkWriteOptions.VALIDATE_FROM_SNAPSHOT_ID, String.valueOf(snapshotId))
+ .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SNAPSHOT.toString())
+ .overwritePartitions();
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting deleted data files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found conflicting deleted files that can apply to records matching [id=1]");
// Validating from latest snapshot should succeed
table.refresh();
@@ -409,20 +429,23 @@ public void testOverwritePartitionNoSnapshotIdValidation() throws Exception {
// Validating from null snapshot is equivalent to validating from beginning
Dataset conflictingDf = spark.createDataFrame(records, SimpleRecord.class);
- AssertHelpers.assertThrowsCause(
- "Conflicting deleted data files should throw exception",
- ValidationException.class,
- "Found conflicting files that can contain records matching partitions [id=1]",
- () -> {
- try {
- conflictingDf
- .writeTo(tableName)
- .option(SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
- .overwritePartitions();
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ conflictingDf
+ .writeTo(tableName)
+ .option(
+ SparkWriteOptions.ISOLATION_LEVEL, IsolationLevel.SERIALIZABLE.toString())
+ .overwritePartitions();
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Conflicting deleted data files should throw exception")
+ .cause()
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Found conflicting files that can contain records matching partitions [id=1]");
// Validating from latest snapshot should succeed
table.refresh();
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestDelete.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestDelete.java
index e5ea378e5aab..af66df5a9fd4 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestDelete.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestDelete.java
@@ -44,7 +44,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.apache.iceberg.AppendFiles;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.ManifestFile;
import org.apache.iceberg.RowLevelOperationMode;
@@ -448,11 +447,11 @@ public void testDeleteWithNonDeterministicCondition() {
sql("INSERT INTO TABLE %s VALUES (1, 'hr'), (2, 'hardware')", tableName);
createBranchIfNeeded();
- AssertHelpers.assertThrows(
- "Should complain about non-deterministic expressions",
- AnalysisException.class,
- "nondeterministic expressions are only allowed",
- () -> sql("DELETE FROM %s WHERE id = 1 AND rand() > 0.5", commitTarget()));
+ Assertions.assertThatThrownBy(
+ () -> sql("DELETE FROM %s WHERE id = 1 AND rand() > 0.5", commitTarget()))
+ .as("Should complain about non-deterministic expressions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("nondeterministic expressions are only allowed");
}
@Test
@@ -737,11 +736,10 @@ public void testDeleteWithNotInSubquery() throws NoSuchTableException {
public void testDeleteOnNonIcebergTableNotSupported() {
createOrReplaceView("testtable", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Delete is supported only for Iceberg tables",
- AnalysisException.class,
- "DELETE is only supported with v2 tables.",
- () -> sql("DELETE FROM %s WHERE c1 = -100", "testtable"));
+ Assertions.assertThatThrownBy(() -> sql("DELETE FROM %s WHERE c1 = -100", "testtable"))
+ .as("Delete is supported only for Iceberg tables")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("DELETE is only supported with v2 tables.");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestExpireSnapshotsProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestExpireSnapshotsProcedure.java
index 6383521a44c2..f677facb9902 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestExpireSnapshotsProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestExpireSnapshotsProcedure.java
@@ -31,7 +31,6 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.GenericBlobMetadata;
import org.apache.iceberg.GenericStatisticsFile;
import org.apache.iceberg.PartitionStatisticsFile;
@@ -163,44 +162,42 @@ public void testExpireSnapshotsGCDisabled() {
sql("ALTER TABLE %s SET TBLPROPERTIES ('%s' 'false')", tableName, GC_ENABLED);
- AssertHelpers.assertThrows(
- "Should reject call",
- ValidationException.class,
- "Cannot expire snapshots: GC is disabled",
- () -> sql("CALL %s.system.expire_snapshots('%s')", catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.expire_snapshots('%s')", catalogName, tableIdent))
+ .as("Should reject call")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot expire snapshots: GC is disabled");
}
@Test
public void testInvalidExpireSnapshotsCases() {
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () -> sql("CALL %s.system.expire_snapshots('n', table => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.expire_snapshots('n', 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.expire_snapshots()", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type",
- () -> sql("CALL %s.system.expire_snapshots('n', 2.2)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.expire_snapshots('')", catalogName));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.expire_snapshots('n', table => 't')", catalogName))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.expire_snapshots('n', 't')", catalogName))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.expire_snapshots()", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.expire_snapshots('n', 2.2)", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.expire_snapshots('')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
@Test
@@ -218,14 +215,14 @@ public void testResolvingTableInAnotherCatalog() throws IOException {
"CREATE TABLE %s.%s (id bigint NOT NULL, data string) USING iceberg",
anotherCatalog, tableIdent);
- AssertHelpers.assertThrows(
- "Should reject calls for a table in another catalog",
- IllegalArgumentException.class,
- "Cannot run procedure in catalog",
- () ->
- sql(
- "CALL %s.system.expire_snapshots('%s')",
- catalogName, anotherCatalog + "." + tableName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.expire_snapshots('%s')",
+ catalogName, anotherCatalog + "." + tableName))
+ .as("Should reject calls for a table in another catalog")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot run procedure in catalog");
}
@Test
@@ -255,23 +252,23 @@ public void testConcurrentExpireSnapshots() {
public void testConcurrentExpireSnapshotsWithInvalidInput() {
sql("CREATE TABLE %s (id bigint NOT NULL, data string) USING iceberg", tableName);
- AssertHelpers.assertThrows(
- "Should throw an error when max_concurrent_deletes = 0",
- IllegalArgumentException.class,
- "max_concurrent_deletes should have value > 0",
- () ->
- sql(
- "CALL %s.system.expire_snapshots(table => '%s', max_concurrent_deletes => %s)",
- catalogName, tableIdent, 0));
-
- AssertHelpers.assertThrows(
- "Should throw an error when max_concurrent_deletes < 0 ",
- IllegalArgumentException.class,
- "max_concurrent_deletes should have value > 0",
- () ->
- sql(
- "CALL %s.system.expire_snapshots(table => '%s', max_concurrent_deletes => %s)",
- catalogName, tableIdent, -1));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.expire_snapshots(table => '%s', max_concurrent_deletes => %s)",
+ catalogName, tableIdent, 0))
+ .as("Should throw an error when max_concurrent_deletes = 0")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("max_concurrent_deletes should have value > 0");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.expire_snapshots(table => '%s', max_concurrent_deletes => %s)",
+ catalogName, tableIdent, -1))
+ .as("Should throw an error when max_concurrent_deletes < 0 ")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("max_concurrent_deletes should have value > 0");
}
@Test
@@ -404,19 +401,19 @@ public void testExpireSnapshotShouldFailForCurrentSnapshot() {
Table table = validationCatalog.loadTable(tableIdent);
Assert.assertEquals("Should be 2 snapshots", 2, Iterables.size(table.snapshots()));
- AssertHelpers.assertThrows(
- "Should reject call",
- IllegalArgumentException.class,
- "Cannot expire",
- () ->
- sql(
- "CALL %s.system.expire_snapshots("
- + "table => '%s',"
- + "snapshot_ids => ARRAY(%d, %d))",
- catalogName,
- tableIdent,
- table.currentSnapshot().snapshotId(),
- table.currentSnapshot().parentId()));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.expire_snapshots("
+ + "table => '%s',"
+ + "snapshot_ids => ARRAY(%d, %d))",
+ catalogName,
+ tableIdent,
+ table.currentSnapshot().snapshotId(),
+ table.currentSnapshot().parentId()))
+ .as("Should reject call")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot expire");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMerge.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMerge.java
index e855eb49a16c..ead477d71b20 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMerge.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMerge.java
@@ -40,7 +40,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.iceberg.AppendFiles;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DistributionMode;
import org.apache.iceberg.RowLevelOperationMode;
@@ -584,22 +583,23 @@ public void testMergeWithMultipleUpdatesForTargetRowSmallTargetLargeSource() {
ds.union(ds).createOrReplaceTempView("source");
String errorMsg = "a single row from the target table with multiple rows of the source table";
- AssertHelpers.assertThrowsCause(
- "Should complain about multiple matches",
- SparkException.class,
- errorMsg,
- () -> {
- sql(
- "MERGE INTO %s AS t USING source AS s "
- + "ON t.id == s.value "
- + "WHEN MATCHED AND t.id = 1 THEN "
- + " UPDATE SET id = 10 "
- + "WHEN MATCHED AND t.id = 6 THEN "
- + " DELETE "
- + "WHEN NOT MATCHED AND s.value = 2 THEN "
- + " INSERT (id, dep) VALUES (s.value, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s AS t USING source AS s "
+ + "ON t.id == s.value "
+ + "WHEN MATCHED AND t.id = 1 THEN "
+ + " UPDATE SET id = 10 "
+ + "WHEN MATCHED AND t.id = 6 THEN "
+ + " DELETE "
+ + "WHEN NOT MATCHED AND s.value = 2 THEN "
+ + " INSERT (id, dep) VALUES (s.value, null)",
+ commitTarget());
+ })
+ .as("Should complain about multiple matches")
+ .cause()
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining(errorMsg);
assertEquals(
"Target should be unchanged",
@@ -626,22 +626,23 @@ public void testMergeWithMultipleUpdatesForTargetRowSmallTargetLargeSource() {
() -> {
String errorMsg =
"a single row from the target table with multiple rows of the source table";
- AssertHelpers.assertThrowsCause(
- "Should complain about multiple matches",
- SparkException.class,
- errorMsg,
- () -> {
- sql(
- "MERGE INTO %s AS t USING source AS s "
- + "ON t.id == s.value "
- + "WHEN MATCHED AND t.id = 1 THEN "
- + " UPDATE SET id = 10 "
- + "WHEN MATCHED AND t.id = 6 THEN "
- + " DELETE "
- + "WHEN NOT MATCHED AND s.value = 2 THEN "
- + " INSERT (id, dep) VALUES (s.value, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s AS t USING source AS s "
+ + "ON t.id == s.value "
+ + "WHEN MATCHED AND t.id = 1 THEN "
+ + " UPDATE SET id = 10 "
+ + "WHEN MATCHED AND t.id = 6 THEN "
+ + " DELETE "
+ + "WHEN NOT MATCHED AND s.value = 2 THEN "
+ + " INSERT (id, dep) VALUES (s.value, null)",
+ commitTarget());
+ })
+ .as("Should complain about multiple matches")
+ .cause()
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining(errorMsg);
});
assertEquals(
@@ -666,22 +667,23 @@ public void testMergeWithMultipleUpdatesForTargetRowSmallTargetLargeSourceNoEqua
() -> {
String errorMsg =
"a single row from the target table with multiple rows of the source table";
- AssertHelpers.assertThrowsCause(
- "Should complain about multiple matches",
- SparkException.class,
- errorMsg,
- () -> {
- sql(
- "MERGE INTO %s AS t USING source AS s "
- + "ON t.id > s.value "
- + "WHEN MATCHED AND t.id = 1 THEN "
- + " UPDATE SET id = 10 "
- + "WHEN MATCHED AND t.id = 6 THEN "
- + " DELETE "
- + "WHEN NOT MATCHED AND s.value = 2 THEN "
- + " INSERT (id, dep) VALUES (s.value, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s AS t USING source AS s "
+ + "ON t.id > s.value "
+ + "WHEN MATCHED AND t.id = 1 THEN "
+ + " UPDATE SET id = 10 "
+ + "WHEN MATCHED AND t.id = 6 THEN "
+ + " DELETE "
+ + "WHEN NOT MATCHED AND s.value = 2 THEN "
+ + " INSERT (id, dep) VALUES (s.value, null)",
+ commitTarget());
+ })
+ .as("Should complain about multiple matches")
+ .cause()
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining(errorMsg);
});
assertEquals(
@@ -704,20 +706,21 @@ public void testMergeWithMultipleUpdatesForTargetRowSmallTargetLargeSourceNoNotM
ds.union(ds).createOrReplaceTempView("source");
String errorMsg = "a single row from the target table with multiple rows of the source table";
- AssertHelpers.assertThrowsCause(
- "Should complain about multiple matches",
- SparkException.class,
- errorMsg,
- () -> {
- sql(
- "MERGE INTO %s AS t USING source AS s "
- + "ON t.id == s.value "
- + "WHEN MATCHED AND t.id = 1 THEN "
- + " UPDATE SET id = 10 "
- + "WHEN MATCHED AND t.id = 6 THEN "
- + " DELETE",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s AS t USING source AS s "
+ + "ON t.id == s.value "
+ + "WHEN MATCHED AND t.id = 1 THEN "
+ + " UPDATE SET id = 10 "
+ + "WHEN MATCHED AND t.id = 6 THEN "
+ + " DELETE",
+ commitTarget());
+ })
+ .as("Should complain about multiple matches")
+ .cause()
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining(errorMsg);
assertEquals(
"Target should be unchanged",
@@ -738,20 +741,21 @@ public void testMergeWithMultipleUpdatesForTargetRowSmallTargetLargeSourceNoNotM
ds.union(ds).createOrReplaceTempView("source");
String errorMsg = "a single row from the target table with multiple rows of the source table";
- AssertHelpers.assertThrowsCause(
- "Should complain about multiple matches",
- SparkException.class,
- errorMsg,
- () -> {
- sql(
- "MERGE INTO %s AS t USING source AS s "
- + "ON t.id > s.value "
- + "WHEN MATCHED AND t.id = 1 THEN "
- + " UPDATE SET id = 10 "
- + "WHEN MATCHED AND t.id = 6 THEN "
- + " DELETE",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s AS t USING source AS s "
+ + "ON t.id > s.value "
+ + "WHEN MATCHED AND t.id = 1 THEN "
+ + " UPDATE SET id = 10 "
+ + "WHEN MATCHED AND t.id = 6 THEN "
+ + " DELETE",
+ commitTarget());
+ })
+ .as("Should complain about multiple matches")
+ .cause()
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining(errorMsg);
assertEquals(
"Target should be unchanged",
@@ -774,22 +778,23 @@ public void testMergeWithMultipleUpdatesForTargetRow() {
+ "{ \"id\": 6, \"dep\": \"emp-id-6\" }");
String errorMsg = "a single row from the target table with multiple rows of the source table";
- AssertHelpers.assertThrowsCause(
- "Should complain about multiple matches",
- SparkException.class,
- errorMsg,
- () -> {
- sql(
- "MERGE INTO %s AS t USING source AS s "
- + "ON t.id == s.id "
- + "WHEN MATCHED AND t.id = 1 THEN "
- + " UPDATE SET * "
- + "WHEN MATCHED AND t.id = 6 THEN "
- + " DELETE "
- + "WHEN NOT MATCHED AND s.id = 2 THEN "
- + " INSERT *",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s AS t USING source AS s "
+ + "ON t.id == s.id "
+ + "WHEN MATCHED AND t.id = 1 THEN "
+ + " UPDATE SET * "
+ + "WHEN MATCHED AND t.id = 6 THEN "
+ + " DELETE "
+ + "WHEN NOT MATCHED AND s.id = 2 THEN "
+ + " INSERT *",
+ commitTarget());
+ })
+ .as("Should complain about multiple matches")
+ .cause()
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining(errorMsg);
assertEquals(
"Target should be unchanged",
@@ -845,20 +850,21 @@ public void testMergeWithSingleConditionalDelete() {
+ "{ \"id\": 6, \"dep\": \"emp-id-6\" }");
String errorMsg = "a single row from the target table with multiple rows of the source table";
- AssertHelpers.assertThrowsCause(
- "Should complain about multiple matches",
- SparkException.class,
- errorMsg,
- () -> {
- sql(
- "MERGE INTO %s AS t USING source AS s "
- + "ON t.id == s.id "
- + "WHEN MATCHED AND t.id = 1 THEN "
- + " DELETE "
- + "WHEN NOT MATCHED AND s.id = 2 THEN "
- + " INSERT *",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s AS t USING source AS s "
+ + "ON t.id == s.id "
+ + "WHEN MATCHED AND t.id = 1 THEN "
+ + " DELETE "
+ + "WHEN NOT MATCHED AND s.id = 2 THEN "
+ + " INSERT *",
+ commitTarget());
+ })
+ .as("Should complain about multiple matches")
+ .cause()
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining(errorMsg);
assertEquals(
"Target should be unchanged",
@@ -1985,46 +1991,46 @@ public void testMergeWithNonExistingColumns() {
"{ \"id\": 1, \"c\": { \"n1\": 2, \"n2\": { \"dn1\": 3, \"dn2\": 4 } } }");
createOrReplaceView("source", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Should complain about the invalid top-level column",
- AnalysisException.class,
- "cannot resolve t.invalid_col",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.invalid_col = s.c2",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.invalid_col = s.c2",
+ commitTarget());
+ })
+ .as("Should complain about the invalid top-level column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("cannot resolve t.invalid_col");
- AssertHelpers.assertThrows(
- "Should complain about the invalid nested column",
- AnalysisException.class,
- "No such struct field invalid_col",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.c.n2.invalid_col = s.c2",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.c.n2.invalid_col = s.c2",
+ commitTarget());
+ })
+ .as("Should complain about the invalid nested column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("No such struct field invalid_col");
- AssertHelpers.assertThrows(
- "Should complain about the invalid top-level column",
- AnalysisException.class,
- "cannot resolve invalid_col",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.c.n2.dn1 = s.c2 "
- + "WHEN NOT MATCHED THEN "
- + " INSERT (id, invalid_col) VALUES (s.c1, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.c.n2.dn1 = s.c2 "
+ + "WHEN NOT MATCHED THEN "
+ + " INSERT (id, invalid_col) VALUES (s.c1, null)",
+ commitTarget());
+ })
+ .as("Should complain about the invalid top-level column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("cannot resolve invalid_col");
}
@Test
@@ -2034,48 +2040,48 @@ public void testMergeWithInvalidColumnsInInsert() {
"{ \"id\": 1, \"c\": { \"n1\": 2, \"n2\": { \"dn1\": 3, \"dn2\": 4 } } }");
createOrReplaceView("source", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Should complain about the nested column",
- AnalysisException.class,
- "Nested fields are not supported inside INSERT clauses",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.c.n2.dn1 = s.c2 "
- + "WHEN NOT MATCHED THEN "
- + " INSERT (id, c.n2) VALUES (s.c1, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.c.n2.dn1 = s.c2 "
+ + "WHEN NOT MATCHED THEN "
+ + " INSERT (id, c.n2) VALUES (s.c1, null)",
+ commitTarget());
+ })
+ .as("Should complain about the nested column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Nested fields are not supported inside INSERT clauses");
- AssertHelpers.assertThrows(
- "Should complain about duplicate columns",
- AnalysisException.class,
- "Duplicate column names inside INSERT clause",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.c.n2.dn1 = s.c2 "
- + "WHEN NOT MATCHED THEN "
- + " INSERT (id, id) VALUES (s.c1, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.c.n2.dn1 = s.c2 "
+ + "WHEN NOT MATCHED THEN "
+ + " INSERT (id, id) VALUES (s.c1, null)",
+ commitTarget());
+ })
+ .as("Should complain about duplicate columns")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Duplicate column names inside INSERT clause");
- AssertHelpers.assertThrows(
- "Should complain about missing columns",
- AnalysisException.class,
- "must provide values for all columns of the target table",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN NOT MATCHED THEN "
- + " INSERT (id) VALUES (s.c1)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN NOT MATCHED THEN "
+ + " INSERT (id) VALUES (s.c1)",
+ commitTarget());
+ })
+ .as("Should complain about missing columns")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("must provide values for all columns of the target table");
}
@Test
@@ -2085,31 +2091,31 @@ public void testMergeWithInvalidUpdates() {
"{ \"id\": 1, \"a\": [ { \"c1\": 2, \"c2\": 3 } ], \"m\": { \"k\": \"v\"} }");
createOrReplaceView("source", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Should complain about updating an array column",
- AnalysisException.class,
- "Updating nested fields is only supported for structs",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.a.c1 = s.c2",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.a.c1 = s.c2",
+ commitTarget());
+ })
+ .as("Should complain about updating an array column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updating nested fields is only supported for structs");
- AssertHelpers.assertThrows(
- "Should complain about updating a map column",
- AnalysisException.class,
- "Updating nested fields is only supported for structs",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.m.key = 'new_key'",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.m.key = 'new_key'",
+ commitTarget());
+ })
+ .as("Should complain about updating a map column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updating nested fields is only supported for structs");
}
@Test
@@ -2119,44 +2125,44 @@ public void testMergeWithConflictingUpdates() {
"{ \"id\": 1, \"c\": { \"n1\": 2, \"n2\": { \"dn1\": 3, \"dn2\": 4 } } }");
createOrReplaceView("source", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Should complain about conflicting updates to a top-level column",
- AnalysisException.class,
- "Updates are in conflict",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.id = 1, t.c.n1 = 2, t.id = 2",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.id = 1, t.c.n1 = 2, t.id = 2",
+ commitTarget());
+ })
+ .as("Should complain about conflicting updates to a top-level column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updates are in conflict");
- AssertHelpers.assertThrows(
- "Should complain about conflicting updates to a nested column",
- AnalysisException.class,
- "Updates are in conflict for these columns",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.c.n1 = 1, t.id = 2, t.c.n1 = 2",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.c.n1 = 1, t.id = 2, t.c.n1 = 2",
+ commitTarget());
+ })
+ .as("Should complain about conflicting updates to a nested column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updates are in conflict for these columns");
- AssertHelpers.assertThrows(
- "Should complain about conflicting updates to a nested column",
- AnalysisException.class,
- "Updates are in conflict",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET c.n1 = 1, c = named_struct('n1', 1, 'n2', named_struct('dn1', 1, 'dn2', 2))",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET c.n1 = 1, c = named_struct('n1', 1, 'n2', named_struct('dn1', 1, 'dn2', 2))",
+ commitTarget());
+ })
+ .as("Should complain about conflicting updates to a nested column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updates are in conflict");
}
@Test
@@ -2173,70 +2179,70 @@ public void testMergeWithInvalidAssignments() {
withSQLConf(
ImmutableMap.of("spark.sql.storeAssignmentPolicy", policy),
() -> {
- AssertHelpers.assertThrows(
- "Should complain about writing nulls to a top-level column",
- AnalysisException.class,
- "Cannot write nullable values to non-null column",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.id = NULL",
- commitTarget());
- });
-
- AssertHelpers.assertThrows(
- "Should complain about writing nulls to a nested column",
- AnalysisException.class,
- "Cannot write nullable values to non-null column",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.s.n1 = NULL",
- commitTarget());
- });
-
- AssertHelpers.assertThrows(
- "Should complain about writing missing fields in structs",
- AnalysisException.class,
- "missing fields",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.s = s.c2",
- commitTarget());
- });
-
- AssertHelpers.assertThrows(
- "Should complain about writing invalid data types",
- AnalysisException.class,
- "Cannot safely cast",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.s.n1 = s.c3",
- commitTarget());
- });
-
- AssertHelpers.assertThrows(
- "Should complain about writing incompatible structs",
- AnalysisException.class,
- "field name does not match",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.s.n2 = s.c4",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.id = NULL",
+ commitTarget());
+ })
+ .as("Should complain about writing nulls to a top-level column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Cannot write nullable values to non-null column");
+
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.s.n1 = NULL",
+ commitTarget());
+ })
+ .as("Should complain about writing nulls to a nested column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Cannot write nullable values to non-null column");
+
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.s = s.c2",
+ commitTarget());
+ })
+ .as("Should complain about writing missing fields in structs")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("missing fields");
+
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.s.n1 = s.c3",
+ commitTarget());
+ })
+ .as("Should complain about writing invalid data types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Cannot safely cast");
+
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.s.n2 = s.c4",
+ commitTarget());
+ })
+ .as("Should complain about writing incompatible structs")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("field name does not match");
});
}
}
@@ -2248,57 +2254,57 @@ public void testMergeWithNonDeterministicConditions() {
"{ \"id\": 1, \"c\": { \"n1\": 2, \"n2\": { \"dn1\": 3, \"dn2\": 4 } } }");
createOrReplaceView("source", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Should complain about non-deterministic search conditions",
- AnalysisException.class,
- "Non-deterministic functions are not supported",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 AND rand() > t.id "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.c.n1 = -1",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 AND rand() > t.id "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.c.n1 = -1",
+ commitTarget());
+ })
+ .as("Should complain about non-deterministic search conditions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Non-deterministic functions are not supported");
- AssertHelpers.assertThrows(
- "Should complain about non-deterministic update conditions",
- AnalysisException.class,
- "Non-deterministic functions are not supported",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED AND rand() > t.id THEN "
- + " UPDATE SET t.c.n1 = -1",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED AND rand() > t.id THEN "
+ + " UPDATE SET t.c.n1 = -1",
+ commitTarget());
+ })
+ .as("Should complain about non-deterministic update conditions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Non-deterministic functions are not supported");
- AssertHelpers.assertThrows(
- "Should complain about non-deterministic delete conditions",
- AnalysisException.class,
- "Non-deterministic functions are not supported",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED AND rand() > t.id THEN "
- + " DELETE",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED AND rand() > t.id THEN "
+ + " DELETE",
+ commitTarget());
+ })
+ .as("Should complain about non-deterministic delete conditions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Non-deterministic functions are not supported");
- AssertHelpers.assertThrows(
- "Should complain about non-deterministic insert conditions",
- AnalysisException.class,
- "Non-deterministic functions are not supported",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN NOT MATCHED AND rand() > c1 THEN "
- + " INSERT (id, c) VALUES (1, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN NOT MATCHED AND rand() > c1 THEN "
+ + " INSERT (id, c) VALUES (1, null)",
+ commitTarget());
+ })
+ .as("Should complain about non-deterministic insert conditions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Non-deterministic functions are not supported");
}
@Test
@@ -2308,57 +2314,57 @@ public void testMergeWithAggregateExpressions() {
"{ \"id\": 1, \"c\": { \"n1\": 2, \"n2\": { \"dn1\": 3, \"dn2\": 4 } } }");
createOrReplaceView("source", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Should complain about agg expressions in search conditions",
- AnalysisException.class,
- "Agg functions are not supported",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 AND max(t.id) == 1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.c.n1 = -1",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 AND max(t.id) == 1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.c.n1 = -1",
+ commitTarget());
+ })
+ .as("Should complain about agg expressions in search conditions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Agg functions are not supported");
- AssertHelpers.assertThrows(
- "Should complain about agg expressions in update conditions",
- AnalysisException.class,
- "Agg functions are not supported",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED AND sum(t.id) < 1 THEN "
- + " UPDATE SET t.c.n1 = -1",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED AND sum(t.id) < 1 THEN "
+ + " UPDATE SET t.c.n1 = -1",
+ commitTarget());
+ })
+ .as("Should complain about agg expressions in update conditions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Agg functions are not supported");
- AssertHelpers.assertThrows(
- "Should complain about agg expressions in delete conditions",
- AnalysisException.class,
- "Agg functions are not supported",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED AND sum(t.id) THEN "
- + " DELETE",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED AND sum(t.id) THEN "
+ + " DELETE",
+ commitTarget());
+ })
+ .as("Should complain about agg expressions in delete conditions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Agg functions are not supported");
- AssertHelpers.assertThrows(
- "Should complain about agg expressions in insert conditions",
- AnalysisException.class,
- "Agg functions are not supported",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN NOT MATCHED AND sum(c1) < 1 THEN "
- + " INSERT (id, c) VALUES (1, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN NOT MATCHED AND sum(c1) < 1 THEN "
+ + " INSERT (id, c) VALUES (1, null)",
+ commitTarget());
+ })
+ .as("Should complain about agg expressions in insert conditions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Agg functions are not supported");
}
@Test
@@ -2368,57 +2374,57 @@ public void testMergeWithSubqueriesInConditions() {
"{ \"id\": 1, \"c\": { \"n1\": 2, \"n2\": { \"dn1\": 3, \"dn2\": 4 } } }");
createOrReplaceView("source", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Should complain about subquery expressions",
- AnalysisException.class,
- "Subqueries are not supported in conditions",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 AND t.id < (SELECT max(c2) FROM source) "
- + "WHEN MATCHED THEN "
- + " UPDATE SET t.c.n1 = s.c2",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 AND t.id < (SELECT max(c2) FROM source) "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET t.c.n1 = s.c2",
+ commitTarget());
+ })
+ .as("Should complain about subquery expressions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Subqueries are not supported in conditions");
- AssertHelpers.assertThrows(
- "Should complain about subquery expressions",
- AnalysisException.class,
- "Subqueries are not supported in conditions",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED AND t.id < (SELECT max(c2) FROM source) THEN "
- + " UPDATE SET t.c.n1 = s.c2",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED AND t.id < (SELECT max(c2) FROM source) THEN "
+ + " UPDATE SET t.c.n1 = s.c2",
+ commitTarget());
+ })
+ .as("Should complain about subquery expressions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Subqueries are not supported in conditions");
- AssertHelpers.assertThrows(
- "Should complain about subquery expressions",
- AnalysisException.class,
- "Subqueries are not supported in conditions",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN MATCHED AND t.id NOT IN (SELECT c2 FROM source) THEN "
- + " DELETE",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN MATCHED AND t.id NOT IN (SELECT c2 FROM source) THEN "
+ + " DELETE",
+ commitTarget());
+ })
+ .as("Should complain about subquery expressions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Subqueries are not supported in conditions");
- AssertHelpers.assertThrows(
- "Should complain about subquery expressions",
- AnalysisException.class,
- "Subqueries are not supported in conditions",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.c1 "
- + "WHEN NOT MATCHED AND s.c1 IN (SELECT c2 FROM source) THEN "
- + " INSERT (id, c) VALUES (1, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.c1 "
+ + "WHEN NOT MATCHED AND s.c1 IN (SELECT c2 FROM source) THEN "
+ + " INSERT (id, c) VALUES (1, null)",
+ commitTarget());
+ })
+ .as("Should complain about subquery expressions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Subqueries are not supported in conditions");
}
@Test
@@ -2426,18 +2432,18 @@ public void testMergeWithTargetColumnsInInsertConditions() {
createAndInitTable("id INT, c2 INT", "{ \"id\": 1, \"c2\": 2 }");
createOrReplaceView("source", "{ \"id\": 1, \"value\": 11 }");
- AssertHelpers.assertThrows(
- "Should complain about the target column",
- AnalysisException.class,
- "Cannot resolve [c2]",
- () -> {
- sql(
- "MERGE INTO %s t USING source s "
- + "ON t.id == s.id "
- + "WHEN NOT MATCHED AND c2 = 1 THEN "
- + " INSERT (id, c2) VALUES (s.id, null)",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO %s t USING source s "
+ + "ON t.id == s.id "
+ + "WHEN NOT MATCHED AND c2 = 1 THEN "
+ + " INSERT (id, c2) VALUES (s.id, null)",
+ commitTarget());
+ })
+ .as("Should complain about the target column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Cannot resolve [c2]");
}
@Test
@@ -2445,17 +2451,17 @@ public void testMergeWithNonIcebergTargetTableNotSupported() {
createOrReplaceView("target", "{ \"c1\": -100, \"c2\": -200 }");
createOrReplaceView("source", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "Should complain non iceberg target table",
- UnsupportedOperationException.class,
- "MERGE INTO TABLE is not supported temporarily.",
- () -> {
- sql(
- "MERGE INTO target t USING source s "
- + "ON t.c1 == s.c1 "
- + "WHEN MATCHED THEN "
- + " UPDATE SET *");
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "MERGE INTO target t USING source s "
+ + "ON t.c1 == s.c1 "
+ + "WHEN MATCHED THEN "
+ + " UPDATE SET *");
+ })
+ .as("Should complain non iceberg target table")
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessageContaining("MERGE INTO TABLE is not supported temporarily.");
}
/**
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMergeOnReadDelete.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMergeOnReadDelete.java
index 6d8120127586..c156e4c77767 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMergeOnReadDelete.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMergeOnReadDelete.java
@@ -25,7 +25,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.RowDelta;
import org.apache.iceberg.RowLevelOperationMode;
import org.apache.iceberg.Table;
@@ -38,6 +37,7 @@
import org.apache.iceberg.spark.source.TestSparkCatalog;
import org.apache.spark.SparkException;
import org.apache.spark.sql.connector.catalog.Identifier;
+import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runners.Parameterized;
@@ -115,13 +115,14 @@ public void testCommitUnknownException() {
TestSparkCatalog.setTable(ident, sparkTable);
// Although an exception is thrown here, write and commit have succeeded
- AssertHelpers.assertThrowsWithCause(
- "Should throw a Commit State Unknown Exception",
- SparkException.class,
- "Writing job aborted",
- CommitStateUnknownException.class,
- "Datacenter on Fire",
- () -> sql("DELETE FROM %s WHERE id = 2", "dummy_catalog.default.table"));
+ Assertions.assertThatThrownBy(
+ () -> sql("DELETE FROM %s WHERE id = 2", "dummy_catalog.default.table"))
+ .as("Should throw a Commit State Unknown Exception")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Writing job aborted")
+ .cause()
+ .isInstanceOf(CommitStateUnknownException.class)
+ .hasMessageContaining("Datacenter on Fire");
// Since write and commit succeeded, the rows should be readable
assertEquals(
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMigrateTableProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMigrateTableProcedure.java
index b8b5df099089..3a51e87be804 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMigrateTableProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestMigrateTableProcedure.java
@@ -20,11 +20,11 @@
import java.io.IOException;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Table;
import org.apache.iceberg.exceptions.ValidationException;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.spark.sql.AnalysisException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -131,14 +131,14 @@ public void testMigrateWithInvalidMetricsConfig() throws IOException {
"CREATE TABLE %s (id bigint NOT NULL, data string) USING parquet LOCATION '%s'",
tableName, location);
- AssertHelpers.assertThrows(
- "Should reject invalid metrics config",
- ValidationException.class,
- "Invalid metrics config",
- () -> {
- String props = "map('write.metadata.metrics.column.x', 'X')";
- sql("CALL %s.system.migrate('%s', %s)", catalogName, tableName, props);
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ String props = "map('write.metadata.metrics.column.x', 'X')";
+ sql("CALL %s.system.migrate('%s', %s)", catalogName, tableName, props);
+ })
+ .as("Should reject invalid metrics config")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Invalid metrics config");
}
@Test
@@ -166,23 +166,21 @@ public void testMigrateWithConflictingProps() throws IOException {
@Test
public void testInvalidMigrateCases() {
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.migrate()", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type",
- () -> sql("CALL %s.system.migrate(map('foo','bar'))", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.migrate('')", catalogName));
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.migrate()", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.migrate(map('foo','bar'))", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.migrate('')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestPublishChangesProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestPublishChangesProcedure.java
index 2b74cd475fae..19a065234ed8 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestPublishChangesProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestPublishChangesProcedure.java
@@ -22,7 +22,6 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Snapshot;
import org.apache.iceberg.Table;
import org.apache.iceberg.exceptions.ValidationException;
@@ -32,6 +31,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchProcedureException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Test;
@@ -157,37 +157,37 @@ public void testApplyWapChangesRefreshesRelationCache() {
public void testApplyInvalidWapId() {
sql("CREATE TABLE %s (id bigint NOT NULL, data string) USING iceberg", tableName);
- AssertHelpers.assertThrows(
- "Should reject invalid wap id",
- ValidationException.class,
- "Cannot apply unknown WAP ID",
- () -> sql("CALL %s.system.publish_changes('%s', 'not_valid')", catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.publish_changes('%s', 'not_valid')", catalogName, tableIdent))
+ .as("Should reject invalid wap id")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot apply unknown WAP ID");
}
@Test
public void testInvalidApplyWapChangesCases() {
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () -> sql("CALL %s.system.publish_changes('n', table => 't', 'not_valid')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.publish_changes('n', 't', 'not_valid')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.publish_changes('t')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.publish_changes('', 'not_valid')", catalogName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql("CALL %s.system.publish_changes('n', table => 't', 'not_valid')", catalogName))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.publish_changes('n', 't', 'not_valid')", catalogName))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.publish_changes('t')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.publish_changes('', 'not_valid')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoveOrphanFilesProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoveOrphanFilesProcedure.java
index 670c4e565760..415141968664 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoveOrphanFilesProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRemoveOrphanFilesProcedure.java
@@ -34,7 +34,6 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DataFiles;
import org.apache.iceberg.Files;
@@ -227,11 +226,11 @@ public void testRemoveOrphanFilesGCDisabled() {
sql("ALTER TABLE %s SET TBLPROPERTIES ('%s' 'false')", tableName, GC_ENABLED);
- AssertHelpers.assertThrows(
- "Should reject call",
- ValidationException.class,
- "Cannot delete orphan files: GC is disabled",
- () -> sql("CALL %s.system.remove_orphan_files('%s')", catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.remove_orphan_files('%s')", catalogName, tableIdent))
+ .as("Should reject call")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot delete orphan files: GC is disabled");
// reset the property to enable the table purging in removeTable.
sql("ALTER TABLE %s SET TBLPROPERTIES ('%s' 'true')", tableName, GC_ENABLED);
@@ -258,35 +257,33 @@ public void testRemoveOrphanFilesWap() {
@Test
public void testInvalidRemoveOrphanFilesCases() {
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () -> sql("CALL %s.system.remove_orphan_files('n', table => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.remove_orphan_files('n', 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.remove_orphan_files()", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type",
- () -> sql("CALL %s.system.remove_orphan_files('n', 2.2)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.remove_orphan_files('')", catalogName));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.remove_orphan_files('n', table => 't')", catalogName))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.remove_orphan_files('n', 't')", catalogName))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.remove_orphan_files()", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.remove_orphan_files('n', 2.2)", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.remove_orphan_files('')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
@Test
@@ -351,63 +348,63 @@ public void testConcurrentRemoveOrphanFiles() throws IOException {
public void testConcurrentRemoveOrphanFilesWithInvalidInput() {
sql("CREATE TABLE %s (id bigint NOT NULL, data string) USING iceberg", tableName);
- AssertHelpers.assertThrows(
- "Should throw an error when max_concurrent_deletes = 0",
- IllegalArgumentException.class,
- "max_concurrent_deletes should have value > 0",
- () ->
- sql(
- "CALL %s.system.remove_orphan_files(table => '%s', max_concurrent_deletes => %s)",
- catalogName, tableIdent, 0));
-
- AssertHelpers.assertThrows(
- "Should throw an error when max_concurrent_deletes < 0 ",
- IllegalArgumentException.class,
- "max_concurrent_deletes should have value > 0",
- () ->
- sql(
- "CALL %s.system.remove_orphan_files(table => '%s', max_concurrent_deletes => %s)",
- catalogName, tableIdent, -1));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.remove_orphan_files(table => '%s', max_concurrent_deletes => %s)",
+ catalogName, tableIdent, 0))
+ .as("Should throw an error when max_concurrent_deletes = 0")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("max_concurrent_deletes should have value > 0");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.remove_orphan_files(table => '%s', max_concurrent_deletes => %s)",
+ catalogName, tableIdent, -1))
+ .as("Should throw an error when max_concurrent_deletes < 0 ")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("max_concurrent_deletes should have value > 0");
String tempViewName = "file_list_test";
spark.emptyDataFrame().createOrReplaceTempView(tempViewName);
- AssertHelpers.assertThrows(
- "Should throw an error if file_list_view is missing required columns",
- IllegalArgumentException.class,
- "does not exist. Available:",
- () ->
- sql(
- "CALL %s.system.remove_orphan_files(table => '%s', file_list_view => '%s')",
- catalogName, tableIdent, tempViewName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.remove_orphan_files(table => '%s', file_list_view => '%s')",
+ catalogName, tableIdent, tempViewName))
+ .as("Should throw an error if file_list_view is missing required columns")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("does not exist. Available:");
spark
.createDataset(Lists.newArrayList(), Encoders.tuple(Encoders.INT(), Encoders.TIMESTAMP()))
.toDF("file_path", "last_modified")
.createOrReplaceTempView(tempViewName);
- AssertHelpers.assertThrows(
- "Should throw an error if file_path has wrong type",
- IllegalArgumentException.class,
- "Invalid file_path column",
- () ->
- sql(
- "CALL %s.system.remove_orphan_files(table => '%s', file_list_view => '%s')",
- catalogName, tableIdent, tempViewName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.remove_orphan_files(table => '%s', file_list_view => '%s')",
+ catalogName, tableIdent, tempViewName))
+ .as("Should throw an error if file_path has wrong type")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Invalid file_path column");
spark
.createDataset(Lists.newArrayList(), Encoders.tuple(Encoders.STRING(), Encoders.STRING()))
.toDF("file_path", "last_modified")
.createOrReplaceTempView(tempViewName);
- AssertHelpers.assertThrows(
- "Should throw an error if last_modified has wrong type",
- IllegalArgumentException.class,
- "Invalid last_modified column",
- () ->
- sql(
- "CALL %s.system.remove_orphan_files(table => '%s', file_list_view => '%s')",
- catalogName, tableIdent, tempViewName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.remove_orphan_files(table => '%s', file_list_view => '%s')",
+ catalogName, tableIdent, tempViewName))
+ .as("Should throw an error if last_modified has wrong type")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Invalid last_modified column");
}
@Test
@@ -679,16 +676,16 @@ public void testRemoveOrphanFilesProcedureWithPrefixMode()
Assert.assertEquals(0, orphanFiles.size());
// Test with no equal schemes
- AssertHelpers.assertThrows(
- "Should complain about removing orphan files",
- ValidationException.class,
- "Conflicting authorities/schemes: [(file1, file)]",
- () ->
- sql(
- "CALL %s.system.remove_orphan_files("
- + "table => '%s',"
- + "file_list_view => '%s')",
- catalogName, tableIdent, fileListViewName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.remove_orphan_files("
+ + "table => '%s',"
+ + "file_list_view => '%s')",
+ catalogName, tableIdent, fileListViewName))
+ .as("Should complain about removing orphan files")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Conflicting authorities/schemes: [(file1, file)]");
// Drop table in afterEach has purge and fails due to invalid scheme "file1" used in this test
// Dropping the table here
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestReplaceBranch.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestReplaceBranch.java
index b63826e543b8..ed428310b8f4 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestReplaceBranch.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestReplaceBranch.java
@@ -21,7 +21,6 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.SnapshotRef;
import org.apache.iceberg.Table;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
@@ -30,6 +29,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
@@ -74,11 +74,14 @@ public void testReplaceBranchFailsForTag() throws NoSuchTableException {
df.writeTo(tableName).append();
long second = table.currentSnapshot().snapshotId();
- AssertHelpers.assertThrows(
- "Cannot perform replace branch on tags",
- IllegalArgumentException.class,
- "Ref tag1 is a tag not a branch",
- () -> sql("ALTER TABLE %s REPLACE BRANCH %s AS OF VERSION %d", tableName, tagName, second));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "ALTER TABLE %s REPLACE BRANCH %s AS OF VERSION %d",
+ tableName, tagName, second))
+ .as("Cannot perform replace branch on tags")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Ref tag1 is a tag not a branch");
}
@Test
@@ -126,14 +129,14 @@ public void testReplaceBranchDoesNotExist() throws NoSuchTableException {
df.writeTo(tableName).append();
Table table = validationCatalog.loadTable(tableIdent);
- AssertHelpers.assertThrows(
- "Cannot perform replace branch on branch which does not exist",
- IllegalArgumentException.class,
- "Branch does not exist",
- () ->
- sql(
- "ALTER TABLE %s REPLACE BRANCH %s AS OF VERSION %d",
- tableName, "someBranch", table.currentSnapshot().snapshotId()));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "ALTER TABLE %s REPLACE BRANCH %s AS OF VERSION %d",
+ tableName, "someBranch", table.currentSnapshot().snapshotId()))
+ .as("Cannot perform replace branch on branch which does not exist")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Branch does not exist");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRequiredDistributionAndOrdering.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRequiredDistributionAndOrdering.java
index 02ae0e6ac664..b459f3c24807 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRequiredDistributionAndOrdering.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRequiredDistributionAndOrdering.java
@@ -21,7 +21,6 @@
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.spark.SparkWriteOptions;
import org.apache.iceberg.spark.source.ThreeColumnRecord;
@@ -29,6 +28,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Test;
@@ -187,20 +187,20 @@ public void testDisabledDistributionAndOrdering() {
Dataset inputDF = ds.coalesce(1).sortWithinPartitions("c1");
// should fail if ordering is disabled
- AssertHelpers.assertThrows(
- "Should reject writes without ordering",
- SparkException.class,
- "Writing job aborted",
- () -> {
- try {
- inputDF
- .writeTo(tableName)
- .option(SparkWriteOptions.USE_TABLE_DISTRIBUTION_AND_ORDERING, "false")
- .append();
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ inputDF
+ .writeTo(tableName)
+ .option(SparkWriteOptions.USE_TABLE_DISTRIBUTION_AND_ORDERING, "false")
+ .append();
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Should reject writes without ordering")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Writing job aborted");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRewriteDataFilesProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRewriteDataFilesProcedure.java
index 80cacbf376ac..4a4e4d7dfd7b 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRewriteDataFilesProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRewriteDataFilesProcedure.java
@@ -24,7 +24,6 @@
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.SnapshotSummary;
import org.apache.iceberg.TableProperties;
import org.apache.iceberg.catalog.TableIdentifier;
@@ -455,136 +454,137 @@ public void testRewriteDataFilesWithInvalidInputs() {
insertData(2);
// Test for invalid strategy
- AssertHelpers.assertThrows(
- "Should reject calls with unsupported strategy error message",
- IllegalArgumentException.class,
- "unsupported strategy: temp. Only binpack or sort is supported",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', options => map('min-input-files','2'), "
- + "strategy => 'temp')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', options => map('min-input-files','2'), "
+ + "strategy => 'temp')",
+ catalogName, tableIdent))
+ .as("Should reject calls with unsupported strategy error message")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("unsupported strategy: temp. Only binpack or sort is supported");
// Test for sort_order with binpack strategy
- AssertHelpers.assertThrows(
- "Should reject calls with error message",
- IllegalArgumentException.class,
- "Must use only one rewriter type (bin-pack, sort, zorder)",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'binpack', "
- + "sort_order => 'c1 ASC NULLS FIRST')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'binpack', "
+ + "sort_order => 'c1 ASC NULLS FIRST')",
+ catalogName, tableIdent))
+ .as("Should reject calls with error message")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Must use only one rewriter type (bin-pack, sort, zorder)");
// Test for sort strategy without any (default/user defined) sort_order
- AssertHelpers.assertThrows(
- "Should reject calls with error message",
- IllegalArgumentException.class,
- "Cannot sort data without a valid sort order",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort')",
+ catalogName, tableIdent))
+ .as("Should reject calls with error message")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot sort data without a valid sort order");
// Test for sort_order with invalid null order
- AssertHelpers.assertThrows(
- "Should reject calls with error message",
- IllegalArgumentException.class,
- "Unable to parse sortOrder:",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
- + "sort_order => 'c1 ASC none')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
+ + "sort_order => 'c1 ASC none')",
+ catalogName, tableIdent))
+ .as("Should reject calls with error message")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Unable to parse sortOrder:");
// Test for sort_order with invalid sort direction
- AssertHelpers.assertThrows(
- "Should reject calls with error message",
- IllegalArgumentException.class,
- "Unable to parse sortOrder:",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
- + "sort_order => 'c1 none NULLS FIRST')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
+ + "sort_order => 'c1 none NULLS FIRST')",
+ catalogName, tableIdent))
+ .as("Should reject calls with error message")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Unable to parse sortOrder:");
// Test for sort_order with invalid column name
- AssertHelpers.assertThrows(
- "Should reject calls with error message",
- ValidationException.class,
- "Cannot find field 'col1' in struct:"
- + " struct<1: c1: optional int, 2: c2: optional string, 3: c3: optional string>",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
- + "sort_order => 'col1 DESC NULLS FIRST')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
+ + "sort_order => 'col1 DESC NULLS FIRST')",
+ catalogName, tableIdent))
+ .as("Should reject calls with error message")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Cannot find field 'col1' in struct:"
+ + " struct<1: c1: optional int, 2: c2: optional string, 3: c3: optional string>");
// Test with invalid filter column col1
- AssertHelpers.assertThrows(
- "Should reject calls with error message",
- IllegalArgumentException.class,
- "Cannot parse predicates in where option: col1 = 3",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', " + "where => 'col1 = 3')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', " + "where => 'col1 = 3')",
+ catalogName, tableIdent))
+ .as("Should reject calls with error message")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot parse predicates in where option: col1 = 3");
// Test for z_order with invalid column name
- AssertHelpers.assertThrows(
- "Should reject calls with error message",
- IllegalArgumentException.class,
- "Cannot find column 'col1' in table schema (case sensitive = false): "
- + "struct<1: c1: optional int, 2: c2: optional string, 3: c3: optional string>",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
- + "sort_order => 'zorder(col1)')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
+ + "sort_order => 'zorder(col1)')",
+ catalogName, tableIdent))
+ .as("Should reject calls with error message")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(
+ "Cannot find column 'col1' in table schema (case sensitive = false): "
+ + "struct<1: c1: optional int, 2: c2: optional string, 3: c3: optional string>");
// Test for z_order with sort_order
- AssertHelpers.assertThrows(
- "Should reject calls with error message",
- IllegalArgumentException.class,
- "Cannot mix identity sort columns and a Zorder sort expression:" + " c1,zorder(c2,c3)",
- () ->
- sql(
- "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
- + "sort_order => 'c1,zorder(c2,c3)')",
- catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rewrite_data_files(table => '%s', strategy => 'sort', "
+ + "sort_order => 'c1,zorder(c2,c3)')",
+ catalogName, tableIdent))
+ .as("Should reject calls with error message")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(
+ "Cannot mix identity sort columns and a Zorder sort expression:" + " c1,zorder(c2,c3)");
}
@Test
public void testInvalidCasesForRewriteDataFiles() {
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () -> sql("CALL %s.system.rewrite_data_files('n', table => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.rewrite_data_files('n', 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.rewrite_data_files()", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject duplicate arg names name",
- AnalysisException.class,
- "Duplicate procedure argument: table",
- () -> sql("CALL %s.system.rewrite_data_files(table => 't', table => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.rewrite_data_files('')", catalogName));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rewrite_data_files('n', table => 't')", catalogName))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.rewrite_data_files('n', 't')", catalogName))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.rewrite_data_files()", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rewrite_data_files(table => 't', table => 't')", catalogName))
+ .as("Should reject duplicate arg names name")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Duplicate procedure argument: table");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.rewrite_data_files('')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRewriteManifestsProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRewriteManifestsProcedure.java
index 2675c1010baa..3afad8a7b839 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRewriteManifestsProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRewriteManifestsProcedure.java
@@ -24,7 +24,6 @@
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Table;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
@@ -32,6 +31,7 @@
import org.apache.spark.sql.RowFactory;
import org.apache.spark.sql.catalyst.analysis.NoSuchProcedureException;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
@@ -276,41 +276,39 @@ public void testRewriteManifestsCaseInsensitiveArgs() {
@Test
public void testInvalidRewriteManifestsCases() {
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () -> sql("CALL %s.system.rewrite_manifests('n', table => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.rewrite_manifests('n', 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.rewrite_manifests()", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type",
- () -> sql("CALL %s.system.rewrite_manifests('n', 2.2)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject duplicate arg names name",
- AnalysisException.class,
- "Duplicate procedure argument: table",
- () -> sql("CALL %s.system.rewrite_manifests(table => 't', tAbLe => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.rewrite_manifests('')", catalogName));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rewrite_manifests('n', table => 't')", catalogName))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.rewrite_manifests('n', 't')", catalogName))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.rewrite_manifests()", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rewrite_manifests('n', 2.2)", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rewrite_manifests(table => 't', tAbLe => 't')", catalogName))
+ .as("Should reject duplicate arg names name")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Duplicate procedure argument: table");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.rewrite_manifests('')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRollbackToSnapshotProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRollbackToSnapshotProcedure.java
index af94b456d02e..95d03a0104fd 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRollbackToSnapshotProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRollbackToSnapshotProcedure.java
@@ -20,7 +20,6 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Snapshot;
import org.apache.iceberg.Table;
import org.apache.iceberg.exceptions.ValidationException;
@@ -29,6 +28,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchProcedureException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assume;
import org.junit.Test;
@@ -240,58 +240,57 @@ public void testRollbackToSnapshotWithoutExplicitCatalog() {
public void testRollbackToInvalidSnapshot() {
sql("CREATE TABLE %s (id bigint NOT NULL, data string) USING iceberg", tableName);
- AssertHelpers.assertThrows(
- "Should reject invalid snapshot id",
- ValidationException.class,
- "Cannot roll back to unknown snapshot id",
- () -> sql("CALL %s.system.rollback_to_snapshot('%s', -1L)", catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rollback_to_snapshot('%s', -1L)", catalogName, tableIdent))
+ .as("Should reject invalid snapshot id")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot roll back to unknown snapshot id");
}
@Test
public void testInvalidRollbackToSnapshotCases() {
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () ->
- sql(
- "CALL %s.system.rollback_to_snapshot(namespace => 'n1', table => 't', 1L)",
- catalogName));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.rollback_to_snapshot('n', 't', 1L)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.rollback_to_snapshot('t')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.rollback_to_snapshot(1L)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.rollback_to_snapshot(table => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type for snapshot_id: cannot cast",
- () -> sql("CALL %s.system.rollback_to_snapshot('t', 2.2)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.rollback_to_snapshot('', 1L)", catalogName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rollback_to_snapshot(namespace => 'n1', table => 't', 1L)",
+ catalogName))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.rollback_to_snapshot('n', 't', 1L)", catalogName))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rollback_to_snapshot('t')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.rollback_to_snapshot(1L)", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rollback_to_snapshot(table => 't')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rollback_to_snapshot('t', 2.2)", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type for snapshot_id: cannot cast");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rollback_to_snapshot('', 1L)", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRollbackToTimestampProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRollbackToTimestampProcedure.java
index 6da3853bbe24..c11c7ab7e421 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRollbackToTimestampProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestRollbackToTimestampProcedure.java
@@ -21,7 +21,6 @@
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Snapshot;
import org.apache.iceberg.Table;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
@@ -29,6 +28,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchProcedureException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assume;
import org.junit.Test;
@@ -255,50 +255,55 @@ public void testRollbackToTimestampWithoutExplicitCatalog() {
public void testInvalidRollbackToTimestampCases() {
String timestamp = "TIMESTAMP '2007-12-03T10:15:30'";
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () ->
- sql(
- "CALL %s.system.rollback_to_timestamp(namespace => 'n1', 't', %s)",
- catalogName, timestamp));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.rollback_to_timestamp('n', 't', %s)", catalogName, timestamp));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.rollback_to_timestamp('t')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.rollback_to_timestamp(timestamp => %s)", catalogName, timestamp));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.rollback_to_timestamp(table => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with extra args",
- AnalysisException.class,
- "Too many arguments",
- () ->
- sql("CALL %s.system.rollback_to_timestamp('n', 't', %s, 1L)", catalogName, timestamp));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type for timestamp: cannot cast",
- () -> sql("CALL %s.system.rollback_to_timestamp('t', 2.2)", catalogName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rollback_to_timestamp(namespace => 'n1', 't', %s)",
+ catalogName, timestamp))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.rollback_to_timestamp('n', 't', %s)", catalogName, timestamp))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rollback_to_timestamp('t')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rollback_to_timestamp(timestamp => %s)",
+ catalogName, timestamp))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rollback_to_timestamp(table => 't')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.rollback_to_timestamp('n', 't', %s, 1L)",
+ catalogName, timestamp))
+ .as("Should reject calls with extra args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Too many arguments");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.rollback_to_timestamp('t', 2.2)", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type for timestamp: cannot cast");
}
}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestSetCurrentSnapshotProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestSetCurrentSnapshotProcedure.java
index 8a8a974bbebe..d996e4b5c805 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestSetCurrentSnapshotProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestSetCurrentSnapshotProcedure.java
@@ -22,7 +22,6 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Snapshot;
import org.apache.iceberg.Table;
import org.apache.iceberg.catalog.Namespace;
@@ -31,6 +30,7 @@
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
import org.apache.spark.sql.AnalysisException;
import org.apache.spark.sql.catalyst.analysis.NoSuchProcedureException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assume;
import org.junit.Test;
@@ -193,64 +193,63 @@ public void testSetCurrentSnapshotToInvalidSnapshot() {
Namespace namespace = tableIdent.namespace();
String tableName = tableIdent.name();
- AssertHelpers.assertThrows(
- "Should reject invalid snapshot id",
- ValidationException.class,
- "Cannot roll back to unknown snapshot id",
- () -> sql("CALL %s.system.set_current_snapshot('%s', -1L)", catalogName, tableIdent));
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.set_current_snapshot('%s', -1L)", catalogName, tableIdent))
+ .as("Should reject invalid snapshot id")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot roll back to unknown snapshot id");
}
@Test
public void testInvalidRollbackToSnapshotCases() {
- AssertHelpers.assertThrows(
- "Should not allow mixed args",
- AnalysisException.class,
- "Named and positional arguments cannot be mixed",
- () ->
- sql(
- "CALL %s.system.set_current_snapshot(namespace => 'n1', table => 't', 1L)",
- catalogName));
-
- AssertHelpers.assertThrows(
- "Should not resolve procedures in arbitrary namespaces",
- NoSuchProcedureException.class,
- "not found",
- () -> sql("CALL %s.custom.set_current_snapshot('n', 't', 1L)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.set_current_snapshot('t')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.set_current_snapshot(1L)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.set_current_snapshot(snapshot_id => 1L)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.set_current_snapshot(table => 't')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type for snapshot_id: cannot cast",
- () -> sql("CALL %s.system.set_current_snapshot('t', 2.2)", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.set_current_snapshot('', 1L)", catalogName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.set_current_snapshot(namespace => 'n1', table => 't', 1L)",
+ catalogName))
+ .as("Should not allow mixed args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Named and positional arguments cannot be mixed");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.custom.set_current_snapshot('n', 't', 1L)", catalogName))
+ .as("Should not resolve procedures in arbitrary namespaces")
+ .isInstanceOf(NoSuchProcedureException.class)
+ .hasMessageContaining("not found");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.set_current_snapshot('t')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.set_current_snapshot(1L)", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.set_current_snapshot(snapshot_id => 1L)", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.set_current_snapshot(table => 't')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.set_current_snapshot('t', 2.2)", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type for snapshot_id: cannot cast");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.set_current_snapshot('', 1L)", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestSnapshotTableProcedure.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestSnapshotTableProcedure.java
index d8e918d8aadd..d44f8d3721ca 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestSnapshotTableProcedure.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestSnapshotTableProcedure.java
@@ -20,11 +20,11 @@
import java.io.IOException;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Table;
import org.apache.iceberg.TableProperties;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.spark.sql.AnalysisException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -195,37 +195,34 @@ public void testInvalidSnapshotsCases() throws IOException {
"CREATE TABLE %s (id bigint NOT NULL, data string) USING parquet LOCATION '%s'",
sourceName, location);
- AssertHelpers.assertThrows(
- "Should reject calls without all required args",
- AnalysisException.class,
- "Missing required parameters",
- () -> sql("CALL %s.system.snapshot('foo')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid arg types",
- AnalysisException.class,
- "Wrong arg type",
- () -> sql("CALL %s.system.snapshot('n', 't', map('foo', 'bar'))", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with invalid map args",
- AnalysisException.class,
- "cannot resolve 'map",
- () ->
- sql(
- "CALL %s.system.snapshot('%s', 'fable', 'loc', map(2, 1, 1))",
- catalogName, sourceName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.snapshot('', 'dest')", catalogName));
-
- AssertHelpers.assertThrows(
- "Should reject calls with empty table identifier",
- IllegalArgumentException.class,
- "Cannot handle an empty identifier",
- () -> sql("CALL %s.system.snapshot('src', '')", catalogName));
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.snapshot('foo')", catalogName))
+ .as("Should reject calls without all required args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Missing required parameters");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("CALL %s.system.snapshot('n', 't', map('foo', 'bar'))", catalogName))
+ .as("Should reject calls with invalid arg types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Wrong arg type");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CALL %s.system.snapshot('%s', 'fable', 'loc', map(2, 1, 1))",
+ catalogName, sourceName))
+ .as("Should reject calls with invalid map args")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("cannot resolve 'map");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.snapshot('', 'dest')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
+
+ Assertions.assertThatThrownBy(() -> sql("CALL %s.system.snapshot('src', '')", catalogName))
+ .as("Should reject calls with empty table identifier")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot handle an empty identifier");
}
}
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestTagDDL.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestTagDDL.java
index 866a965e33e6..3dadadd9c4de 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestTagDDL.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestTagDDL.java
@@ -24,7 +24,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.SnapshotRef;
import org.apache.iceberg.Table;
import org.apache.iceberg.exceptions.ValidationException;
@@ -97,29 +96,29 @@ public void testCreateTagWithRetain() throws NoSuchTableException {
}
String tagName = "t1";
- AssertHelpers.assertThrows(
- "Illegal statement",
- IcebergParseException.class,
- "mismatched input",
- () ->
- sql(
- "ALTER TABLE %s CREATE TAG %s AS OF VERSION %d RETAIN",
- tableName, tagName, firstSnapshotId, maxRefAge));
-
- AssertHelpers.assertThrows(
- "Illegal statement",
- IcebergParseException.class,
- "mismatched input",
- () -> sql("ALTER TABLE %s CREATE TAG %s RETAIN %s DAYS", tableName, tagName, "abc"));
-
- AssertHelpers.assertThrows(
- "Illegal statement",
- IcebergParseException.class,
- "mismatched input 'SECONDS' expecting {'DAYS', 'HOURS', 'MINUTES'}",
- () ->
- sql(
- "ALTER TABLE %s CREATE TAG %s AS OF VERSION %d RETAIN %d SECONDS",
- tableName, tagName, firstSnapshotId, maxRefAge));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "ALTER TABLE %s CREATE TAG %s AS OF VERSION %d RETAIN",
+ tableName, tagName, firstSnapshotId, maxRefAge))
+ .as("Illegal statement")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s CREATE TAG %s RETAIN %s DAYS", tableName, tagName, "abc"))
+ .as("Illegal statement")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "ALTER TABLE %s CREATE TAG %s AS OF VERSION %d RETAIN %d SECONDS",
+ tableName, tagName, firstSnapshotId, maxRefAge))
+ .as("Illegal statement")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input 'SECONDS' expecting {'DAYS', 'HOURS', 'MINUTES'}");
}
@Test
@@ -137,11 +136,11 @@ public void testCreateTagUseDefaultConfig() throws NoSuchTableException {
long snapshotId = table.currentSnapshot().snapshotId();
String tagName = "t1";
- AssertHelpers.assertThrows(
- "unknown snapshot",
- ValidationException.class,
- "unknown snapshot: -1",
- () -> sql("ALTER TABLE %s CREATE TAG %s AS OF VERSION %d", tableName, tagName, -1));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s CREATE TAG %s AS OF VERSION %d", tableName, tagName, -1))
+ .as("unknown snapshot")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("unknown snapshot: -1");
sql("ALTER TABLE %s CREATE TAG %s", tableName, tagName);
table.refresh();
@@ -151,17 +150,15 @@ public void testCreateTagUseDefaultConfig() throws NoSuchTableException {
Assert.assertNull(
"The tag needs to have the default max ref age, which is null.", ref.maxRefAgeMs());
- AssertHelpers.assertThrows(
- "Cannot create an exist tag",
- IllegalArgumentException.class,
- "already exists",
- () -> sql("ALTER TABLE %s CREATE TAG %s", tableName, tagName));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s CREATE TAG %s", tableName, tagName))
+ .as("Cannot create an exist tag")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("already exists");
- AssertHelpers.assertThrows(
- "Non-conforming tag name",
- IcebergParseException.class,
- "mismatched input '123'",
- () -> sql("ALTER TABLE %s CREATE TAG %s", tableName, "123"));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s CREATE TAG %s", tableName, "123"))
+ .as("Non-conforming tag name")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input '123'");
table.manageSnapshots().removeTag(tagName).commit();
List records =
@@ -207,11 +204,11 @@ public void testReplaceTagFailsForBranch() throws NoSuchTableException {
insertRows();
long second = table.currentSnapshot().snapshotId();
- AssertHelpers.assertThrows(
- "Cannot perform replace tag on branches",
- IllegalArgumentException.class,
- "Ref branch1 is a branch not a tag",
- () -> sql("ALTER TABLE %s REPLACE Tag %s", tableName, branchName, second));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s REPLACE Tag %s", tableName, branchName, second))
+ .as("Cannot perform replace tag on branches")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Ref branch1 is a branch not a tag");
}
@Test
@@ -244,14 +241,14 @@ public void testReplaceTag() throws NoSuchTableException {
public void testReplaceTagDoesNotExist() throws NoSuchTableException {
Table table = insertRows();
- AssertHelpers.assertThrows(
- "Cannot perform replace tag on tag which does not exist",
- IllegalArgumentException.class,
- "Tag does not exist",
- () ->
- sql(
- "ALTER TABLE %s REPLACE Tag %s AS OF VERSION %d",
- tableName, "someTag", table.currentSnapshot().snapshotId()));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "ALTER TABLE %s REPLACE Tag %s AS OF VERSION %d",
+ tableName, "someTag", table.currentSnapshot().snapshotId()))
+ .as("Cannot perform replace tag on tag which does not exist")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Tag does not exist");
}
@Test
@@ -316,20 +313,19 @@ public void testDropTag() throws NoSuchTableException {
@Test
public void testDropTagNonConformingName() {
- AssertHelpers.assertThrows(
- "Non-conforming tag name",
- IcebergParseException.class,
- "mismatched input '123'",
- () -> sql("ALTER TABLE %s DROP TAG %s", tableName, "123"));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s DROP TAG %s", tableName, "123"))
+ .as("Non-conforming tag name")
+ .isInstanceOf(IcebergParseException.class)
+ .hasMessageContaining("mismatched input '123'");
}
@Test
public void testDropTagDoesNotExist() {
- AssertHelpers.assertThrows(
- "Cannot perform drop tag on tag which does not exist",
- IllegalArgumentException.class,
- "Tag does not exist: nonExistingTag",
- () -> sql("ALTER TABLE %s DROP TAG %s", tableName, "nonExistingTag"));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s DROP TAG %s", tableName, "nonExistingTag"))
+ .as("Cannot perform drop tag on tag which does not exist")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Tag does not exist: nonExistingTag");
}
@Test
@@ -338,11 +334,10 @@ public void testDropTagFailesForBranch() throws NoSuchTableException {
Table table = insertRows();
table.manageSnapshots().createBranch(branchName, table.currentSnapshot().snapshotId()).commit();
- AssertHelpers.assertThrows(
- "Cannot perform drop tag on branch",
- IllegalArgumentException.class,
- "Ref b1 is a branch not a tag",
- () -> sql("ALTER TABLE %s DROP TAG %s", tableName, branchName));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s DROP TAG %s", tableName, branchName))
+ .as("Cannot perform drop tag on branch")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Ref b1 is a branch not a tag");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestUpdate.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestUpdate.java
index 8093e6fc0984..76c7a171f603 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestUpdate.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestUpdate.java
@@ -42,7 +42,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.iceberg.AppendFiles;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.RowLevelOperationMode;
import org.apache.iceberg.Snapshot;
@@ -1149,17 +1148,15 @@ public void testUpdateWithInvalidUpdates() {
"id INT, a ARRAY>, m MAP",
"{ \"id\": 0, \"a\": null, \"m\": null }");
- AssertHelpers.assertThrows(
- "Should complain about updating an array column",
- AnalysisException.class,
- "Updating nested fields is only supported for structs",
- () -> sql("UPDATE %s SET a.c1 = 1", commitTarget()));
-
- AssertHelpers.assertThrows(
- "Should complain about updating a map column",
- AnalysisException.class,
- "Updating nested fields is only supported for structs",
- () -> sql("UPDATE %s SET m.key = 'new_key'", commitTarget()));
+ Assertions.assertThatThrownBy(() -> sql("UPDATE %s SET a.c1 = 1", commitTarget()))
+ .as("Should complain about updating an array column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updating nested fields is only supported for structs");
+
+ Assertions.assertThatThrownBy(() -> sql("UPDATE %s SET m.key = 'new_key'", commitTarget()))
+ .as("Should complain about updating a map column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updating nested fields is only supported for structs");
}
@Test
@@ -1167,27 +1164,27 @@ public void testUpdateWithConflictingAssignments() {
createAndInitTable(
"id INT, c STRUCT>", "{ \"id\": 0, \"s\": null }");
- AssertHelpers.assertThrows(
- "Should complain about conflicting updates to a top-level column",
- AnalysisException.class,
- "Updates are in conflict",
- () -> sql("UPDATE %s t SET t.id = 1, t.c.n1 = 2, t.id = 2", commitTarget()));
-
- AssertHelpers.assertThrows(
- "Should complain about conflicting updates to a nested column",
- AnalysisException.class,
- "Updates are in conflict for these columns",
- () -> sql("UPDATE %s t SET t.c.n1 = 1, t.id = 2, t.c.n1 = 2", commitTarget()));
-
- AssertHelpers.assertThrows(
- "Should complain about conflicting updates to a nested column",
- AnalysisException.class,
- "Updates are in conflict",
- () -> {
- sql(
- "UPDATE %s SET c.n1 = 1, c = named_struct('n1', 1, 'n2', named_struct('dn1', 1, 'dn2', 2))",
- commitTarget());
- });
+ Assertions.assertThatThrownBy(
+ () -> sql("UPDATE %s t SET t.id = 1, t.c.n1 = 2, t.id = 2", commitTarget()))
+ .as("Should complain about conflicting updates to a top-level column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updates are in conflict");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("UPDATE %s t SET t.c.n1 = 1, t.id = 2, t.c.n1 = 2", commitTarget()))
+ .as("Should complain about conflicting updates to a nested column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updates are in conflict for these columns");
+
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "UPDATE %s SET c.n1 = 1, c = named_struct('n1', 1, 'n2', named_struct('dn1', 1, 'dn2', 2))",
+ commitTarget());
+ })
+ .as("Should complain about conflicting updates to a nested column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Updates are in conflict");
}
@Test
@@ -1200,38 +1197,37 @@ public void testUpdateWithInvalidAssignments() {
withSQLConf(
ImmutableMap.of("spark.sql.storeAssignmentPolicy", policy),
() -> {
- AssertHelpers.assertThrows(
- "Should complain about writing nulls to a top-level column",
- AnalysisException.class,
- "Cannot write nullable values to non-null column",
- () -> sql("UPDATE %s t SET t.id = NULL", commitTarget()));
-
- AssertHelpers.assertThrows(
- "Should complain about writing nulls to a nested column",
- AnalysisException.class,
- "Cannot write nullable values to non-null column",
- () -> sql("UPDATE %s t SET t.s.n1 = NULL", commitTarget()));
-
- AssertHelpers.assertThrows(
- "Should complain about writing missing fields in structs",
- AnalysisException.class,
- "missing fields",
- () -> sql("UPDATE %s t SET t.s = named_struct('n1', 1)", commitTarget()));
-
- AssertHelpers.assertThrows(
- "Should complain about writing invalid data types",
- AnalysisException.class,
- "Cannot safely cast",
- () -> sql("UPDATE %s t SET t.s.n1 = 'str'", commitTarget()));
-
- AssertHelpers.assertThrows(
- "Should complain about writing incompatible structs",
- AnalysisException.class,
- "field name does not match",
- () ->
- sql(
- "UPDATE %s t SET t.s.n2 = named_struct('dn2', 1, 'dn1', 2)",
- commitTarget()));
+ Assertions.assertThatThrownBy(() -> sql("UPDATE %s t SET t.id = NULL", commitTarget()))
+ .as("Should complain about writing nulls to a top-level column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Cannot write nullable values to non-null column");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("UPDATE %s t SET t.s.n1 = NULL", commitTarget()))
+ .as("Should complain about writing nulls to a nested column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Cannot write nullable values to non-null column");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("UPDATE %s t SET t.s = named_struct('n1', 1)", commitTarget()))
+ .as("Should complain about writing missing fields in structs")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("missing fields");
+
+ Assertions.assertThatThrownBy(
+ () -> sql("UPDATE %s t SET t.s.n1 = 'str'", commitTarget()))
+ .as("Should complain about writing invalid data types")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Cannot safely cast");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "UPDATE %s t SET t.s.n2 = named_struct('dn2', 1, 'dn1', 2)",
+ commitTarget()))
+ .as("Should complain about writing incompatible structs")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("field name does not match");
});
}
}
@@ -1240,22 +1236,21 @@ public void testUpdateWithInvalidAssignments() {
public void testUpdateWithNonDeterministicCondition() {
createAndInitTable("id INT, dep STRING", "{ \"id\": 1, \"dep\": \"hr\" }");
- AssertHelpers.assertThrows(
- "Should complain about non-deterministic expressions",
- AnalysisException.class,
- "nondeterministic expressions are only allowed",
- () -> sql("UPDATE %s SET id = -1 WHERE id = 1 AND rand() > 0.5", commitTarget()));
+ Assertions.assertThatThrownBy(
+ () -> sql("UPDATE %s SET id = -1 WHERE id = 1 AND rand() > 0.5", commitTarget()))
+ .as("Should complain about non-deterministic expressions")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("nondeterministic expressions are only allowed");
}
@Test
public void testUpdateOnNonIcebergTableNotSupported() {
createOrReplaceView("testtable", "{ \"c1\": -100, \"c2\": -200 }");
- AssertHelpers.assertThrows(
- "UPDATE is not supported for non iceberg table",
- UnsupportedOperationException.class,
- "not supported temporarily",
- () -> sql("UPDATE %s SET c1 = -1 WHERE c2 = 1", "testtable"));
+ Assertions.assertThatThrownBy(() -> sql("UPDATE %s SET c1 = -1 WHERE c2 = 1", "testtable"))
+ .as("UPDATE is not supported for non iceberg table")
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessageContaining("not supported temporarily");
}
@Test
diff --git a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestWriteAborts.java b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestWriteAborts.java
index 24a9b3f232e0..2966e95fa3de 100644
--- a/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestWriteAborts.java
+++ b/spark/v3.3/spark-extensions/src/test/java/org/apache/iceberg/spark/extensions/TestWriteAborts.java
@@ -21,7 +21,6 @@
import java.util.List;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.CatalogProperties;
import org.apache.iceberg.TableProperties;
import org.apache.iceberg.hadoop.HadoopFileIO;
@@ -39,6 +38,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
@@ -105,23 +105,23 @@ public void testBatchAppend() throws Exception {
new SimpleRecord(4, "b"));
Dataset inputDF = spark.createDataFrame(records, SimpleRecord.class);
- AssertHelpers.assertThrows(
- "Write must fail",
- SparkException.class,
- "Writing job aborted",
- () -> {
- try {
- // incoming records are not ordered by partitions so the job must fail
- inputDF
- .coalesce(1)
- .sortWithinPartitions("id")
- .writeTo(tableName)
- .option(SparkWriteOptions.USE_TABLE_DISTRIBUTION_AND_ORDERING, "false")
- .append();
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ // incoming records are not ordered by partitions so the job must fail
+ inputDF
+ .coalesce(1)
+ .sortWithinPartitions("id")
+ .writeTo(tableName)
+ .option(SparkWriteOptions.USE_TABLE_DISTRIBUTION_AND_ORDERING, "false")
+ .append();
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Write must fail")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Writing job aborted");
assertEquals("Should be no records", sql("SELECT * FROM %s", tableName), ImmutableList.of());
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/TestFunctionCatalog.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/TestFunctionCatalog.java
index 9dcd59cb4f11..d224e175d3b0 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/TestFunctionCatalog.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/TestFunctionCatalog.java
@@ -18,7 +18,6 @@
*/
package org.apache.iceberg.spark;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.IcebergBuild;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.spark.functions.IcebergVersionFunction;
@@ -68,11 +67,10 @@ public void testListFunctionsViaCatalog() throws NoSuchNamespaceException {
new Identifier[0],
asFunctionCatalog.listFunctions(DEFAULT_NAMESPACE));
- AssertHelpers.assertThrows(
- "Listing functions in a namespace that does not exist should throw",
- NoSuchNamespaceException.class,
- "Namespace 'db' not found",
- () -> asFunctionCatalog.listFunctions(DB_NAMESPACE));
+ Assertions.assertThatThrownBy(() -> asFunctionCatalog.listFunctions(DB_NAMESPACE))
+ .as("Listing functions in a namespace that does not exist should throw")
+ .isInstanceOf(NoSuchNamespaceException.class)
+ .hasMessageContaining("Namespace 'db' not found");
}
@Test
@@ -87,24 +85,24 @@ public void testLoadFunctions() throws NoSuchFunctionException {
.isExactlyInstanceOf(IcebergVersionFunction.class);
}
- AssertHelpers.assertThrows(
- "Cannot load a function if it's not used with the system namespace or the empty namespace",
- NoSuchFunctionException.class,
- "Undefined function: default.iceberg_version",
- () -> asFunctionCatalog.loadFunction(Identifier.of(DEFAULT_NAMESPACE, "iceberg_version")));
+ Assertions.assertThatThrownBy(
+ () ->
+ asFunctionCatalog.loadFunction(Identifier.of(DEFAULT_NAMESPACE, "iceberg_version")))
+ .as(
+ "Cannot load a function if it's not used with the system namespace or the empty namespace")
+ .isInstanceOf(NoSuchFunctionException.class)
+ .hasMessageContaining("Undefined function: default.iceberg_version");
Identifier undefinedFunction = Identifier.of(SYSTEM_NAMESPACE, "undefined_function");
- AssertHelpers.assertThrows(
- "Cannot load a function that does not exist",
- NoSuchFunctionException.class,
- "Undefined function: system.undefined_function",
- () -> asFunctionCatalog.loadFunction(undefinedFunction));
-
- AssertHelpers.assertThrows(
- "Using an undefined function from SQL should fail analysis",
- AnalysisException.class,
- "Undefined function",
- () -> sql("SELECT undefined_function(1, 2)"));
+ Assertions.assertThatThrownBy(() -> asFunctionCatalog.loadFunction(undefinedFunction))
+ .as("Cannot load a function that does not exist")
+ .isInstanceOf(NoSuchFunctionException.class)
+ .hasMessageContaining("Undefined function: system.undefined_function");
+
+ Assertions.assertThatThrownBy(() -> sql("SELECT undefined_function(1, 2)"))
+ .as("Using an undefined function from SQL should fail analysis")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Undefined function");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestDeleteReachableFilesAction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestDeleteReachableFilesAction.java
index 0e333f216c26..5b1cf8281784 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestDeleteReachableFilesAction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestDeleteReachableFilesAction.java
@@ -27,7 +27,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.StreamSupport;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DataFiles;
import org.apache.iceberg.DeleteFile;
@@ -51,6 +50,7 @@
import org.apache.iceberg.relocated.com.google.common.collect.Sets;
import org.apache.iceberg.spark.SparkTestBase;
import org.apache.iceberg.types.Types;
+import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
@@ -362,22 +362,22 @@ public void testIgnoreMetadataFilesNotFound() {
public void testEmptyIOThrowsException() {
DeleteReachableFiles baseRemoveFilesSparkAction =
sparkActions().deleteReachableFiles(metadataLocation(table)).io(null);
- AssertHelpers.assertThrows(
- "FileIO can't be null in DeleteReachableFiles action",
- IllegalArgumentException.class,
- "File IO cannot be null",
- baseRemoveFilesSparkAction::execute);
+ Assertions.assertThatThrownBy(baseRemoveFilesSparkAction::execute)
+ .as("FileIO can't be null in DeleteReachableFiles action")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("File IO cannot be null");
}
@Test
public void testRemoveFilesActionWhenGarbageCollectionDisabled() {
table.updateProperties().set(TableProperties.GC_ENABLED, "false").commit();
- AssertHelpers.assertThrows(
- "Should complain about removing files when GC is disabled",
- ValidationException.class,
- "Cannot delete files: GC is disabled (deleting files may corrupt other tables)",
- () -> sparkActions().deleteReachableFiles(metadataLocation(table)).execute());
+ Assertions.assertThatThrownBy(
+ () -> sparkActions().deleteReachableFiles(metadataLocation(table)).execute())
+ .as("Should complain about removing files when GC is disabled")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Cannot delete files: GC is disabled (deleting files may corrupt other tables)");
}
private String metadataLocation(Table tbl) {
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestExpireSnapshotsAction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestExpireSnapshotsAction.java
index c8bef4a2a973..a3580bd2d980 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestExpireSnapshotsAction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestExpireSnapshotsAction.java
@@ -29,7 +29,6 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.BaseTable;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DataFiles;
@@ -57,6 +56,7 @@
import org.apache.iceberg.spark.data.TestHelpers;
import org.apache.iceberg.types.Types;
import org.apache.spark.sql.Dataset;
+import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
@@ -447,11 +447,10 @@ public void testExpireSnapshotsWithDisabledGarbageCollection() {
table.newAppend().appendFile(FILE_A).commit();
- AssertHelpers.assertThrows(
- "Should complain about expiring snapshots",
- ValidationException.class,
- "Cannot expire snapshots: GC is disabled",
- () -> SparkActions.get().expireSnapshots(table));
+ Assertions.assertThatThrownBy(() -> SparkActions.get().expireSnapshots(table))
+ .as("Should complain about expiring snapshots")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot expire snapshots: GC is disabled");
}
@Test
@@ -529,11 +528,13 @@ public void testRetainLastMultipleCalls() {
@Test
public void testRetainZeroSnapshots() {
- AssertHelpers.assertThrows(
- "Should fail retain 0 snapshots " + "because number of snapshots to retain cannot be zero",
- IllegalArgumentException.class,
- "Number of snapshots to retain must be at least 1, cannot be: 0",
- () -> SparkActions.get().expireSnapshots(table).retainLast(0).execute());
+ Assertions.assertThatThrownBy(
+ () -> SparkActions.get().expireSnapshots(table).retainLast(0).execute())
+ .as(
+ "Should fail retain 0 snapshots "
+ + "because number of snapshots to retain cannot be zero")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Number of snapshots to retain must be at least 1, cannot be: 0");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRemoveOrphanFilesAction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRemoveOrphanFilesAction.java
index c94aec6f5c19..10af2454fa4a 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRemoveOrphanFilesAction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRemoveOrphanFilesAction.java
@@ -40,7 +40,6 @@
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Files;
import org.apache.iceberg.GenericBlobMetadata;
import org.apache.iceberg.GenericStatisticsFile;
@@ -755,11 +754,10 @@ public void testGarbageCollectionDisabled() {
table.updateProperties().set(TableProperties.GC_ENABLED, "false").commit();
- AssertHelpers.assertThrows(
- "Should complain about removing orphan files",
- ValidationException.class,
- "Cannot delete orphan files: GC is disabled",
- () -> SparkActions.get().deleteOrphanFiles(table).execute());
+ Assertions.assertThatThrownBy(() -> SparkActions.get().deleteOrphanFiles(table).execute())
+ .as("Should complain about removing orphan files")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot delete orphan files: GC is disabled");
}
@Test
@@ -991,18 +989,18 @@ public void testPathsWithActualFileHavingNoAuthority() {
public void testPathsWithEqualSchemes() {
List validFiles = Lists.newArrayList("scheme1://bucket1/dir1/dir2/file1");
List actualFiles = Lists.newArrayList("scheme2://bucket1/dir1/dir2/file1");
- AssertHelpers.assertThrows(
- "Test remove orphan files with equal schemes",
- ValidationException.class,
- "Conflicting authorities/schemes: [(scheme1, scheme2)]",
- () ->
- executeTest(
- validFiles,
- actualFiles,
- Lists.newArrayList(),
- ImmutableMap.of(),
- ImmutableMap.of(),
- DeleteOrphanFiles.PrefixMismatchMode.ERROR));
+ Assertions.assertThatThrownBy(
+ () ->
+ executeTest(
+ validFiles,
+ actualFiles,
+ Lists.newArrayList(),
+ ImmutableMap.of(),
+ ImmutableMap.of(),
+ DeleteOrphanFiles.PrefixMismatchMode.ERROR))
+ .as("Test remove orphan files with equal schemes")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Conflicting authorities/schemes: [(scheme1, scheme2)]");
Map equalSchemes = Maps.newHashMap();
equalSchemes.put("scheme1", "scheme");
@@ -1020,18 +1018,18 @@ public void testPathsWithEqualSchemes() {
public void testPathsWithEqualAuthorities() {
List validFiles = Lists.newArrayList("hdfs://servicename1/dir1/dir2/file1");
List actualFiles = Lists.newArrayList("hdfs://servicename2/dir1/dir2/file1");
- AssertHelpers.assertThrows(
- "Test remove orphan files with equal authorities",
- ValidationException.class,
- "Conflicting authorities/schemes: [(servicename1, servicename2)]",
- () ->
- executeTest(
- validFiles,
- actualFiles,
- Lists.newArrayList(),
- ImmutableMap.of(),
- ImmutableMap.of(),
- DeleteOrphanFiles.PrefixMismatchMode.ERROR));
+ Assertions.assertThatThrownBy(
+ () ->
+ executeTest(
+ validFiles,
+ actualFiles,
+ Lists.newArrayList(),
+ ImmutableMap.of(),
+ ImmutableMap.of(),
+ DeleteOrphanFiles.PrefixMismatchMode.ERROR))
+ .as("Test remove orphan files with equal authorities")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Conflicting authorities/schemes: [(servicename1, servicename2)]");
Map equalAuthorities = Maps.newHashMap();
equalAuthorities.put("servicename1", "servicename");
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRewriteDataFilesAction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRewriteDataFilesAction.java
index cfa1c9da951e..5e8865dff2da 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRewriteDataFilesAction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRewriteDataFilesAction.java
@@ -47,7 +47,6 @@
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.ContentFile;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DeleteFile;
@@ -643,10 +642,10 @@ public void testSingleCommitWithRewriteFailure() {
.when(spyRewrite)
.rewriteFiles(any(), argThat(failGroup));
- AssertHelpers.assertThrows(
- "Should fail entire rewrite if part fails",
- RuntimeException.class,
- () -> spyRewrite.execute());
+ Assertions.assertThatThrownBy(() -> spyRewrite.execute())
+ .as("Should fail entire rewrite if part fails")
+ .isInstanceOf(RuntimeException.class)
+ .hasMessage("Rewrite Failed");
table.refresh();
@@ -678,10 +677,10 @@ public void testSingleCommitWithCommitFailure() {
doReturn(util).when(spyRewrite).commitManager(table.currentSnapshot().snapshotId());
- AssertHelpers.assertThrows(
- "Should fail entire rewrite if commit fails",
- RuntimeException.class,
- () -> spyRewrite.execute());
+ Assertions.assertThatThrownBy(() -> spyRewrite.execute())
+ .as("Should fail entire rewrite if commit fails")
+ .isInstanceOf(RuntimeException.class)
+ .hasMessage("Commit Failure");
table.refresh();
@@ -714,10 +713,10 @@ public void testParallelSingleCommitWithRewriteFailure() {
.when(spyRewrite)
.rewriteFiles(any(), argThat(failGroup));
- AssertHelpers.assertThrows(
- "Should fail entire rewrite if part fails",
- RuntimeException.class,
- () -> spyRewrite.execute());
+ Assertions.assertThatThrownBy(() -> spyRewrite.execute())
+ .as("Should fail entire rewrite if part fails")
+ .isInstanceOf(RuntimeException.class)
+ .hasMessage("Rewrite Failed");
table.refresh();
@@ -859,32 +858,39 @@ public void testParallelPartialProgressWithCommitFailure() {
public void testInvalidOptions() {
Table table = createTable(20);
- AssertHelpers.assertThrows(
- "No negative values for partial progress max commits",
- IllegalArgumentException.class,
- () ->
- basicRewrite(table)
- .option(RewriteDataFiles.PARTIAL_PROGRESS_ENABLED, "true")
- .option(RewriteDataFiles.PARTIAL_PROGRESS_MAX_COMMITS, "-5")
- .execute());
-
- AssertHelpers.assertThrows(
- "No negative values for max concurrent groups",
- IllegalArgumentException.class,
- () ->
- basicRewrite(table)
- .option(RewriteDataFiles.MAX_CONCURRENT_FILE_GROUP_REWRITES, "-5")
- .execute());
-
- AssertHelpers.assertThrows(
- "No unknown options allowed",
- IllegalArgumentException.class,
- () -> basicRewrite(table).option("foobarity", "-5").execute());
-
- AssertHelpers.assertThrows(
- "Cannot set rewrite-job-order to foo",
- IllegalArgumentException.class,
- () -> basicRewrite(table).option(RewriteDataFiles.REWRITE_JOB_ORDER, "foo").execute());
+ Assertions.assertThatThrownBy(
+ () ->
+ basicRewrite(table)
+ .option(RewriteDataFiles.PARTIAL_PROGRESS_ENABLED, "true")
+ .option(RewriteDataFiles.PARTIAL_PROGRESS_MAX_COMMITS, "-5")
+ .execute())
+ .as("No negative values for partial progress max commits")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage(
+ "Cannot set partial-progress.max-commits to -5, "
+ + "the value must be positive when partial-progress.enabled is true");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ basicRewrite(table)
+ .option(RewriteDataFiles.MAX_CONCURRENT_FILE_GROUP_REWRITES, "-5")
+ .execute())
+ .as("No negative values for max concurrent groups")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage(
+ "Cannot set max-concurrent-file-group-rewrites to -5, the value must be positive.");
+
+ Assertions.assertThatThrownBy(() -> basicRewrite(table).option("foobarity", "-5").execute())
+ .as("No unknown options allowed")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage(
+ "Cannot use options [foobarity], they are not supported by the action or the rewriter BIN-PACK");
+
+ Assertions.assertThatThrownBy(
+ () -> basicRewrite(table).option(RewriteDataFiles.REWRITE_JOB_ORDER, "foo").execute())
+ .as("Cannot set rewrite-job-order to foo")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Invalid rewrite job order name: foo");
}
@Test
@@ -1120,10 +1126,11 @@ public void testCommitStateUnknownException() {
doReturn(util).when(spyAction).commitManager(table.currentSnapshot().snapshotId());
- AssertHelpers.assertThrows(
- "Should propagate CommitStateUnknown Exception",
- CommitStateUnknownException.class,
- () -> spyAction.execute());
+ Assertions.assertThatThrownBy(() -> spyAction.execute())
+ .as("Should propagate CommitStateUnknown Exception")
+ .isInstanceOf(CommitStateUnknownException.class)
+ .hasMessageStartingWith(
+ "Unknown State\n" + "Cannot determine whether the commit was successful or not");
List postRewriteData = currentData();
assertEquals("We shouldn't have changed the data", originalData, postRewriteData);
@@ -1239,23 +1246,20 @@ public void testInvalidAPIUsage() {
SortOrder sortOrder = SortOrder.builderFor(table.schema()).asc("c2").build();
- AssertHelpers.assertThrows(
- "Should be unable to set Strategy more than once",
- IllegalArgumentException.class,
- "Must use only one rewriter type",
- () -> actions().rewriteDataFiles(table).binPack().sort());
-
- AssertHelpers.assertThrows(
- "Should be unable to set Strategy more than once",
- IllegalArgumentException.class,
- "Must use only one rewriter type",
- () -> actions().rewriteDataFiles(table).sort(sortOrder).binPack());
-
- AssertHelpers.assertThrows(
- "Should be unable to set Strategy more than once",
- IllegalArgumentException.class,
- "Must use only one rewriter type",
- () -> actions().rewriteDataFiles(table).sort(sortOrder).binPack());
+ Assertions.assertThatThrownBy(() -> actions().rewriteDataFiles(table).binPack().sort())
+ .as("Should be unable to set Strategy more than once")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Must use only one rewriter type");
+
+ Assertions.assertThatThrownBy(() -> actions().rewriteDataFiles(table).sort(sortOrder).binPack())
+ .as("Should be unable to set Strategy more than once")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Must use only one rewriter type");
+
+ Assertions.assertThatThrownBy(() -> actions().rewriteDataFiles(table).sort(sortOrder).binPack())
+ .as("Should be unable to set Strategy more than once")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Must use only one rewriter type");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRewriteManifestsAction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRewriteManifestsAction.java
index a5dd0054da25..339bb1db328e 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRewriteManifestsAction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/actions/TestRewriteManifestsAction.java
@@ -35,7 +35,6 @@
import java.util.List;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.ManifestFile;
import org.apache.iceberg.PartitionSpec;
@@ -59,6 +58,7 @@
import org.apache.spark.sql.Encoders;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.TableIdentifier;
+import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
@@ -231,11 +231,12 @@ public void testRewriteManifestsWithCommitStateUnknownException() {
Table spyTable = spy(table);
when(spyTable.rewriteManifests()).thenReturn(spyNewRewriteManifests);
- AssertHelpers.assertThrowsCause(
- "Should throw a Commit State Unknown Exception",
- RuntimeException.class,
- "Datacenter on Fire",
- () -> actions.rewriteManifests(spyTable).rewriteIf(manifest -> true).execute());
+ Assertions.assertThatThrownBy(
+ () -> actions.rewriteManifests(spyTable).rewriteIf(manifest -> true).execute())
+ .as("Should throw a Commit State Unknown Exception")
+ .cause()
+ .isInstanceOf(RuntimeException.class)
+ .hasMessageContaining("Datacenter on Fire");
table.refresh();
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/data/parquet/vectorized/TestParquetVectorizedReads.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/data/parquet/vectorized/TestParquetVectorizedReads.java
index 53099eefa40c..866bbd240aa5 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/data/parquet/vectorized/TestParquetVectorizedReads.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/data/parquet/vectorized/TestParquetVectorizedReads.java
@@ -27,7 +27,6 @@
import java.security.SecureRandom;
import java.util.Iterator;
import org.apache.avro.generic.GenericData;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Files;
import org.apache.iceberg.Schema;
import org.apache.iceberg.io.CloseableIterable;
@@ -49,6 +48,7 @@
import org.apache.parquet.schema.MessageType;
import org.apache.parquet.schema.Type;
import org.apache.spark.sql.vectorized.ColumnarBatch;
+import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Ignore;
@@ -255,18 +255,18 @@ public void testMixedTypes() {}
@Test
@Override
public void testNestedStruct() {
- AssertHelpers.assertThrows(
- "Vectorized reads are not supported yet for struct fields",
- UnsupportedOperationException.class,
- "Vectorized reads are not supported yet for struct fields",
- () ->
- VectorizedSparkParquetReaders.buildReader(
- TypeUtil.assignIncreasingFreshIds(
- new Schema(required(1, "struct", SUPPORTED_PRIMITIVES))),
- new MessageType(
- "struct", new GroupType(Type.Repetition.OPTIONAL, "struct").withId(1)),
- Maps.newHashMap(),
- null));
+ Assertions.assertThatThrownBy(
+ () ->
+ VectorizedSparkParquetReaders.buildReader(
+ TypeUtil.assignIncreasingFreshIds(
+ new Schema(required(1, "struct", SUPPORTED_PRIMITIVES))),
+ new MessageType(
+ "struct", new GroupType(Type.Repetition.OPTIONAL, "struct").withId(1)),
+ Maps.newHashMap(),
+ null))
+ .as("Vectorized reads are not supported yet for struct fields")
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessageContaining("Vectorized reads are not supported yet for struct fields");
}
@Test
@@ -390,13 +390,10 @@ public void testUnsupportedReadsForParquetV2() throws Exception {
try (FileAppender writer = parquetV2Writer(schema, dataFile)) {
writer.addAll(data);
}
- AssertHelpers.assertThrows(
- "Vectorized reads not supported",
- UnsupportedOperationException.class,
- "Cannot support vectorized reads for column",
- () -> {
- assertRecordsMatch(schema, 30000, data, dataFile, true, BATCH_SIZE);
- return null;
- });
+ Assertions.assertThatThrownBy(
+ () -> assertRecordsMatch(schema, 30000, data, dataFile, true, BATCH_SIZE))
+ .as("Vectorized reads not supported")
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessageContaining("Cannot support vectorized reads for column");
}
}
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestDataFrameWriterV2.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestDataFrameWriterV2.java
index a9b4f0d3ad2f..f57c87e8b809 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestDataFrameWriterV2.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestDataFrameWriterV2.java
@@ -19,7 +19,6 @@
package org.apache.iceberg.spark.source;
import java.util.List;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.TableProperties;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.spark.Spark3Util;
@@ -33,6 +32,7 @@
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
import org.apache.spark.sql.catalyst.parser.ParseException;
import org.apache.spark.sql.internal.SQLConf;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -76,18 +76,18 @@ public void testMergeSchemaFailsWithoutWriterOption() throws Exception {
// this has a different error message than the case without accept-any-schema because it uses
// Iceberg checks
- AssertHelpers.assertThrows(
- "Should fail when merge-schema is not enabled on the writer",
- IllegalArgumentException.class,
- "Field new_col not found in source schema",
- () -> {
- try {
- threeColDF.writeTo(tableName).append();
- } catch (NoSuchTableException e) {
- // needed because append has checked exceptions
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ threeColDF.writeTo(tableName).append();
+ } catch (NoSuchTableException e) {
+ // needed because append has checked exceptions
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Should fail when merge-schema is not enabled on the writer")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Field new_col not found in source schema");
}
@Test
@@ -111,18 +111,18 @@ public void testMergeSchemaWithoutAcceptAnySchema() throws Exception {
"{ \"id\": 3, \"data\": \"c\", \"new_col\": 12.06 }",
"{ \"id\": 4, \"data\": \"d\", \"new_col\": 14.41 }");
- AssertHelpers.assertThrows(
- "Should fail when accept-any-schema is not enabled on the table",
- AnalysisException.class,
- "too many data columns",
- () -> {
- try {
- threeColDF.writeTo(tableName).option("merge-schema", "true").append();
- } catch (NoSuchTableException e) {
- // needed because append has checked exceptions
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ threeColDF.writeTo(tableName).option("merge-schema", "true").append();
+ } catch (NoSuchTableException e) {
+ // needed because append has checked exceptions
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Should fail when accept-any-schema is not enabled on the table")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("too many data columns");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestDataSourceOptions.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestDataSourceOptions.java
index 7e254960e759..2c3a7aba59d1 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestDataSourceOptions.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestDataSourceOptions.java
@@ -25,7 +25,6 @@
import java.util.List;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.FileFormat;
import org.apache.iceberg.FileScanTask;
@@ -246,50 +245,52 @@ public void testIncrementalScanOptions() throws IOException {
List snapshotIds = SnapshotUtil.currentAncestorIds(table);
// start-snapshot-id and snapshot-id are both configured.
- AssertHelpers.assertThrows(
- "Check both start-snapshot-id and snapshot-id are configured",
- IllegalArgumentException.class,
- "Cannot set start-snapshot-id and end-snapshot-id for incremental scans",
- () -> {
- spark
- .read()
- .format("iceberg")
- .option("snapshot-id", snapshotIds.get(3).toString())
- .option("start-snapshot-id", snapshotIds.get(3).toString())
- .load(tableLocation)
- .explain();
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ spark
+ .read()
+ .format("iceberg")
+ .option("snapshot-id", snapshotIds.get(3).toString())
+ .option("start-snapshot-id", snapshotIds.get(3).toString())
+ .load(tableLocation)
+ .explain();
+ })
+ .as("Check both start-snapshot-id and snapshot-id are configured")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(
+ "Cannot set start-snapshot-id and end-snapshot-id for incremental scans");
// end-snapshot-id and as-of-timestamp are both configured.
- AssertHelpers.assertThrows(
- "Check both start-snapshot-id and snapshot-id are configured",
- IllegalArgumentException.class,
- "Cannot set start-snapshot-id and end-snapshot-id for incremental scans",
- () -> {
- spark
- .read()
- .format("iceberg")
- .option(
- SparkReadOptions.AS_OF_TIMESTAMP,
- Long.toString(table.snapshot(snapshotIds.get(3)).timestampMillis()))
- .option("end-snapshot-id", snapshotIds.get(2).toString())
- .load(tableLocation)
- .explain();
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ spark
+ .read()
+ .format("iceberg")
+ .option(
+ SparkReadOptions.AS_OF_TIMESTAMP,
+ Long.toString(table.snapshot(snapshotIds.get(3)).timestampMillis()))
+ .option("end-snapshot-id", snapshotIds.get(2).toString())
+ .load(tableLocation)
+ .explain();
+ })
+ .as("Check both start-snapshot-id and snapshot-id are configured")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(
+ "Cannot set start-snapshot-id and end-snapshot-id for incremental scans");
// only end-snapshot-id is configured.
- AssertHelpers.assertThrows(
- "Check both start-snapshot-id and snapshot-id are configured",
- IllegalArgumentException.class,
- "Cannot set only end-snapshot-id for incremental scans",
- () -> {
- spark
- .read()
- .format("iceberg")
- .option("end-snapshot-id", snapshotIds.get(2).toString())
- .load(tableLocation)
- .explain();
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ spark
+ .read()
+ .format("iceberg")
+ .option("end-snapshot-id", snapshotIds.get(2).toString())
+ .load(tableLocation)
+ .explain();
+ })
+ .as("Check both start-snapshot-id and snapshot-id are configured")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot set only end-snapshot-id for incremental scans");
// test (1st snapshot, current snapshot] incremental scan.
List result =
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestForwardCompatibility.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestForwardCompatibility.java
index 6ab9e57949e3..8630c50151f3 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestForwardCompatibility.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestForwardCompatibility.java
@@ -28,7 +28,6 @@
import java.util.concurrent.TimeoutException;
import org.apache.avro.generic.GenericData;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DataFiles;
import org.apache.iceberg.FileFormat;
@@ -55,6 +54,7 @@
import org.apache.spark.sql.execution.streaming.MemoryStream;
import org.apache.spark.sql.streaming.StreamingQuery;
import org.apache.spark.sql.streaming.StreamingQueryException;
+import org.assertj.core.api.Assertions;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -120,16 +120,16 @@ public void testSparkWriteFailsUnknownTransform() throws IOException {
Dataset df = spark.createDataFrame(expected, SimpleRecord.class);
- AssertHelpers.assertThrows(
- "Should reject write with unsupported transform",
- UnsupportedOperationException.class,
- "Cannot write using unsupported transforms: zero",
- () ->
- df.select("id", "data")
- .write()
- .format("iceberg")
- .mode("append")
- .save(location.toString()));
+ Assertions.assertThatThrownBy(
+ () ->
+ df.select("id", "data")
+ .write()
+ .format("iceberg")
+ .mode("append")
+ .save(location.toString()))
+ .as("Should reject write with unsupported transform")
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessageContaining("Cannot write using unsupported transforms: zero");
}
@Test
@@ -159,11 +159,10 @@ public void testSparkStreamingWriteFailsUnknownTransform() throws IOException, T
List batch1 = Lists.newArrayList(1, 2);
send(batch1, inputStream);
- AssertHelpers.assertThrows(
- "Should reject streaming write with unsupported transform",
- StreamingQueryException.class,
- "Cannot write using unsupported transforms: zero",
- query::processAllAvailable);
+ Assertions.assertThatThrownBy(query::processAllAvailable)
+ .as("Should reject streaming write with unsupported transform")
+ .isInstanceOf(StreamingQueryException.class)
+ .hasMessageContaining("Cannot write using unsupported transforms: zero");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestIcebergSourceTablesBase.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestIcebergSourceTablesBase.java
index 111da882fe8a..079ca5f77fa4 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestIcebergSourceTablesBase.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestIcebergSourceTablesBase.java
@@ -38,7 +38,6 @@
import java.util.stream.StreamSupport;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecordBuilder;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DeleteFile;
import org.apache.iceberg.Files;
@@ -1119,17 +1118,17 @@ public void testPruneManifestsTable() {
if (!spark.version().startsWith("2")) {
// Spark 2 isn't able to actually push down nested struct projections so this will not break
- AssertHelpers.assertThrows(
- "Can't prune struct inside list",
- SparkException.class,
- "Cannot project a partial list element struct",
- () ->
- spark
- .read()
- .format("iceberg")
- .load(loadLocation(tableIdentifier, "manifests"))
- .select("partition_spec_id", "path", "partition_summaries.contains_null")
- .collectAsList());
+ Assertions.assertThatThrownBy(
+ () ->
+ spark
+ .read()
+ .format("iceberg")
+ .load(loadLocation(tableIdentifier, "manifests"))
+ .select("partition_spec_id", "path", "partition_summaries.contains_null")
+ .collectAsList())
+ .as("Can't prune struct inside list")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Cannot project a partial list element struct");
}
Dataset actualDf =
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestMetadataTablesWithPartitionEvolution.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestMetadataTablesWithPartitionEvolution.java
index 0baaef1374d4..9c5d48e1debb 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestMetadataTablesWithPartitionEvolution.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestMetadataTablesWithPartitionEvolution.java
@@ -33,7 +33,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.FileFormat;
import org.apache.iceberg.HasTableOperations;
import org.apache.iceberg.MetadataTableType;
@@ -54,6 +53,7 @@
import org.apache.spark.sql.catalyst.parser.ParseException;
import org.apache.spark.sql.types.DataType;
import org.apache.spark.sql.types.StructType;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -641,11 +641,10 @@ public void testMetadataTablesWithUnknownTransforms() {
sql("REFRESH TABLE %s", tableName);
for (MetadataTableType tableType : Arrays.asList(FILES, ALL_DATA_FILES, ENTRIES, ALL_ENTRIES)) {
- AssertHelpers.assertThrows(
- "Should complain about the partition type",
- ValidationException.class,
- "Cannot build table partition type, unknown transforms",
- () -> loadMetadataTable(tableType));
+ Assertions.assertThatThrownBy(() -> loadMetadataTable(tableType))
+ .as("Should complain about the partition type")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot build table partition type, unknown transforms");
}
}
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestRequiredDistributionAndOrdering.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestRequiredDistributionAndOrdering.java
index 8e54a23f815a..e8e402ac44cc 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestRequiredDistributionAndOrdering.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestRequiredDistributionAndOrdering.java
@@ -20,7 +20,6 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Table;
import org.apache.iceberg.TableProperties;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
@@ -30,6 +29,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Test;
@@ -163,20 +163,20 @@ public void testDisabledDistributionAndOrdering() {
Dataset inputDF = ds.coalesce(1).sortWithinPartitions("c1");
// should fail if ordering is disabled
- AssertHelpers.assertThrows(
- "Should reject writes without ordering",
- SparkException.class,
- "Writing job aborted",
- () -> {
- try {
- inputDF
- .writeTo(tableName)
- .option(SparkWriteOptions.USE_TABLE_DISTRIBUTION_AND_ORDERING, "false")
- .append();
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ inputDF
+ .writeTo(tableName)
+ .option(SparkWriteOptions.USE_TABLE_DISTRIBUTION_AND_ORDERING, "false")
+ .append();
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Should reject writes without ordering")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Writing job aborted");
}
@Test
@@ -233,17 +233,17 @@ public void testNoSortBucketTransformsWithoutExtensions() throws NoSuchTableExce
Dataset inputDF = ds.coalesce(1).sortWithinPartitions("c1");
// should fail by default as extensions are disabled
- AssertHelpers.assertThrows(
- "Should reject writes without ordering",
- SparkException.class,
- "Writing job aborted",
- () -> {
- try {
- inputDF.writeTo(tableName).append();
- } catch (NoSuchTableException e) {
- throw new RuntimeException(e);
- }
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ try {
+ inputDF.writeTo(tableName).append();
+ } catch (NoSuchTableException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .as("Should reject writes without ordering")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Writing job aborted");
inputDF.writeTo(tableName).option(SparkWriteOptions.FANOUT_ENABLED, "true").append();
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkDataWrite.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkDataWrite.java
index 551dc961e309..3d759759f608 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkDataWrite.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkDataWrite.java
@@ -30,7 +30,6 @@
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
import org.apache.iceberg.AppendFiles;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.FileFormat;
import org.apache.iceberg.ManifestFile;
@@ -691,20 +690,21 @@ public void testCommitUnknownException() throws IOException {
ManualSource.setTable(manualTableName, sparkTable);
// Although an exception is thrown here, write and commit have succeeded
- AssertHelpers.assertThrowsWithCause(
- "Should throw a Commit State Unknown Exception",
- SparkException.class,
- "Writing job aborted",
- CommitStateUnknownException.class,
- "Datacenter on Fire",
- () ->
- df2.select("id", "data")
- .sort("data")
- .write()
- .format("org.apache.iceberg.spark.source.ManualSource")
- .option(ManualSource.TABLE_NAME, manualTableName)
- .mode(SaveMode.Append)
- .save(targetLocation));
+ Assertions.assertThatThrownBy(
+ () ->
+ df2.select("id", "data")
+ .sort("data")
+ .write()
+ .format("org.apache.iceberg.spark.source.ManualSource")
+ .option(ManualSource.TABLE_NAME, manualTableName)
+ .mode(SaveMode.Append)
+ .save(targetLocation))
+ .as("Should throw a Commit State Unknown Exception")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Writing job aborted")
+ .cause()
+ .isInstanceOf(CommitStateUnknownException.class)
+ .hasMessageContaining("Datacenter on Fire");
// Since write and commit succeeded, the rows should be readable
Dataset result = spark.read().format("iceberg").load(targetLocation);
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkMetadataColumns.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkMetadataColumns.java
index 5c7929112fb9..2b0033fdcbb5 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkMetadataColumns.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestSparkMetadataColumns.java
@@ -30,7 +30,6 @@
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.FileFormat;
import org.apache.iceberg.HasTableOperations;
import org.apache.iceberg.MetadataColumns;
@@ -53,6 +52,7 @@
import org.apache.spark.sql.Encoders;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -224,11 +224,10 @@ public void testPartitionMetadataColumnWithUnknownTransforms() {
TableMetadata base = ops.current();
ops.commit(base, base.updatePartitionSpec(UNKNOWN_SPEC));
- AssertHelpers.assertThrows(
- "Should fail to query the partition metadata column",
- ValidationException.class,
- "Cannot build table partition type, unknown transforms",
- () -> sql("SELECT _partition FROM %s", TABLE_NAME));
+ Assertions.assertThatThrownBy(() -> sql("SELECT _partition FROM %s", TABLE_NAME))
+ .as("Should fail to query the partition metadata column")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot build table partition type, unknown transforms");
}
@Test
@@ -246,11 +245,10 @@ public void testConflictingColumns() {
ImmutableList.of(row(1L, "a1")),
sql("SELECT id, category FROM %s", TABLE_NAME));
- AssertHelpers.assertThrows(
- "Should fail to query conflicting columns",
- ValidationException.class,
- "column names conflict",
- () -> sql("SELECT * FROM %s", TABLE_NAME));
+ Assertions.assertThatThrownBy(() -> sql("SELECT * FROM %s", TABLE_NAME))
+ .as("Should fail to query conflicting columns")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("column names conflict");
table.refresh();
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestStructuredStreamingRead3.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestStructuredStreamingRead3.java
index de94a7c8bf8b..7a4c25607850 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestStructuredStreamingRead3.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestStructuredStreamingRead3.java
@@ -29,7 +29,6 @@
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.BaseTable;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DataFiles;
@@ -495,11 +494,12 @@ public void testReadStreamWithSnapshotTypeOverwriteErrorsOut() throws Exception
StreamingQuery query = startStream();
- AssertHelpers.assertThrowsCause(
- "Streaming should fail with IllegalStateException, as the snapshot is not of type APPEND",
- IllegalStateException.class,
- "Cannot process overwrite snapshot",
- () -> query.processAllAvailable());
+ Assertions.assertThatThrownBy(() -> query.processAllAvailable())
+ .as(
+ "Streaming should fail with IllegalStateException, as the snapshot is not of type APPEND")
+ .cause()
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageContaining("Cannot process overwrite snapshot");
}
@Test
@@ -536,11 +536,12 @@ public void testReadStreamWithSnapshotTypeDeleteErrorsOut() throws Exception {
StreamingQuery query = startStream();
- AssertHelpers.assertThrowsCause(
- "Streaming should fail with IllegalStateException, as the snapshot is not of type APPEND",
- IllegalStateException.class,
- "Cannot process delete snapshot",
- () -> query.processAllAvailable());
+ Assertions.assertThatThrownBy(() -> query.processAllAvailable())
+ .as(
+ "Streaming should fail with IllegalStateException, as the snapshot is not of type APPEND")
+ .cause()
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageContaining("Cannot process delete snapshot");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestTimestampWithoutZone.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestTimestampWithoutZone.java
index 053f6dbaea46..d85e1954950d 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestTimestampWithoutZone.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestTimestampWithoutZone.java
@@ -28,7 +28,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.DataFiles;
import org.apache.iceberg.FileFormat;
@@ -53,6 +52,7 @@
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SaveMode;
import org.apache.spark.sql.SparkSession;
+import org.assertj.core.api.Assertions;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
@@ -159,21 +159,22 @@ public void testUnpartitionedTimestampWithoutZoneProjection() {
@Test
public void testUnpartitionedTimestampWithoutZoneError() {
- AssertHelpers.assertThrows(
- String.format(
- "Read operation performed on a timestamp without timezone field while "
- + "'%s' set to false should throw exception",
- SparkReadOptions.HANDLE_TIMESTAMP_WITHOUT_TIMEZONE),
- IllegalArgumentException.class,
- SparkUtil.TIMESTAMP_WITHOUT_TIMEZONE_ERROR,
- () ->
- spark
- .read()
- .format("iceberg")
- .option(SparkReadOptions.VECTORIZATION_ENABLED, String.valueOf(vectorized))
- .option(SparkReadOptions.HANDLE_TIMESTAMP_WITHOUT_TIMEZONE, "false")
- .load(unpartitioned.toString())
- .collectAsList());
+ Assertions.assertThatThrownBy(
+ () ->
+ spark
+ .read()
+ .format("iceberg")
+ .option(SparkReadOptions.VECTORIZATION_ENABLED, String.valueOf(vectorized))
+ .option(SparkReadOptions.HANDLE_TIMESTAMP_WITHOUT_TIMEZONE, "false")
+ .load(unpartitioned.toString())
+ .collectAsList())
+ .as(
+ String.format(
+ "Read operation performed on a timestamp without timezone field while "
+ + "'%s' set to false should throw exception",
+ SparkReadOptions.HANDLE_TIMESTAMP_WITHOUT_TIMEZONE))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(SparkUtil.TIMESTAMP_WITHOUT_TIMEZONE_ERROR);
}
@Test
@@ -217,11 +218,10 @@ public void testUnpartitionedTimestampWithoutZoneWriteError() {
.mode(SaveMode.Append)
.save(unpartitioned.toString());
- AssertHelpers.assertThrows(
- errorMessage,
- IllegalArgumentException.class,
- SparkUtil.TIMESTAMP_WITHOUT_TIMEZONE_ERROR,
- writeOperation);
+ Assertions.assertThatThrownBy(writeOperation::run)
+ .as(errorMessage)
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(SparkUtil.TIMESTAMP_WITHOUT_TIMEZONE_ERROR);
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestWriteMetricsConfig.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestWriteMetricsConfig.java
index 9bf00f1b1365..fd88eb2c907e 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestWriteMetricsConfig.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/source/TestWriteMetricsConfig.java
@@ -27,7 +27,6 @@
import java.util.List;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.DataFile;
import org.apache.iceberg.FileScanTask;
import org.apache.iceberg.PartitionSpec;
@@ -49,6 +48,7 @@
import org.apache.spark.sql.SaveMode;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.catalyst.InternalRow;
+import org.assertj.core.api.Assertions;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -231,11 +231,13 @@ public void testBadCustomMetricCollectionForParquet() throws IOException {
properties.put(TableProperties.DEFAULT_WRITE_METRICS_MODE, "counts");
properties.put("write.metadata.metrics.column.ids", "full");
- AssertHelpers.assertThrows(
- "Creating a table with invalid metrics should fail",
- ValidationException.class,
- null,
- () -> tables.create(SIMPLE_SCHEMA, spec, properties, tableLocation));
+ Assertions.assertThatThrownBy(
+ () -> tables.create(SIMPLE_SCHEMA, spec, properties, tableLocation))
+ .as("Creating a table with invalid metrics should fail")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageStartingWith(
+ "Invalid metrics config, could not find column ids from table prop write.metadata.metrics.column.ids in "
+ + "schema table");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestAlterTable.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestAlterTable.java
index e347cde7ba32..901a7c15e78f 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestAlterTable.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestAlterTable.java
@@ -19,7 +19,6 @@
package org.apache.iceberg.spark.sql;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.catalog.Namespace;
import org.apache.iceberg.catalog.TableIdentifier;
import org.apache.iceberg.hadoop.HadoopCatalog;
@@ -28,6 +27,7 @@
import org.apache.iceberg.types.Types.NestedField;
import org.apache.spark.SparkException;
import org.apache.spark.sql.AnalysisException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -55,11 +55,10 @@ public void removeTable() {
@Test
public void testAddColumnNotNull() {
- AssertHelpers.assertThrows(
- "Should reject adding NOT NULL column",
- SparkException.class,
- "Incompatible change: cannot add required column",
- () -> sql("ALTER TABLE %s ADD COLUMN c3 INT NOT NULL", tableName));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s ADD COLUMN c3 INT NOT NULL", tableName))
+ .as("Should reject adding NOT NULL column")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Incompatible change: cannot add required column");
}
@Test
@@ -156,11 +155,10 @@ public void testAddColumnWithMap() {
validationCatalog.loadTable(tableIdent).schema().asStruct());
// should not allow changing map key column
- AssertHelpers.assertThrows(
- "Should reject changing key of the map column",
- SparkException.class,
- "Unsupported table change: Cannot add fields to map keys:",
- () -> sql("ALTER TABLE %s ADD COLUMN data2.key.y int", tableName));
+ Assertions.assertThatThrownBy(() -> sql("ALTER TABLE %s ADD COLUMN data2.key.y int", tableName))
+ .as("Should reject changing key of the map column")
+ .isInstanceOf(SparkException.class)
+ .hasMessageContaining("Unsupported table change: Cannot add fields to map keys:");
}
@Test
@@ -253,11 +251,11 @@ public void testAlterColumnSetNotNull() {
expectedSchema,
validationCatalog.loadTable(tableIdent).schema().asStruct());
- AssertHelpers.assertThrows(
- "Should reject adding NOT NULL constraint to an optional column",
- AnalysisException.class,
- "Cannot change nullable column to non-nullable: data",
- () -> sql("ALTER TABLE %s ALTER COLUMN data SET NOT NULL", tableName));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s ALTER COLUMN data SET NOT NULL", tableName))
+ .as("Should reject adding NOT NULL constraint to an optional column")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Cannot change nullable column to non-nullable: data");
}
@Test
@@ -323,9 +321,11 @@ public void testSetTableProperties() {
"Should not have the removed table property",
validationCatalog.loadTable(tableIdent).properties().get("prop"));
- AssertHelpers.assertThrows(
- "Cannot specify the 'sort-order' because it's a reserved table property",
- UnsupportedOperationException.class,
- () -> sql("ALTER TABLE %s SET TBLPROPERTIES ('sort-order'='value')", tableName));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s SET TBLPROPERTIES ('sort-order'='value')", tableName))
+ .as("Cannot specify the 'sort-order' because it's a reserved table property")
+ .isInstanceOf(UnsupportedOperationException.class)
+ .hasMessageStartingWith(
+ "Cannot specify the 'sort-order' because it's a reserved table property");
}
}
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestCreateTable.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestCreateTable.java
index 3a62361590d1..f4bef9cec155 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestCreateTable.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestCreateTable.java
@@ -21,7 +21,6 @@
import java.io.File;
import java.util.Map;
import java.util.UUID;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.BaseTable;
import org.apache.iceberg.PartitionSpec;
import org.apache.iceberg.Schema;
@@ -168,14 +167,14 @@ public void testCreateTableUsingParquet() {
"parquet",
table.properties().get(TableProperties.DEFAULT_FILE_FORMAT));
- AssertHelpers.assertThrows(
- "Should reject unsupported format names",
- IllegalArgumentException.class,
- "Unsupported format in USING: crocodile",
- () ->
- sql(
- "CREATE TABLE %s.default.fail (id BIGINT NOT NULL, data STRING) USING crocodile",
- catalogName));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "CREATE TABLE %s.default.fail (id BIGINT NOT NULL, data STRING) USING crocodile",
+ catalogName))
+ .as("Should reject unsupported format names")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Unsupported format in USING: crocodile");
}
@Test
@@ -382,10 +381,11 @@ public void testDowngradeTableToFormatV1ThroughTablePropertyFails() {
TableOperations ops = ((BaseTable) table).operations();
Assert.assertEquals("should create table using format v2", 2, ops.refresh().formatVersion());
- AssertHelpers.assertThrowsCause(
- "should fail to downgrade to v1",
- IllegalArgumentException.class,
- "Cannot downgrade v2 table to v1",
- () -> sql("ALTER TABLE %s SET TBLPROPERTIES ('format-version'='1')", tableName));
+ Assertions.assertThatThrownBy(
+ () -> sql("ALTER TABLE %s SET TBLPROPERTIES ('format-version'='1')", tableName))
+ .as("should fail to downgrade to v1")
+ .cause()
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot downgrade v2 table to v1");
}
}
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestDeleteFrom.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestDeleteFrom.java
index cae1901aa713..55031188453a 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestDeleteFrom.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestDeleteFrom.java
@@ -20,7 +20,6 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Table;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
@@ -30,6 +29,7 @@
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
@@ -86,11 +86,11 @@ public void testDeleteFromTableAtSnapshot() throws NoSuchTableException {
long snapshotId = validationCatalog.loadTable(tableIdent).currentSnapshot().snapshotId();
String prefix = "snapshot_id_";
- AssertHelpers.assertThrows(
- "Should not be able to delete from a table at a specific snapshot",
- IllegalArgumentException.class,
- "Cannot delete from table at a specific snapshot",
- () -> sql("DELETE FROM %s.%s WHERE id < 4", tableName, prefix + snapshotId));
+ Assertions.assertThatThrownBy(
+ () -> sql("DELETE FROM %s.%s WHERE id < 4", tableName, prefix + snapshotId))
+ .as("Should not be able to delete from a table at a specific snapshot")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot delete from table at a specific snapshot");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestDropTable.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestDropTable.java
index 2189bd0dae75..c5c39e5d782f 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestDropTable.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestDropTable.java
@@ -24,12 +24,12 @@
import java.util.stream.Collectors;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.MetadataTableType;
import org.apache.iceberg.exceptions.ValidationException;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.Streams;
import org.apache.iceberg.spark.SparkCatalogTestBase;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -116,11 +116,11 @@ public void testPurgeTableGCDisabled() throws IOException {
"There totally should have 2 files for manifests and files", 2, manifestAndFiles.size());
Assert.assertTrue("All files should be existed", checkFilesExist(manifestAndFiles, true));
- AssertHelpers.assertThrows(
- "Purge table is not allowed when GC is disabled",
- ValidationException.class,
- "Cannot purge table: GC is disabled (deleting files may corrupt other tables",
- () -> sql("DROP TABLE %s PURGE", tableName));
+ Assertions.assertThatThrownBy(() -> sql("DROP TABLE %s PURGE", tableName))
+ .as("Purge table is not allowed when GC is disabled")
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining(
+ "Cannot purge table: GC is disabled (deleting files may corrupt other tables");
Assert.assertTrue("Table should not been dropped", validationCatalog.tableExists(tableIdent));
Assert.assertTrue("All files should not be deleted", checkFilesExist(manifestAndFiles, true));
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestNamespaceSQL.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestNamespaceSQL.java
index 6c29ea4442ef..77b564cd001b 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestNamespaceSQL.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestNamespaceSQL.java
@@ -23,13 +23,13 @@
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.catalog.Namespace;
import org.apache.iceberg.catalog.TableIdentifier;
import org.apache.iceberg.exceptions.NamespaceNotEmptyException;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableSet;
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
import org.apache.iceberg.spark.SparkCatalogTestBase;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -103,11 +103,10 @@ public void testDropNonEmptyNamespace() {
Assert.assertTrue(
"Table should exist", validationCatalog.tableExists(TableIdentifier.of(NS, "table")));
- AssertHelpers.assertThrows(
- "Should fail if trying to delete a non-empty namespace",
- NamespaceNotEmptyException.class,
- "Namespace db is not empty.",
- () -> sql("DROP NAMESPACE %s", fullNamespace));
+ Assertions.assertThatThrownBy(() -> sql("DROP NAMESPACE %s", fullNamespace))
+ .as("Should fail if trying to delete a non-empty namespace")
+ .isInstanceOf(NamespaceNotEmptyException.class)
+ .hasMessageContaining("Namespace db is not empty.");
sql("DROP TABLE %s.table", fullNamespace);
}
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSelect.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSelect.java
index 2265dec4763c..ea97949d1327 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSelect.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSelect.java
@@ -23,7 +23,6 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Table;
import org.apache.iceberg.events.Listeners;
import org.apache.iceberg.events.ScanEvent;
@@ -396,48 +395,48 @@ public void testInvalidTimeTravelBasedOnBothAsOfAndTableIdentifier() {
sql("INSERT INTO %s VALUES (4, 'd', 4.0), (5, 'e', 5.0)", tableName);
// using snapshot in table identifier and VERSION AS OF
- AssertHelpers.assertThrows(
- "Cannot do time-travel based on both table identifier and AS OF",
- IllegalArgumentException.class,
- "Cannot do time-travel based on both table identifier and AS OF",
- () -> {
- sql(
- "SELECT * FROM %s.%s VERSION AS OF %s",
- tableName, snapshotPrefix + snapshotId, snapshotId);
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "SELECT * FROM %s.%s VERSION AS OF %s",
+ tableName, snapshotPrefix + snapshotId, snapshotId);
+ })
+ .as("Cannot do time-travel based on both table identifier and AS OF")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot do time-travel based on both table identifier and AS OF");
// using snapshot in table identifier and TIMESTAMP AS OF
- AssertHelpers.assertThrows(
- "Cannot do time-travel based on both table identifier and AS OF",
- IllegalArgumentException.class,
- "Cannot do time-travel based on both table identifier and AS OF",
- () -> {
- sql(
- "SELECT * FROM %s.%s VERSION AS OF %s",
- tableName, timestampPrefix + timestamp, snapshotId);
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "SELECT * FROM %s.%s VERSION AS OF %s",
+ tableName, timestampPrefix + timestamp, snapshotId);
+ })
+ .as("Cannot do time-travel based on both table identifier and AS OF")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot do time-travel based on both table identifier and AS OF");
// using timestamp in table identifier and VERSION AS OF
- AssertHelpers.assertThrows(
- "Cannot do time-travel based on both table identifier and AS OF",
- IllegalArgumentException.class,
- "Cannot do time-travel based on both table identifier and AS OF",
- () -> {
- sql(
- "SELECT * FROM %s.%s TIMESTAMP AS OF %s",
- tableName, snapshotPrefix + snapshotId, timestamp);
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "SELECT * FROM %s.%s TIMESTAMP AS OF %s",
+ tableName, snapshotPrefix + snapshotId, timestamp);
+ })
+ .as("Cannot do time-travel based on both table identifier and AS OF")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot do time-travel based on both table identifier and AS OF");
// using timestamp in table identifier and TIMESTAMP AS OF
- AssertHelpers.assertThrows(
- "Cannot do time-travel based on both table identifier and AS OF",
- IllegalArgumentException.class,
- "Cannot do time-travel based on both table identifier and AS OF",
- () -> {
- sql(
- "SELECT * FROM %s.%s TIMESTAMP AS OF %s",
- tableName, timestampPrefix + timestamp, timestamp);
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ sql(
+ "SELECT * FROM %s.%s TIMESTAMP AS OF %s",
+ tableName, timestampPrefix + timestamp, timestamp);
+ })
+ .as("Cannot do time-travel based on both table identifier and AS OF")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot do time-travel based on both table identifier and AS OF");
}
@Test
@@ -472,21 +471,22 @@ public void testSpecifySnapshotAndTimestamp() {
// create a second snapshot
sql("INSERT INTO %s VALUES (4, 'd', 4.0), (5, 'e', 5.0)", tableName);
- AssertHelpers.assertThrows(
- "Should not be able to specify both snapshot id and timestamp",
- IllegalArgumentException.class,
- String.format(
- "Can specify only one of snapshot-id (%s), as-of-timestamp (%s)",
- snapshotId, timestamp),
- () -> {
- spark
- .read()
- .format("iceberg")
- .option(SparkReadOptions.SNAPSHOT_ID, snapshotId)
- .option(SparkReadOptions.AS_OF_TIMESTAMP, timestamp)
- .load(tableName)
- .collectAsList();
- });
+ Assertions.assertThatThrownBy(
+ () -> {
+ spark
+ .read()
+ .format("iceberg")
+ .option(SparkReadOptions.SNAPSHOT_ID, snapshotId)
+ .option(SparkReadOptions.AS_OF_TIMESTAMP, timestamp)
+ .load(tableName)
+ .collectAsList();
+ })
+ .as("Should not be able to specify both snapshot id and timestamp")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(
+ String.format(
+ "Can specify only one of snapshot-id (%s), as-of-timestamp (%s)",
+ snapshotId, timestamp));
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkBucketFunction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkBucketFunction.java
index c9c8c02b417c..2cf2865fe8bb 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkBucketFunction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkBucketFunction.java
@@ -21,7 +21,6 @@
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.expressions.Literal;
import org.apache.iceberg.relocated.com.google.common.io.BaseEncoding;
import org.apache.iceberg.spark.SparkTestBaseWithCatalog;
@@ -191,101 +190,107 @@ public void testNumBucketsAcceptsShortAndByte() {
@Test
public void testWrongNumberOfArguments() {
- AssertHelpers.assertThrows(
- "Function resolution should not work with zero arguments",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (): Wrong number of inputs (expected numBuckets and value)",
- () -> scalarSql("SELECT system.bucket()"));
-
- AssertHelpers.assertThrows(
- "Function resolution should not work with only one argument",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int): Wrong number of inputs (expected numBuckets and value)",
- () -> scalarSql("SELECT system.bucket(1)"));
-
- AssertHelpers.assertThrows(
- "Function resolution should not work with more than two arguments",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int, bigint, int): Wrong number of inputs (expected numBuckets and value)",
- () -> scalarSql("SELECT system.bucket(1, 1L, 1)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.bucket()"))
+ .as("Function resolution should not work with zero arguments")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (): Wrong number of inputs (expected numBuckets and value)");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.bucket(1)"))
+ .as("Function resolution should not work with only one argument")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (int): Wrong number of inputs (expected numBuckets and value)");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.bucket(1, 1L, 1)"))
+ .as("Function resolution should not work with more than two arguments")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (int, bigint, int): Wrong number of inputs (expected numBuckets and value)");
}
@Test
public void testInvalidTypesCannotBeUsedForNumberOfBuckets() {
- AssertHelpers.assertThrows(
- "Decimal type should not be coercible to the number of buckets",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (decimal(9,2), int): Expected number of buckets to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.bucket(CAST('12.34' as DECIMAL(9, 2)), 10)"));
-
- AssertHelpers.assertThrows(
- "Long type should not be coercible to the number of buckets",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (bigint, int): Expected number of buckets to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.bucket(12L, 10)"));
-
- AssertHelpers.assertThrows(
- "String type should not be coercible to the number of buckets",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (string, int): Expected number of buckets to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.bucket('5', 10)"));
-
- AssertHelpers.assertThrows(
- "Interval year to month type should not be coercible to the number of buckets",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (interval year to month, int): Expected number of buckets to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.bucket(INTERVAL '100-00' YEAR TO MONTH, 10)"));
-
- AssertHelpers.assertThrows(
- "Interval day-time type should not be coercible to the number of buckets",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (interval day to second, int): Expected number of buckets to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.bucket(CAST('11 23:4:0' AS INTERVAL DAY TO SECOND), 10)"));
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.bucket(CAST('12.34' as DECIMAL(9, 2)), 10)"))
+ .as("Decimal type should not be coercible to the number of buckets")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (decimal(9,2), int): Expected number of buckets to be tinyint, shortint or int");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.bucket(12L, 10)"))
+ .as("Long type should not be coercible to the number of buckets")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (bigint, int): Expected number of buckets to be tinyint, shortint or int");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.bucket('5', 10)"))
+ .as("String type should not be coercible to the number of buckets")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (string, int): Expected number of buckets to be tinyint, shortint or int");
+
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.bucket(INTERVAL '100-00' YEAR TO MONTH, 10)"))
+ .as("Interval year to month type should not be coercible to the number of buckets")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (interval year to month, int): Expected number of buckets to be tinyint, shortint or int");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql("SELECT system.bucket(CAST('11 23:4:0' AS INTERVAL DAY TO SECOND), 10)"))
+ .as("Interval day-time type should not be coercible to the number of buckets")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (interval day to second, int): Expected number of buckets to be tinyint, shortint or int");
}
@Test
public void testInvalidTypesForBucketColumn() {
- AssertHelpers.assertThrows(
- "Double type should not be bucketable",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int, float): Expected column to be date, tinyint, smallint, int, bigint, decimal, timestamp, string, or binary",
- () -> scalarSql("SELECT system.bucket(10, cast(12.3456 as float))"));
-
- AssertHelpers.assertThrows(
- "Double type should not be bucketable",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int, double): Expected column to be date, tinyint, smallint, int, bigint, decimal, timestamp, string, or binary",
- () -> scalarSql("SELECT system.bucket(10, cast(12.3456 as double))"));
-
- AssertHelpers.assertThrows(
- "Boolean type should not be bucketable",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int, boolean)",
- () -> scalarSql("SELECT system.bucket(10, true)"));
-
- AssertHelpers.assertThrows(
- "Map types should not be bucketable",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int, map)",
- () -> scalarSql("SELECT system.bucket(10, map(1, 1))"));
-
- AssertHelpers.assertThrows(
- "Array types should not be bucketable",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int, array)",
- () -> scalarSql("SELECT system.bucket(10, array(1L))"));
-
- AssertHelpers.assertThrows(
- "Interval year-to-month type should not be bucketable",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int, interval year to month)",
- () -> scalarSql("SELECT system.bucket(10, INTERVAL '100-00' YEAR TO MONTH)"));
-
- AssertHelpers.assertThrows(
- "Interval day-time type should not be bucketable",
- AnalysisException.class,
- "Function 'bucket' cannot process input: (int, interval day to second)",
- () -> scalarSql("SELECT system.bucket(10, CAST('11 23:4:0' AS INTERVAL DAY TO SECOND))"));
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.bucket(10, cast(12.3456 as float))"))
+ .as("Double type should not be bucketable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (int, float): Expected column to be date, tinyint, smallint, int, bigint, decimal, timestamp, string, or binary");
+
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.bucket(10, cast(12.3456 as double))"))
+ .as("Double type should not be bucketable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (int, double): Expected column to be date, tinyint, smallint, int, bigint, decimal, timestamp, string, or binary");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.bucket(10, true)"))
+ .as("Boolean type should not be bucketable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Function 'bucket' cannot process input: (int, boolean)");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.bucket(10, map(1, 1))"))
+ .as("Map types should not be bucketable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Function 'bucket' cannot process input: (int, map)");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.bucket(10, array(1L))"))
+ .as("Array types should not be bucketable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Function 'bucket' cannot process input: (int, array)");
+
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.bucket(10, INTERVAL '100-00' YEAR TO MONTH)"))
+ .as("Interval year-to-month type should not be bucketable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (int, interval year to month)");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql("SELECT system.bucket(10, CAST('11 23:4:0' AS INTERVAL DAY TO SECOND))"))
+ .as("Interval day-time type should not be bucketable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'bucket' cannot process input: (int, interval day to second)");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkDaysFunction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkDaysFunction.java
index ccba28735e33..e139d3d000ef 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkDaysFunction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkDaysFunction.java
@@ -19,9 +19,9 @@
package org.apache.iceberg.spark.sql;
import java.sql.Date;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.spark.SparkTestBaseWithCatalog;
import org.apache.spark.sql.AnalysisException;
+import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -69,31 +69,31 @@ public void testTimestamps() {
@Test
public void testWrongNumberOfArguments() {
- AssertHelpers.assertThrows(
- "Function resolution should not work with zero arguments",
- AnalysisException.class,
- "Function 'days' cannot process input: (): Wrong number of inputs",
- () -> scalarSql("SELECT system.days()"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.days()"))
+ .as("Function resolution should not work with zero arguments")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Function 'days' cannot process input: (): Wrong number of inputs");
- AssertHelpers.assertThrows(
- "Function resolution should not work with more than one argument",
- AnalysisException.class,
- "Function 'days' cannot process input: (date, date): Wrong number of inputs",
- () -> scalarSql("SELECT system.days(date('1969-12-31'), date('1969-12-31'))"));
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.days(date('1969-12-31'), date('1969-12-31'))"))
+ .as("Function resolution should not work with more than one argument")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'days' cannot process input: (date, date): Wrong number of inputs");
}
@Test
public void testInvalidInputTypes() {
- AssertHelpers.assertThrows(
- "Int type should not be coercible to date/timestamp",
- AnalysisException.class,
- "Function 'days' cannot process input: (int): Expected value to be date or timestamp",
- () -> scalarSql("SELECT system.days(1)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.days(1)"))
+ .as("Int type should not be coercible to date/timestamp")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'days' cannot process input: (int): Expected value to be date or timestamp");
- AssertHelpers.assertThrows(
- "Long type should not be coercible to date/timestamp",
- AnalysisException.class,
- "Function 'days' cannot process input: (bigint): Expected value to be date or timestamp",
- () -> scalarSql("SELECT system.days(1L)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.days(1L)"))
+ .as("Long type should not be coercible to date/timestamp")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'days' cannot process input: (bigint): Expected value to be date or timestamp");
}
}
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkHoursFunction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkHoursFunction.java
index fc0d781318c9..312299ffee09 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkHoursFunction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkHoursFunction.java
@@ -18,9 +18,9 @@
*/
package org.apache.iceberg.spark.sql;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.spark.SparkTestBaseWithCatalog;
import org.apache.spark.sql.AnalysisException;
+import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -51,31 +51,31 @@ public void testTimestamps() {
@Test
public void testWrongNumberOfArguments() {
- AssertHelpers.assertThrows(
- "Function resolution should not work with zero arguments",
- AnalysisException.class,
- "Function 'hours' cannot process input: (): Wrong number of inputs",
- () -> scalarSql("SELECT system.hours()"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.hours()"))
+ .as("Function resolution should not work with zero arguments")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Function 'hours' cannot process input: (): Wrong number of inputs");
- AssertHelpers.assertThrows(
- "Function resolution should not work with more than one argument",
- AnalysisException.class,
- "Function 'hours' cannot process input: (date, date): Wrong number of inputs",
- () -> scalarSql("SELECT system.hours(date('1969-12-31'), date('1969-12-31'))"));
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.hours(date('1969-12-31'), date('1969-12-31'))"))
+ .as("Function resolution should not work with more than one argument")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'hours' cannot process input: (date, date): Wrong number of inputs");
}
@Test
public void testInvalidInputTypes() {
- AssertHelpers.assertThrows(
- "Int type should not be coercible to timestamp",
- AnalysisException.class,
- "Function 'hours' cannot process input: (int): Expected value to be timestamp",
- () -> scalarSql("SELECT system.hours(1)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.hours(1)"))
+ .as("Int type should not be coercible to timestamp")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'hours' cannot process input: (int): Expected value to be timestamp");
- AssertHelpers.assertThrows(
- "Long type should not be coercible to timestamp",
- AnalysisException.class,
- "Function 'hours' cannot process input: (bigint): Expected value to be timestamp",
- () -> scalarSql("SELECT system.hours(1L)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.hours(1L)"))
+ .as("Long type should not be coercible to timestamp")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'hours' cannot process input: (bigint): Expected value to be timestamp");
}
}
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkMonthsFunction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkMonthsFunction.java
index b88bf00256b0..c95823b889c3 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkMonthsFunction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkMonthsFunction.java
@@ -18,7 +18,6 @@
*/
package org.apache.iceberg.spark.sql;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.spark.SparkTestBaseWithCatalog;
import org.apache.iceberg.spark.functions.MonthsFunction;
import org.apache.spark.sql.AnalysisException;
@@ -68,32 +67,32 @@ public void testTimestamps() {
@Test
public void testWrongNumberOfArguments() {
- AssertHelpers.assertThrows(
- "Function resolution should not work with zero arguments",
- AnalysisException.class,
- "Function 'months' cannot process input: (): Wrong number of inputs",
- () -> scalarSql("SELECT system.months()"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.months()"))
+ .as("Function resolution should not work with zero arguments")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Function 'months' cannot process input: (): Wrong number of inputs");
- AssertHelpers.assertThrows(
- "Function resolution should not work with more than one argument",
- AnalysisException.class,
- "Function 'months' cannot process input: (date, date): Wrong number of inputs",
- () -> scalarSql("SELECT system.months(date('1969-12-31'), date('1969-12-31'))"));
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.months(date('1969-12-31'), date('1969-12-31'))"))
+ .as("Function resolution should not work with more than one argument")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'months' cannot process input: (date, date): Wrong number of inputs");
}
@Test
public void testInvalidInputTypes() {
- AssertHelpers.assertThrows(
- "Int type should not be coercible to date/timestamp",
- AnalysisException.class,
- "Function 'months' cannot process input: (int): Expected value to be date or timestamp",
- () -> scalarSql("SELECT system.months(1)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.months(1)"))
+ .as("Int type should not be coercible to date/timestamp")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'months' cannot process input: (int): Expected value to be date or timestamp");
- AssertHelpers.assertThrows(
- "Long type should not be coercible to date/timestamp",
- AnalysisException.class,
- "Function 'months' cannot process input: (bigint): Expected value to be date or timestamp",
- () -> scalarSql("SELECT system.months(1L)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.months(1L)"))
+ .as("Long type should not be coercible to date/timestamp")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'months' cannot process input: (bigint): Expected value to be date or timestamp");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkTruncateFunction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkTruncateFunction.java
index f21544fcdf7a..aaf4f569b655 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkTruncateFunction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkTruncateFunction.java
@@ -20,7 +20,6 @@
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.relocated.com.google.common.io.BaseEncoding;
import org.apache.iceberg.spark.SparkTestBaseWithCatalog;
import org.apache.spark.sql.AnalysisException;
@@ -298,95 +297,106 @@ public void testWidthAcceptsShortAndByte() {
@Test
public void testWrongNumberOfArguments() {
- AssertHelpers.assertThrows(
- "Function resolution should not work with zero arguments",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (): Wrong number of inputs (expected width and value)",
- () -> scalarSql("SELECT system.truncate()"));
-
- AssertHelpers.assertThrows(
- "Function resolution should not work with only one argument",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int): Wrong number of inputs (expected width and value)",
- () -> scalarSql("SELECT system.truncate(1)"));
-
- AssertHelpers.assertThrows(
- "Function resolution should not work with more than two arguments",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int, bigint, int): Wrong number of inputs (expected width and value)",
- () -> scalarSql("SELECT system.truncate(1, 1L, 1)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.truncate()"))
+ .as("Function resolution should not work with zero arguments")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (): Wrong number of inputs (expected width and value)");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.truncate(1)"))
+ .as("Function resolution should not work with only one argument")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int): Wrong number of inputs (expected width and value)");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.truncate(1, 1L, 1)"))
+ .as("Function resolution should not work with more than two arguments")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int, bigint, int): Wrong number of inputs (expected width and value)");
}
@Test
public void testInvalidTypesCannotBeUsedForWidth() {
- AssertHelpers.assertThrows(
- "Decimal type should not be coercible to the width field",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (decimal(9,2), int): Expected truncation width to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.truncate(CAST('12.34' as DECIMAL(9, 2)), 10)"));
-
- AssertHelpers.assertThrows(
- "String type should not be coercible to the width field",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (string, int): Expected truncation width to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.truncate('5', 10)"));
-
- AssertHelpers.assertThrows(
- "Interval year to month type should not be coercible to the width field",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (interval year to month, int): Expected truncation width to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.truncate(INTERVAL '100-00' YEAR TO MONTH, 10)"));
-
- AssertHelpers.assertThrows(
- "Interval day-time type should not be coercible to the width field",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (interval day to second, int): Expected truncation width to be tinyint, shortint or int",
- () -> scalarSql("SELECT system.truncate(CAST('11 23:4:0' AS INTERVAL DAY TO SECOND), 10)"));
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.truncate(CAST('12.34' as DECIMAL(9, 2)), 10)"))
+ .as("Decimal type should not be coercible to the width field")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (decimal(9,2), int): Expected truncation width to be tinyint, shortint or int");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.truncate('5', 10)"))
+ .as("String type should not be coercible to the width field")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (string, int): Expected truncation width to be tinyint, shortint or int");
+
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.truncate(INTERVAL '100-00' YEAR TO MONTH, 10)"))
+ .as("Interval year to month type should not be coercible to the width field")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (interval year to month, int): Expected truncation width to be tinyint, shortint or int");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql(
+ "SELECT system.truncate(CAST('11 23:4:0' AS INTERVAL DAY TO SECOND), 10)"))
+ .as("Interval day-time type should not be coercible to the width field")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (interval day to second, int): Expected truncation width to be tinyint, shortint or int");
}
@Test
public void testInvalidTypesForTruncationColumn() {
- AssertHelpers.assertThrows(
- "FLoat type should not be truncatable",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int, float): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary",
- () -> scalarSql("SELECT system.truncate(10, cast(12.3456 as float))"));
-
- AssertHelpers.assertThrows(
- "Double type should not be truncatable",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int, double): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary",
- () -> scalarSql("SELECT system.truncate(10, cast(12.3456 as double))"));
-
- AssertHelpers.assertThrows(
- "Boolean type should not be truncatable",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int, boolean): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary",
- () -> scalarSql("SELECT system.truncate(10, true)"));
-
- AssertHelpers.assertThrows(
- "Map types should not be truncatable",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int, map): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary",
- () -> scalarSql("SELECT system.truncate(10, map(1, 1))"));
-
- AssertHelpers.assertThrows(
- "Array types should not be truncatable",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int, array): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary",
- () -> scalarSql("SELECT system.truncate(10, array(1L))"));
-
- AssertHelpers.assertThrows(
- "Interval year-to-month type should not be truncatable",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int, interval year to month): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary",
- () -> scalarSql("SELECT system.truncate(10, INTERVAL '100-00' YEAR TO MONTH)"));
-
- AssertHelpers.assertThrows(
- "Interval day-time type should not be truncatable",
- AnalysisException.class,
- "Function 'truncate' cannot process input: (int, interval day to second): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary",
- () -> scalarSql("SELECT system.truncate(10, CAST('11 23:4:0' AS INTERVAL DAY TO SECOND))"));
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.truncate(10, cast(12.3456 as float))"))
+ .as("FLoat type should not be truncatable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int, float): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary");
+
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.truncate(10, cast(12.3456 as double))"))
+ .as("Double type should not be truncatable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int, double): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.truncate(10, true)"))
+ .as("Boolean type should not be truncatable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int, boolean): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.truncate(10, map(1, 1))"))
+ .as("Map types should not be truncatable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int, map): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary");
+
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.truncate(10, array(1L))"))
+ .as("Array types should not be truncatable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int, array): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary");
+
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.truncate(10, INTERVAL '100-00' YEAR TO MONTH)"))
+ .as("Interval year-to-month type should not be truncatable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int, interval year to month): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary");
+
+ Assertions.assertThatThrownBy(
+ () ->
+ scalarSql(
+ "SELECT system.truncate(10, CAST('11 23:4:0' AS INTERVAL DAY TO SECOND))"))
+ .as("Interval day-time type should not be truncatable")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'truncate' cannot process input: (int, interval day to second): Expected truncation col to be tinyint, shortint, int, bigint, decimal, string, or binary");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkYearsFunction.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkYearsFunction.java
index d4676716a612..600b6ac0c1c5 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkYearsFunction.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestSparkYearsFunction.java
@@ -18,7 +18,6 @@
*/
package org.apache.iceberg.spark.sql;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.spark.SparkTestBaseWithCatalog;
import org.apache.iceberg.spark.functions.YearsFunction;
import org.apache.spark.sql.AnalysisException;
@@ -70,32 +69,32 @@ public void testTimestamps() {
@Test
public void testWrongNumberOfArguments() {
- AssertHelpers.assertThrows(
- "Function resolution should not work with zero arguments",
- AnalysisException.class,
- "Function 'years' cannot process input: (): Wrong number of inputs",
- () -> scalarSql("SELECT system.years()"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.years()"))
+ .as("Function resolution should not work with zero arguments")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining("Function 'years' cannot process input: (): Wrong number of inputs");
- AssertHelpers.assertThrows(
- "Function resolution should not work with more than one argument",
- AnalysisException.class,
- "Function 'years' cannot process input: (date, date): Wrong number of inputs",
- () -> scalarSql("SELECT system.years(date('1969-12-31'), date('1969-12-31'))"));
+ Assertions.assertThatThrownBy(
+ () -> scalarSql("SELECT system.years(date('1969-12-31'), date('1969-12-31'))"))
+ .as("Function resolution should not work with more than one argument")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'years' cannot process input: (date, date): Wrong number of inputs");
}
@Test
public void testInvalidInputTypes() {
- AssertHelpers.assertThrows(
- "Int type should not be coercible to date/timestamp",
- AnalysisException.class,
- "Function 'years' cannot process input: (int): Expected value to be date or timestamp",
- () -> scalarSql("SELECT system.years(1)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.years(1)"))
+ .as("Int type should not be coercible to date/timestamp")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'years' cannot process input: (int): Expected value to be date or timestamp");
- AssertHelpers.assertThrows(
- "Long type should not be coercible to date/timestamp",
- AnalysisException.class,
- "Function 'years' cannot process input: (bigint): Expected value to be date or timestamp",
- () -> scalarSql("SELECT system.years(1L)"));
+ Assertions.assertThatThrownBy(() -> scalarSql("SELECT system.years(1L)"))
+ .as("Long type should not be coercible to date/timestamp")
+ .isInstanceOf(AnalysisException.class)
+ .hasMessageContaining(
+ "Function 'years' cannot process input: (bigint): Expected value to be date or timestamp");
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestTimestampWithoutZone.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestTimestampWithoutZone.java
index 51b8d255a99b..5a8c5736a6b4 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestTimestampWithoutZone.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/TestTimestampWithoutZone.java
@@ -23,7 +23,6 @@
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.Schema;
import org.apache.iceberg.Table;
import org.apache.iceberg.catalog.TableIdentifier;
@@ -37,6 +36,7 @@
import org.apache.iceberg.types.Type;
import org.apache.iceberg.types.Types;
import org.apache.spark.sql.util.CaseInsensitiveStringMap;
+import org.assertj.core.api.Assertions;
import org.joda.time.DateTime;
import org.junit.After;
import org.junit.Assert;
@@ -95,14 +95,15 @@ public void removeTables() {
@Test
public void testWriteTimestampWithoutZoneError() {
- AssertHelpers.assertThrows(
- String.format(
- "Write operation performed on a timestamp without timezone field while "
- + "'%s' set to false should throw exception",
- SparkSQLProperties.HANDLE_TIMESTAMP_WITHOUT_TIMEZONE),
- IllegalArgumentException.class,
- SparkUtil.TIMESTAMP_WITHOUT_TIMEZONE_ERROR,
- () -> sql("INSERT INTO %s VALUES %s", tableName, rowToSqlValues(values)));
+ Assertions.assertThatThrownBy(
+ () -> sql("INSERT INTO %s VALUES %s", tableName, rowToSqlValues(values)))
+ .as(
+ String.format(
+ "Write operation performed on a timestamp without timezone field while "
+ + "'%s' set to false should throw exception",
+ SparkSQLProperties.HANDLE_TIMESTAMP_WITHOUT_TIMEZONE))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining(SparkUtil.TIMESTAMP_WITHOUT_TIMEZONE_ERROR);
}
@Test
diff --git a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/UnpartitionedWritesTestBase.java b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/UnpartitionedWritesTestBase.java
index 71089ebfd79e..813e442c6604 100644
--- a/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/UnpartitionedWritesTestBase.java
+++ b/spark/v3.3/spark/src/test/java/org/apache/iceberg/spark/sql/UnpartitionedWritesTestBase.java
@@ -20,7 +20,6 @@
import java.util.List;
import java.util.Map;
-import org.apache.iceberg.AssertHelpers;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.spark.SparkCatalogTestBase;
import org.apache.iceberg.spark.source.SimpleRecord;
@@ -28,6 +27,7 @@
import org.apache.spark.sql.Row;
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
import org.apache.spark.sql.functions;
+import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -97,11 +97,12 @@ public void testInsertAppendAtSnapshot() {
Assume.assumeTrue(tableName.equals(commitTarget()));
long snapshotId = validationCatalog.loadTable(tableIdent).currentSnapshot().snapshotId();
String prefix = "snapshot_id_";
- AssertHelpers.assertThrows(
- "Should not be able to insert into a table at a specific snapshot",
- IllegalArgumentException.class,
- "Cannot write to table at a specific snapshot",
- () -> sql("INSERT INTO %s.%s VALUES (4, 'd'), (5, 'e')", tableName, prefix + snapshotId));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql("INSERT INTO %s.%s VALUES (4, 'd'), (5, 'e')", tableName, prefix + snapshotId))
+ .as("Should not be able to insert into a table at a specific snapshot")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot write to table at a specific snapshot");
}
@Test
@@ -109,14 +110,14 @@ public void testInsertOverwriteAtSnapshot() {
Assume.assumeTrue(tableName.equals(commitTarget()));
long snapshotId = validationCatalog.loadTable(tableIdent).currentSnapshot().snapshotId();
String prefix = "snapshot_id_";
- AssertHelpers.assertThrows(
- "Should not be able to insert into a table at a specific snapshot",
- IllegalArgumentException.class,
- "Cannot write to table at a specific snapshot",
- () ->
- sql(
- "INSERT OVERWRITE %s.%s VALUES (4, 'd'), (5, 'e')",
- tableName, prefix + snapshotId));
+ Assertions.assertThatThrownBy(
+ () ->
+ sql(
+ "INSERT OVERWRITE %s.%s VALUES (4, 'd'), (5, 'e')",
+ tableName, prefix + snapshotId))
+ .as("Should not be able to insert into a table at a specific snapshot")
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessageContaining("Cannot write to table at a specific snapshot");
}
@Test