Skip to content

Commit 2f662ec

Browse files
committed
test(files): refactor tabular ingest size limit tests with parameterized approach #11639
Simplified and improved test structure by introducing nested classes, parameterized tests, and utility methods for TabularIngestSizeLimit configurations. Enhanced code readability and reusability.
1 parent 28d90a7 commit 2f662ec

File tree

1 file changed

+102
-178
lines changed

1 file changed

+102
-178
lines changed

src/test/java/edu/harvard/iq/dataverse/api/FilesIT.java

Lines changed: 102 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,22 @@
99
import io.restassured.RestAssured;
1010
import io.restassured.response.Response;
1111

12+
import java.nio.charset.StandardCharsets;
1213
import java.util.*;
1314
import java.util.logging.Logger;
1415

1516
import edu.harvard.iq.dataverse.api.auth.ApiKeyAuthMechanism;
1617
import jakarta.json.JsonObject;
18+
import jakarta.ws.rs.core.Response.Status;
1719
import org.assertj.core.util.Lists;
20+
import org.hamcrest.Matcher;
21+
import org.junit.jupiter.api.Nested;
1822
import org.junit.jupiter.api.Test;
1923
import org.junit.jupiter.api.BeforeAll;
2024
import io.restassured.path.json.JsonPath;
2125

2226
import static edu.harvard.iq.dataverse.api.ApiConstants.*;
27+
import static edu.harvard.iq.dataverse.settings.SettingsServiceBean.Key;
2328
import static io.restassured.path.json.JsonPath.with;
2429
import io.restassured.path.xml.XmlPath;
2530
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
@@ -45,6 +50,10 @@
4550
import org.hamcrest.CoreMatchers;
4651
import org.hamcrest.Matchers;
4752
import org.junit.jupiter.api.AfterAll;
53+
import org.junit.jupiter.api.io.TempDir;
54+
import org.junit.jupiter.params.ParameterizedTest;
55+
import org.junit.jupiter.params.provider.Arguments;
56+
import org.junit.jupiter.params.provider.MethodSource;
4857

4958
import static org.hamcrest.CoreMatchers.*;
5059
import static org.junit.jupiter.api.Assertions.*;
@@ -59,15 +68,11 @@ public static void setUpClass() {
5968

6069
Response removePublicInstall = UtilIT.deleteSetting(SettingsServiceBean.Key.PublicInstall);
6170
removePublicInstall.then().assertThat().statusCode(200);
62-
63-
Response removeLimit = UtilIT.deleteSetting(SettingsServiceBean.Key.TabularIngestSizeLimit);
64-
removeLimit.then().assertThat().statusCode(OK.getStatusCode());
6571
}
6672

6773
@AfterAll
6874
public static void tearDownClass() {
6975
UtilIT.deleteSetting(SettingsServiceBean.Key.PublicInstall);
70-
UtilIT.deleteSetting(SettingsServiceBean.Key.TabularIngestSizeLimit);
7176
}
7277

