diff --git a/src/org/labkey/test/tests/ClientAPITest.java b/src/org/labkey/test/tests/ClientAPITest.java index a9b4549d91..3a6ceea1d1 100644 --- a/src/org/labkey/test/tests/ClientAPITest.java +++ b/src/org/labkey/test/tests/ClientAPITest.java @@ -57,6 +57,7 @@ import org.labkey.test.util.PermissionsHelper; import org.labkey.test.util.PortalHelper; import org.labkey.test.util.StudyHelper; +import org.labkey.test.util.TestDataGenerator; import org.labkey.test.util.data.TestDataUtils; import org.labkey.test.util.UIUserHelper; import org.labkey.test.util.WikiHelper; @@ -77,9 +78,12 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.labkey.test.WebTestHelper.getHttpResponse; import static org.labkey.test.params.FieldDefinition.DOMAIN_TRICKY_CHARACTERS; @@ -93,8 +97,10 @@ public class ClientAPITest extends BaseWebDriverTest private static final String PROJECT_NAME = "ClientAPITestProject"; private static final String OTHER_PROJECT = "OtherClientAPITestProject"; // for cross-project query test - protected static final String FOLDER_NAME = "api folder"; + protected static final String API_FOLDER_NAME = "api folder"; + private static final String API_FOLDER_PATH = PROJECT_NAME + "/" + API_FOLDER_NAME; private static final String SUBFOLDER_NAME = "subfolder"; + private static final String SUBFOLDER_PATH = API_FOLDER_PATH + "/" + SUBFOLDER_NAME; private static final String TIME_STUDY_FOLDER = "timeStudyFolder"; private static final String TIME_STUDY_NAME = "timeStudyName"; private static final String VISIT_STUDY_FOLDER = "visitStudyFolder"; @@ -129,10 +135,6 @@ public class ClientAPITest extends BaseWebDriverTest public static final String TEST_DIV_NAME = "testDiv"; - private static final String GRIDTEST_GRIDTITLE = "ClientAPITest Grid Title"; - - private static final int PAGE_SIZE = 4; - public static final String SRC_PREFIX = "Loading XSS")); } + @Test // Issue 53699 + public void testLargeMultibytePayload() + { + for (int i = 0; i < 10; i++) + { + // Arrange + int characterCount = 5_000; + // We had problems fetching the JSON content server-side due to Tomcat's InputBuffer not dealing with + // characters that span multiple "pages" of the byte buffer. Test with different numbers of single-byte + // UTF-8 characters before the 4-byte characters to ensure we get different boundary conditions + String tooManyMultibyteCharacters = "a".repeat(i) + "\uD83D\uDC7E".repeat(characterCount); + + TestDataGenerator dataGenerator = new TestDataGenerator("lists", LIST_NAME, API_FOLDER_PATH) + .addCustomRow(Map.of("FirstName", tooManyMultibyteCharacters, "LastName", "Chaplin", "Age", 42)); + + // Act + // Prior to fix for Issue 53699 this would throw a BufferUnderflowException when processing the JSON payload + Exception exception = assertThrows(Exception.class, dataGenerator::insertRows); + + // Assert + // Prior to fix length validation incorrectly checked for string length rather than character code point length + String expectedPrefix = "Value is too long for column 'FirstName', a maximum length of 4000 is allowed."; + String expectedSuffix = String.format("was %d characters long.", characterCount + i); + + assertThat(exception.getMessage(), startsWith(expectedPrefix)); + assertThat(exception.getMessage(), endsWith(expectedSuffix)); + } + } + @Override public BrowserType bestBrowser() {