Skip to content

Commit 463682f

Browse files
authored
Refactor IcebergCatalog to isolate internal state (#1659)
Following up on #1694 * Restore `private` scope on internal fields in `IcebergCatalog` * Use a test-only setter instead of sub-classing to manage injecting test FileIO implementations
1 parent c969812 commit 463682f

File tree

2 files changed

+19
-82
lines changed

2 files changed

+19
-82
lines changed

quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java

Lines changed: 10 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@
9999
import org.apache.polaris.core.persistence.dao.entity.EntityResult;
100100
import org.apache.polaris.core.persistence.dao.entity.PrincipalSecretsResult;
101101
import org.apache.polaris.core.persistence.pagination.PageToken;
102-
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCatalogView;
103102
import org.apache.polaris.core.persistence.transactional.TransactionalPersistence;
104103
import org.apache.polaris.core.secrets.UserSecretsManager;
105104
import org.apache.polaris.core.secrets.UserSecretsManagerFactory;
@@ -221,50 +220,12 @@ public Map<String, String> getConfigOverrides() {
221220
private PolarisAdminService adminService;
222221
private PolarisEntityManager entityManager;
223222
private FileIOFactory fileIOFactory;
223+
private InMemoryFileIO fileIO;
224224
private PolarisEntity catalogEntity;
225225
private SecurityContext securityContext;
226226
private TestPolarisEventListener testPolarisEventListener;
227227
private ReservedProperties reservedProperties;
228228

229-
/**
230-
* A subclass of IcebergCatalog that adds FileIO management capabilities. This allows the file IO
231-
* logic to be encapsulated in a dedicated class.
232-
*/
233-
public static class IcebergFileIOCatalog extends IcebergCatalog {
234-
235-
public IcebergFileIOCatalog(
236-
PolarisEntityManager entityManager,
237-
PolarisMetaStoreManager metaStoreManager,
238-
CallContext callContext,
239-
PolarisResolutionManifestCatalogView resolvedEntityView,
240-
SecurityContext securityContext,
241-
TaskExecutor taskExecutor,
242-
FileIOFactory fileIOFactory,
243-
PolarisEventListener polarisEventListener) {
244-
super(
245-
entityManager,
246-
metaStoreManager,
247-
callContext,
248-
resolvedEntityView,
249-
securityContext,
250-
taskExecutor,
251-
fileIOFactory,
252-
polarisEventListener);
253-
}
254-
255-
@Override
256-
public synchronized FileIO getIo() {
257-
if (catalogFileIO == null) {
258-
catalogFileIO = loadFileIO(ioImplClassName, tableDefaultProperties);
259-
if (closeableGroup != null) {
260-
closeableGroup.addCloseable(catalogFileIO);
261-
}
262-
}
263-
264-
return catalogFileIO;
265-
}
266-
}
267-
268229
@BeforeAll
269230
public static void setUpMocks() {
270231
PolarisStorageIntegrationProviderImpl mock =
@@ -410,7 +371,7 @@ protected IcebergCatalog initCatalog(
410371
callContext, entityManager, securityContext, CATALOG_NAME);
411372
TaskExecutor taskExecutor = Mockito.mock();
412373
IcebergCatalog icebergCatalog =
413-
new IcebergFileIOCatalog(
374+
new IcebergCatalog(
414375
entityManager,
415376
metaStoreManager,
416377
callContext,
@@ -419,6 +380,8 @@ protected IcebergCatalog initCatalog(
419380
taskExecutor,
420381
fileIOFactory,
421382
polarisEventListener);
383+
fileIO = new InMemoryFileIO();
384+
icebergCatalog.setCatalogFileIo(fileIO);
422385
ImmutableMap.Builder<String, String> propertiesBuilder =
423386
ImmutableMap.<String, String>builder()
424387
.put(CatalogProperties.FILE_IO_IMPL, "org.apache.iceberg.inmemory.InMemoryFileIO")
@@ -630,7 +593,6 @@ public void testValidateNotificationWhenTableAndNamespacesDontExist() {
630593

631594
// Now also check that despite creating the metadata file, the validation call still doesn't
632595
// create any namespaces or tables.
633-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
634596
fileIO.addFile(
635597
tableMetadataLocation,
636598
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -766,8 +728,6 @@ public void testUpdateNotificationWhenTableAndNamespacesDontExist() {
766728
update.setTimestamp(230950845L);
767729
request.setPayload(update);
768730

769-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
770-
771731
fileIO.addFile(
772732
tableMetadataLocation,
773733
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -810,8 +770,6 @@ public void testUpdateNotificationCreateTableInDisallowedLocation() {
810770
update.setTimestamp(230950845L);
811771
request.setPayload(update);
812772

813-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
814-
815773
fileIO.addFile(
816774
tableMetadataLocation,
817775
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -859,7 +817,7 @@ public void testCreateNotificationCreateTableInExternalLocation() {
859817
.addPartitionSpec(PartitionSpec.unpartitioned())
860818
.addSortOrder(SortOrder.unsorted())
861819
.build();
862-
TableMetadataParser.write(tableMetadata, catalog.getIo().newOutputFile(tableMetadataLocation));
820+
TableMetadataParser.write(tableMetadata, fileIO.newOutputFile(tableMetadataLocation));
863821

864822
Namespace namespace = Namespace.of("parent", "child1");
865823
TableIdentifier table = TableIdentifier.of(namespace, "my_table");
@@ -919,7 +877,7 @@ public void testCreateNotificationCreateTableOutsideOfMetadataLocation() {
919877
.addPartitionSpec(PartitionSpec.unpartitioned())
920878
.addSortOrder(SortOrder.unsorted())
921879
.build();
922-
TableMetadataParser.write(tableMetadata, catalog.getIo().newOutputFile(tableMetadataLocation));
880+
TableMetadataParser.write(tableMetadata, fileIO.newOutputFile(tableMetadataLocation));
923881

924882
Namespace namespace = Namespace.of("parent", "child1");
925883
TableIdentifier table = TableIdentifier.of(namespace, "my_table");
@@ -968,7 +926,6 @@ public void testUpdateNotificationCreateTableInExternalLocation() {
968926
FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), "true")
969927
.build());
970928
IcebergCatalog catalog = catalog();
971-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
972929

973930
fileIO.addFile(
974931
tableMetadataLocation,
@@ -999,7 +956,7 @@ public void testUpdateNotificationCreateTableInExternalLocation() {
999956
.addPartitionSpec(PartitionSpec.unpartitioned())
1000957
.addSortOrder(SortOrder.unsorted())
1001958
.build();
1002-
TableMetadataParser.write(tableMetadata, catalog.getIo().newOutputFile(maliciousMetadataFile));
959+
TableMetadataParser.write(tableMetadata, fileIO.newOutputFile(maliciousMetadataFile));
1003960

1004961
NotificationRequest updateRequest = new NotificationRequest();
1005962
updateRequest.setNotificationType(NotificationType.UPDATE);
@@ -1042,7 +999,7 @@ public void testUpdateNotificationCreateTableWithLocalFilePrefix() {
1042999
callContext, entityManager, securityContext, catalogWithoutStorage);
10431000
TaskExecutor taskExecutor = Mockito.mock();
10441001
IcebergCatalog catalog =
1045-
new IcebergFileIOCatalog(
1002+
new IcebergCatalog(
10461003
entityManager,
10471004
metaStoreManager,
10481005
callContext,
@@ -1068,8 +1025,6 @@ public void testUpdateNotificationCreateTableWithLocalFilePrefix() {
10681025
update.setTimestamp(230950845L);
10691026
request.setPayload(update);
10701027

1071-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1072-
10731028
fileIO.addFile(
10741029
metadataLocation,
10751030
TableMetadataParser.toJson(createSampleTableMetadata(metadataLocation)).getBytes(UTF_8));
@@ -1108,8 +1063,9 @@ public void testUpdateNotificationCreateTableWithHttpPrefix() {
11081063
new PolarisPassthroughResolutionView(
11091064
callContext, entityManager, securityContext, catalogName);
11101065
TaskExecutor taskExecutor = Mockito.mock();
1066+
InMemoryFileIO localFileIO = new InMemoryFileIO();
11111067
IcebergCatalog catalog =
1112-
new IcebergFileIOCatalog(
1068+
new IcebergCatalog(
11131069
entityManager,
11141070
metaStoreManager,
11151071
callContext,
@@ -1126,8 +1082,6 @@ public void testUpdateNotificationCreateTableWithHttpPrefix() {
11261082
Namespace namespace = Namespace.of("parent", "child1");
11271083
TableIdentifier table = TableIdentifier.of(namespace, "table");
11281084

1129-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1130-
11311085
// The location of the metadata JSON file specified in the create will be forbidden.
11321086
final String metadataLocation = "http://maliciousdomain.com/metadata.json";
11331087
NotificationRequest request = new NotificationRequest();
@@ -1204,8 +1158,6 @@ public void testUpdateNotificationWhenNamespacesExist() {
12041158
update.setTimestamp(230950845L);
12051159
request.setPayload(update);
12061160

1207-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1208-
12091161
fileIO.addFile(
12101162
tableMetadataLocation,
12111163
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -1256,8 +1208,6 @@ public void testUpdateNotificationWhenTableExists() {
12561208
update.setTimestamp(230950845L);
12571209
request.setPayload(update);
12581210

1259-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1260-
12611211
fileIO.addFile(
12621212
tableMetadataLocation,
12631213
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -1309,8 +1259,6 @@ public void testUpdateNotificationWhenTableExistsInDisallowedLocation() {
13091259
update.setTimestamp(230950845L);
13101260
request.setPayload(update);
13111261

1312-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1313-
13141262
fileIO.addFile(
13151263
tableMetadataLocation,
13161264
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -1347,8 +1295,6 @@ public void testUpdateNotificationRejectOutOfOrderTimestamp() {
13471295
update.setTimestamp(timestamp);
13481296
request.setPayload(update);
13491297

1350-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1351-
13521298
fileIO.addFile(
13531299
tableMetadataLocation,
13541300
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -1420,8 +1366,6 @@ public void testUpdateNotificationWhenTableExistsFileSpecifiesDisallowedLocation
14201366
update.setTimestamp(230950845L);
14211367
request.setPayload(update);
14221368

1423-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1424-
14251369
// Though the metadata JSON file itself is in an allowed location, make it internally specify
14261370
// a forbidden table location.
14271371
TableMetadata forbiddenMetadata =
@@ -1498,8 +1442,6 @@ public void testDropNotificationWhenNamespacesExist() {
14981442
update.setTimestamp(230950845L);
14991443
request.setPayload(update);
15001444

1501-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1502-
15031445
fileIO.addFile(
15041446
tableMetadataLocation,
15051447
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -1550,8 +1492,6 @@ public void testDropNotificationWhenTableExists() {
15501492
update.setTimestamp(230950845L);
15511493
request.setPayload(update);
15521494

1553-
InMemoryFileIO fileIO = getInMemoryIo(catalog);
1554-
15551495
fileIO.addFile(
15561496
tableMetadataLocation,
15571497
TableMetadataParser.toJson(createSampleTableMetadata(tableLocation)).getBytes(UTF_8));
@@ -2069,8 +2009,4 @@ public void testEventsAreEmitted() {
20692009
Assertions.assertThat(afterTableEvent.base().properties().get(key)).isEqualTo(valOld);
20702010
Assertions.assertThat(afterTableEvent.metadata().properties().get(key)).isEqualTo(valNew);
20712011
}
2072-
2073-
private static InMemoryFileIO getInMemoryIo(IcebergCatalog catalog) {
2074-
return (InMemoryFileIO) ((ExceptionMappingFileIO) catalog.getIo()).getInnerIo();
2075-
}
20762012
}

service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,10 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
169169
private final SecurityContext securityContext;
170170
private final PolarisEventListener polarisEventListener;
171171

172-
protected String ioImplClassName;
173-
protected FileIO catalogFileIO;
174-
protected CloseableGroup closeableGroup;
175-
protected Map<String, String> tableDefaultProperties;
172+
private String ioImplClassName;
173+
private FileIO catalogFileIO;
174+
private CloseableGroup closeableGroup;
175+
private Map<String, String> tableDefaultProperties;
176176

177177
private final String catalogName;
178178
private long catalogId = -1;
@@ -218,8 +218,8 @@ public String name() {
218218
}
219219

220220
@VisibleForTesting
221-
public FileIO getIo() {
222-
return catalogFileIO;
221+
public void setCatalogFileIo(FileIO fileIO) {
222+
catalogFileIO = fileIO;
223223
}
224224

225225
@Override
@@ -339,7 +339,8 @@ public ViewBuilder buildView(TableIdentifier identifier) {
339339
@VisibleForTesting
340340
public TableOperations newTableOps(
341341
TableIdentifier tableIdentifier, boolean makeMetadataCurrentOnCommit) {
342-
return new BasePolarisTableOperations(getIo(), tableIdentifier, makeMetadataCurrentOnCommit);
342+
return new BasePolarisTableOperations(
343+
catalogFileIO, tableIdentifier, makeMetadataCurrentOnCommit);
343344
}
344345

345346
@Override
@@ -844,7 +845,7 @@ private Page<TableIdentifier> listViews(Namespace namespace, PageToken pageToken
844845
@VisibleForTesting
845846
@Override
846847
protected ViewOperations newViewOps(TableIdentifier identifier) {
847-
return new BasePolarisViewOperations(getIo(), identifier);
848+
return new BasePolarisViewOperations(catalogFileIO, identifier);
848849
}
849850

850851
@Override

0 commit comments

Comments
 (0)