7378
/**
@@ -1211,183 +1216,102 @@ public void test_AddFileBadUploadFormat() {
12111216
}
12121217

12131218
}
1214-
1215-
@Test
1216-
public void testIngestSizeLimits() throws InterruptedException, IOException {
1217-
Response createUser = UtilIT.createRandomUser();
1218-
createUser.then().assertThat().statusCode(OK.getStatusCode());
1219-
String username = UtilIT.getUsernameFromResponse(createUser);
1220-
String apiToken = UtilIT.getApiTokenFromResponse(createUser);
1221-
Response makeSuperUser = UtilIT.setSuperuserStatus(username, true);
1222-
makeSuperUser.then().assertThat().statusCode(OK.getStatusCode());
1223-
1224-
Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
1225-
createDataverseResponse.prettyPrint();
1226-
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
1227-
Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken);
1228-
createDatasetResponse.prettyPrint();
1229-
Integer datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id");
1230-
1231-
String tinyCsvOnly = """
1232-
{
1233-
"csv": "50"
1234-
}
1235-
""";
1236-
1237-
Response setLimit = UtilIT.setSetting(SettingsServiceBean.Key.TabularIngestSizeLimit, tinyCsvOnly);
1238-
setLimit.then().assertThat().statusCode(OK.getStatusCode());
1239-
1240-
Path pathToDataFile = Paths.get(java.nio.file.Files.createTempDirectory(null) + File.separator + "data.csv");
1241-
String contentOfCsv = ""
1242-
+ "name,pounds,species,treats\n"
1243-
+ "Midnight,15,dog,milkbones\n"
1244-
+ "Tiger,17,cat,cat grass\n"
1245-
+ "Panther,21,cat,cat nip\n";
1246-
java.nio.file.Files.write(pathToDataFile, contentOfCsv.getBytes());
1247-
1248-
Response uploadFile = UtilIT.uploadFileViaNative(datasetId.toString(), pathToDataFile.toString(), apiToken);
1249-
uploadFile.prettyPrint();
1250-
uploadFile.then().assertThat()
1251-
.statusCode(OK.getStatusCode())
1252-
.body("data.files[0].label", equalTo("data.csv"));
1253-
1254-
String fileId1 = JsonPath.from(uploadFile.body().asString()).getString("data.files[0].dataFile.id");
1255-
1256-
Response getTabularFails = UtilIT.getFileDataTables(fileId1, apiToken);
1257-
getTabularFails.prettyPrint();
1258-
getTabularFails.then().assertThat()
1259-
.statusCode(BAD_REQUEST.getStatusCode())
1260-
.body("message", equalTo(BundleUtil.getStringFromBundle("files.api.only.tabular.supported")));
1261-
1262-
String largerCsv = """
1263-
{
1264-
"csv": "123456"
1265-
}
1266-
""";
1267-
1268-
setLimit = UtilIT.setSetting(SettingsServiceBean.Key.TabularIngestSizeLimit, largerCsv);
1269-
setLimit.then().assertThat().statusCode(OK.getStatusCode());
1270-
1271-
uploadFile = UtilIT.uploadFileViaNative(datasetId.toString(), pathToDataFile.toString(), apiToken);
1272-
uploadFile.prettyPrint();
1273-
uploadFile.then().assertThat()
1274-
.statusCode(OK.getStatusCode())
1275-
.body("data.files[0].label", equalTo("data-1.csv"));
1276-
1277-
assertTrue(UtilIT.sleepForLock(datasetId.longValue(), "Ingest", apiToken, UtilIT.MAXIMUM_INGEST_LOCK_DURATION), "Failed test if Ingest Lock exceeds max duration " + pathToDataFile);
1278-
1279-
String fileId2 = JsonPath.from(uploadFile.body().asString()).getString("data.files[0].dataFile.id");
1280-
1281-
Response getTabularWorks = UtilIT.getFileDataTables(fileId2, apiToken);
1282-
getTabularWorks.prettyPrint();
1283-
getTabularWorks.then().assertThat()
1284-
.statusCode(OK.getStatusCode())
1285-
.body("data[0].varQuantity", equalTo(4));
1286-
1287-
String tinyDefaultSize = """
1288-
{
1289-
"default": "50"
1290-
}
1291-
""";
1292-
1293-
setLimit = UtilIT.setSetting(SettingsServiceBean.Key.TabularIngestSizeLimit, tinyDefaultSize);
1294-
setLimit.then().assertThat().statusCode(OK.getStatusCode());
1295-
1296-
uploadFile = UtilIT.uploadFileViaNative(datasetId.toString(), pathToDataFile.toString(), apiToken);
1297-
uploadFile.prettyPrint();
1298-
uploadFile.then().assertThat()
1299-
.statusCode(OK.getStatusCode())
1300-
.body("data.files[0].label", equalTo("data-2.csv"));
1301-
1302-
String fileId3 = JsonPath.from(uploadFile.body().asString()).getString("data.files[0].dataFile.id");
1303-
1304-
getTabularFails = UtilIT.getFileDataTables(fileId3, apiToken);
1305-
getTabularFails.prettyPrint();
1306-
getTabularFails.then().assertThat()
1307-
.statusCode(BAD_REQUEST.getStatusCode())
1308-
.body("message", equalTo(BundleUtil.getStringFromBundle("files.api.only.tabular.supported")));
1309-
1310-
// The behavior of `"default": "-2"` is not documented in the guides
1311-
// but it acts like `"default": "0"` which disables ingest.
1312-
String unexpectedNegativeDefault = """
1313-
{
1314-
"default": "-2"
1315-
}
1316-
""";
1317-
1318-
setLimit = UtilIT.setSetting(SettingsServiceBean.Key.TabularIngestSizeLimit, unexpectedNegativeDefault);
1319-
setLimit.then().assertThat().statusCode(OK.getStatusCode());
1320-
1321-
uploadFile = UtilIT.uploadFileViaNative(datasetId.toString(), pathToDataFile.toString(), apiToken);
1322-
uploadFile.prettyPrint();
1323-
uploadFile.then().assertThat()
1324-
.statusCode(OK.getStatusCode())
1325-
.body("data.files[0].label", equalTo("data-3.csv"));
1326-
1327-
String fileId4 = JsonPath.from(uploadFile.body().asString()).getString("data.files[0].dataFile.id");
1328-
1329-
getTabularFails = UtilIT.getFileDataTables(fileId4, apiToken);
1330-
getTabularFails.prettyPrint();
1331-
getTabularFails.then().assertThat()
1332-
.statusCode(BAD_REQUEST.getStatusCode())
1333-
.body("message", equalTo(BundleUtil.getStringFromBundle("files.api.only.tabular.supported")));
1334-
1335-
// As the guides say, you MUST provide a string, not a JSON number.
1336-
// That is, `"123"` in quotes rather than `123` with no quotes.
1337-
// If you provide a number (no quotes) rather than a string,
1338-
// all ingest will be disabled and you'll see an error in server.log
1339-
// about how the system is misconfigured.
1340-
String invalidNonString = """
1341-
{
1342-
"default": 987654321
1343-
}
1344-
""";
1345-
1346-
setLimit = UtilIT.setSetting(SettingsServiceBean.Key.TabularIngestSizeLimit, invalidNonString);
1347-
setLimit.then().assertThat().statusCode(OK.getStatusCode());
1348-
1349-
uploadFile = UtilIT.uploadFileViaNative(datasetId.toString(), pathToDataFile.toString(), apiToken);
1350-
uploadFile.prettyPrint();
1351-
uploadFile.then().assertThat()
1352-
.statusCode(OK.getStatusCode())
1353-
.body("data.files[0].label", equalTo("data-4.csv"));
1354-
1355-
String fileId5 = JsonPath.from(uploadFile.body().asString()).getString("data.files[0].dataFile.id");
1356-
1357-
getTabularFails = UtilIT.getFileDataTables(fileId5, apiToken);
1358-
getTabularFails.prettyPrint();
1359-
getTabularFails.then().assertThat()
1360-
.statusCode(BAD_REQUEST.getStatusCode())
1361-
.body("message", equalTo(BundleUtil.getStringFromBundle("files.api.only.tabular.supported")));
1362-
1363-
String defaultDisabledAndLargeCsvLimit = """
1364-
{
1365-
"default": "0",
1366-
"csv": "123456"
1367-
}
1368-
""";
1369-
1370-
setLimit = UtilIT.setSetting(SettingsServiceBean.Key.TabularIngestSizeLimit, defaultDisabledAndLargeCsvLimit);
1371-
setLimit.then().assertThat().statusCode(OK.getStatusCode());
1372-
1373-
uploadFile = UtilIT.uploadFileViaNative(datasetId.toString(), pathToDataFile.toString(), apiToken);
1374-
uploadFile.prettyPrint();
1375-
uploadFile.then().assertThat()
1376-
.statusCode(OK.getStatusCode())
1377-
.body("data.files[0].label", equalTo("data-5.csv"));
1378-
1379-
String fileId6 = JsonPath.from(uploadFile.body().asString()).getString("data.files[0].dataFile.id");
1380-
1381-
getTabularWorks = UtilIT.getFileDataTables(fileId2, apiToken);
1382-
getTabularWorks.prettyPrint();
1383-
getTabularWorks.then().assertThat()
1219+
1220+
@Nested
1221+
class IngestSizeLimits {
1222+
1223+
static String apiToken;
1224+
static int datasetId;
1225+
@TempDir
1226+
static Path tempDir;
1227+
static String csvFileName = "data.csv";
1228+
static Path csvFile;
1229+
static final String csvData =
1230+
"""
1231+
name,pounds,species,treats
1232+
Midnight,15,dog,milkbones
1233+
Tiger,17,cat,cat grass
1234+
Panther,21,cat,cat nip
1235+
""";
1236+
1237+
@BeforeAll
1238+
static void setup() throws IOException {
1239+
// Create random user, collection and dataset to work with
1240+
Response createUser = UtilIT.createRandomUser();
1241+
createUser.then().assertThat().statusCode(OK.getStatusCode());
1242+
String username = UtilIT.getUsernameFromResponse(createUser);
1243+
apiToken = UtilIT.getApiTokenFromResponse(createUser);
1244+
Response makeSuperUser = UtilIT.setSuperuserStatus(username, true);
1245+
makeSuperUser.then().assertThat().statusCode(OK.getStatusCode());
1246+
1247+
Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken);
1248+
createDataverseResponse.prettyPrint();
1249+
String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse);
1250+
Response createDatasetResponse = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken);
1251+
createDatasetResponse.prettyPrint();
1252+
datasetId = JsonPath.from(createDatasetResponse.body().asString()).getInt("data.id");
1253+
1254+
// Create CSV datafile to work with
1255+
csvFile = tempDir.resolve(csvFileName);
1256+
java.nio.file.Files.writeString(csvFile, csvData, StandardCharsets.UTF_8);
1257+
}
1258+
1259+
@AfterAll
1260+
static void teardown() {
1261+
// Remove the setting for test isolation purposes
1262+
Response removeLimit = UtilIT.deleteSetting(Key.TabularIngestSizeLimit);
1263+
removeLimit.then().assertThat().statusCode(OK.getStatusCode());
1264+
}
1265+
1266+
static List<Arguments> configurations() {
1267+
return List.of(
1268+
// Too small for 134 chars
1269+
Arguments.of("{\"csv\": 50}", BAD_REQUEST, "message", equalTo(BundleUtil.getStringFromBundle("files.api.only.tabular.supported"))),
1270+
Arguments.of("{\"default\": 50.0}", BAD_REQUEST, "message", equalTo(BundleUtil.getStringFromBundle("files.api.only.tabular.supported"))),
1271+
1272+
// The behavior of `"default": "-2"` is not documented in the guides
1273+
// but it acts like `"default": "0"` which disables ingest.
1274+
Arguments.of("{\"default\": -2}", BAD_REQUEST, "message", equalTo(BundleUtil.getStringFromBundle("files.api.only.tabular.supported"))),
1275+
1276+
// Large enough :-)
1277+
Arguments.of("{\"csv\": 123456}", OK, "data[0].varQuantity", equalTo(4)),
1278+
// Default is disabled, but exception for CSV
1279+
Arguments.of("{\"default\": 0,\"csv\": 123456}", OK, "data[0].varQuantity", equalTo(4))
1280+
);
1281+
}
1282+
1283+
@ParameterizedTest
1284+
@MethodSource("configurations")
1285+
void testIngestSizeLimits(String ingestSizeLimitConfig, Status expectedStatus, String jsonPath, Matcher matcher) throws IOException {
1286+
// given
1287+
Response setLimit = UtilIT.setSetting(Key.TabularIngestSizeLimit, ingestSizeLimitConfig);
1288+
setLimit.then().assertThat().statusCode(OK.getStatusCode());
1289+
1290+
// when
1291+
Response uploadResponse = UtilIT.uploadFileViaNative(Integer.toString(datasetId), csvFile.toString(), apiToken);
1292+
//uploadResponse.prettyPrint();
1293+
uploadResponse.then().assertThat()
13841294
.statusCode(OK.getStatusCode())
1385-
.body("data[0].varQuantity", equalTo(4));
1386-
1387-
Response removeLimit = UtilIT.deleteSetting(SettingsServiceBean.Key.TabularIngestSizeLimit);
1388-
removeLimit.then().assertThat().statusCode(OK.getStatusCode());
1295+
.body("data.files[0].label", equalTo(csvFileName));
1296+
String fileId = JsonPath.from(uploadResponse.body().asString()).getString("data.files[0].dataFile.id");
1297+
1298+
// Wait for ingest to complete
1299+
assertTrue(UtilIT.sleepForLock(datasetId, "Ingest", apiToken, UtilIT.MAXIMUM_INGEST_LOCK_DURATION),
1300+
"Failed test if Ingest Lock exceeds max duration");
1301+
1302+
// then
1303+
Response getTabularFails = UtilIT.getFileDataTables(fileId, apiToken);
1304+
//getTabularFails.prettyPrint();
1305+
getTabularFails.then().assertThat()
1306+
.statusCode(expectedStatus.getStatusCode())
1307+
.body(jsonPath, matcher);
1308+
1309+
// delete the file for the next test
1310+
UtilIT.deleteFile(Integer.valueOf(fileId), apiToken);
1311+
}
13891312
}
13901313

1314+
13911315
@Test
13921316
public void testUningestFileViaApi() throws InterruptedException {
13931317
Response createUser = UtilIT.createRandomUser();

0 commit comments

Comments
 (0)