diff --git a/src/org/labkey/remoteapi/SimpleFormCommand.java b/src/org/labkey/remoteapi/SimpleFormCommand.java index c06c1cd47e..8966a6a54e 100644 --- a/src/org/labkey/remoteapi/SimpleFormCommand.java +++ b/src/org/labkey/remoteapi/SimpleFormCommand.java @@ -27,7 +27,7 @@ import java.util.List; import java.util.Map; -public class SimpleFormCommand extends Command +public class SimpleFormCommand extends Command { private final Map _formData; diff --git a/src/org/labkey/remoteapi/query/ImportExperimentDataCommand.java b/src/org/labkey/remoteapi/query/ImportExperimentDataCommand.java index 84a34f0d30..cfa4e268da 100644 --- a/src/org/labkey/remoteapi/query/ImportExperimentDataCommand.java +++ b/src/org/labkey/remoteapi/query/ImportExperimentDataCommand.java @@ -28,7 +28,8 @@ public class ImportExperimentDataCommand extends ImportDataCommand { private AuditLogHelper.AuditBehaviorType _auditBehavior; private Boolean _crossTypeImport; - private String _containerPath; + + private final String _containerPath; public ImportExperimentDataCommand(String schemaName, String queryName, String containerPath) { @@ -76,5 +77,4 @@ protected HttpPost createRequest(URI uri) { } return post; } - } diff --git a/src/org/labkey/test/stress/ApiTestCommand.java b/src/org/labkey/test/stress/ApiTestCommand.java index 20a9e7655f..baba2c5225 100644 --- a/src/org/labkey/test/stress/ApiTestCommand.java +++ b/src/org/labkey/test/stress/ApiTestCommand.java @@ -34,7 +34,7 @@ import java.io.Reader; import java.net.URI; -class ApiTestCommand extends Command +class ApiTestCommand extends Command { private final String _url; private final String _type; diff --git a/src/org/labkey/test/tests/ClientAPITest.java b/src/org/labkey/test/tests/ClientAPITest.java index 128d39c435..a04a151032 100644 --- a/src/org/labkey/test/tests/ClientAPITest.java +++ b/src/org/labkey/test/tests/ClientAPITest.java @@ -17,7 +17,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; -import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpUriRequest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.json.JSONObject; @@ -58,9 +58,9 @@ 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; +import org.labkey.test.util.data.TestDataUtils; import org.labkey.test.util.query.QueryUtils; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.TimeoutException; @@ -1481,9 +1481,9 @@ private void runCommand(Connection cn, SimpleGetCommand source, String requestCo SimpleGetCommand cmd = new SimpleGetCommand(source.getControllerName(), source.getActionName()) { @Override - protected HttpGet getHttpRequest(Connection connection, String folderPath) throws URISyntaxException + protected HttpUriRequest getHttpRequest(Connection connection, String folderPath) throws URISyntaxException { - HttpGet request = super.getHttpRequest(connection, folderPath); + HttpUriRequest request = super.getHttpRequest(connection, folderPath); request.setHeader("Content-Type", requestContentType); return request; diff --git a/src/org/labkey/test/tests/JavaClientApiTest.java b/src/org/labkey/test/tests/JavaClientApiTest.java index 672c12d3ee..e8dc77d363 100644 --- a/src/org/labkey/test/tests/JavaClientApiTest.java +++ b/src/org/labkey/test/tests/JavaClientApiTest.java @@ -31,7 +31,9 @@ import org.labkey.remoteapi.domain.GetDomainDetailsCommand; import org.labkey.remoteapi.domain.PropertyDescriptor; import org.labkey.remoteapi.domain.SaveDomainCommand; +import org.labkey.remoteapi.query.BaseQueryCommand; import org.labkey.remoteapi.query.DeleteRowsCommand; +import org.labkey.remoteapi.query.ExecuteSqlCommand; import org.labkey.remoteapi.query.Filter; import org.labkey.remoteapi.query.InsertRowsCommand; import org.labkey.remoteapi.query.SaveRowsResponse; @@ -70,6 +72,7 @@ import org.labkey.test.util.PermissionsHelper.PrincipalType; import org.labkey.test.util.PortalHelper; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -570,7 +573,7 @@ public void testImpersonateUser() throws Exception // stop impersonation StopImpersonatingCommand stopCmd = new StopImpersonatingCommand(); CommandResponse stopResp = stopCmd.execute(cn, PROJECT_NAME); - assertEquals(302, stopResp.getStatusCode()); + assertEquals(200, stopResp.getStatusCode()); // check whoami who = new WhoAmICommand().execute(cn, PROJECT_NAME); @@ -608,6 +611,7 @@ public void testImpersonationConnection() throws Exception cn.stopImpersonating(); } + // Also tests SelectRowCommand and ExecuteSqlCommand @Test public void testSaveRowsApiCommand() throws Exception { @@ -741,18 +745,7 @@ public void testSaveRowsApiCommand() throws Exception // Verify players list after operations { var selectRowsCommand = new SelectRowsCommand(schemaName, playersListName); - selectRowsCommand.addSort(new Sort("JerseyNumber", Sort.Direction.ASCENDING)); - - var resp = selectRowsCommand.execute(conn, PROJECT_NAME); - assertEquals(3, resp.getRowCount()); - - var players = resp.getRows(); - assertEquals(19, players.get(0).get("jerseyNumber")); // verify case-insensitive - assertEquals("Seattle Mariners", players.get(0).get("Team")); - assertEquals(24, players.get(1).get("Jerseynumber")); // verify case-insensitive - assertEquals("Seattle Mariners", players.get(1).get("Team")); - assertEquals(44, players.get(2).get("JerseyNumber")); - assertEquals("New York Yankees", players.get(2).get("Team")); + verifyJerseys(conn, selectRowsCommand, 3); } // Verify teams list after operations @@ -773,6 +766,63 @@ public void testSaveRowsApiCommand() throws Exception assertEquals("San Francisco", teams.get(2).get("City")); assertEquals("Giants", teams.get(2).get("Team")); } + + // Test ExecuteSqlCommand basic SELECT + { + var executeSqlCommand = new ExecuteSqlCommand(schemaName, "SELECT * FROM " + schemaName + "." + ExecuteSqlCommand.quoteIdentifier(playersListName)); + var resp = verifyJerseys(conn, executeSqlCommand, 3); + // setIncludeMetadata(true), the default, should result in metadata and column model + assertNotNull(resp.getMetaData()); + assertNotNull(resp.getColumnModel()); // setIncludeMetadata(true), the default + } + + // Test ExecuteSqlCommand includeMetadata, offset, and maxRows properties + { + var executeSqlCommand = new ExecuteSqlCommand(schemaName, "SELECT * FROM " + schemaName + "." + ExecuteSqlCommand.quoteIdentifier(playersListName)); + executeSqlCommand.addSort(new Sort("JerseyNumber", Sort.Direction.ASCENDING)); + executeSqlCommand.setIncludeMetadata(false); + executeSqlCommand.setOffset(2); + executeSqlCommand.setMaxRows(1); + var resp = verifyJerseys(conn, executeSqlCommand, 1); + // setIncludeMetadata(false) should result in no metadata or column model + assertNull(resp.getMetaData()); + assertNull(resp.getColumnModel()); + } + + // Test ExecuteSqlCommand parameterized query + { + var executeSqlCommand = new ExecuteSqlCommand(schemaName, + "PARAMETERS\n" + + "(\n" + + " Number INTEGER\n" + + ")\nSELECT * FROM " + schemaName + "." + ExecuteSqlCommand.quoteIdentifier(playersListName) + + "\nWHERE JerseyNumber = Number"); + executeSqlCommand.setQueryParameters(Map.of("Number", "44")); + verifyJerseys(conn, executeSqlCommand, 1); + } + } + + private SelectRowsResponse verifyJerseys(Connection conn, BaseQueryCommand command, int expectedCount) throws IOException, CommandException + { + command.addSort(new Sort("JerseyNumber", Sort.Direction.ASCENDING)); + var resp = command.execute(conn, PROJECT_NAME); + var players = resp.getRows(); + assertEquals(expectedCount, players.size()); + + // Phelps (the Yankee) is always the last player + var lastPlayer = players.getLast(); + assertEquals(44, lastPlayer.get("JerseyNumber")); + assertEquals("New York Yankees", lastPlayer.get("Team")); + + if (expectedCount == 3) + { + assertEquals(19, players.get(0).get("jerseyNumber")); // verify case-insensitive + assertEquals("Seattle Mariners", players.get(0).get("Team")); + assertEquals(24, players.get(1).get("Jerseynumber")); // verify case-insensitive + assertEquals("Seattle Mariners", players.get(1).get("Team")); + } + + return resp; } @Override diff --git a/src/org/labkey/test/tests/SimpleModuleTest.java b/src/org/labkey/test/tests/SimpleModuleTest.java index 63fc4ac10f..f8bcf07bf8 100644 --- a/src/org/labkey/test/tests/SimpleModuleTest.java +++ b/src/org/labkey/test/tests/SimpleModuleTest.java @@ -446,7 +446,7 @@ private void doTestColumnValidators() throws Exception deleteCmd.execute(createDefaultConnection(), getProjectName()); } - private void submitAndTestExpectedFailure(Command cmd, String expectedError) throws Exception + private void submitAndTestExpectedFailure(Command cmd, String expectedError) throws Exception { try { diff --git a/src/org/labkey/test/tests/list/ListTest.java b/src/org/labkey/test/tests/list/ListTest.java index 1a56ca7171..6d87576849 100644 --- a/src/org/labkey/test/tests/list/ListTest.java +++ b/src/org/labkey/test/tests/list/ListTest.java @@ -958,7 +958,7 @@ private int lookupListAuditRowId(Connection cn, String listName) throws Exceptio SelectRowsResponse rs = cmd.execute(cn, getProjectName()); if (rs.getRows().isEmpty()) throw new AssertionError("No ListAuditEvent for " + listName); - return ((Number) rs.getRows().get(0).get("RowId")).intValue(); + return ((Number) rs.getRows().getFirst().get("RowId")).intValue(); } /* Issue 23487: add regression coverage for batch insert into list with multiple errors @@ -1092,9 +1092,9 @@ public void testRemoveColumnOverAPI() throws Exception public void testChangeListNameOverAPI() throws Exception { List cols = Arrays.asList( - new FieldDefinition("name", ColumnType.String), - new FieldDefinition("title", ColumnType.String), - new FieldDefinition("dewey", ColumnType.Decimal) + new FieldDefinition("name", ColumnType.String), + new FieldDefinition("title", ColumnType.String), + new FieldDefinition("dewey", ColumnType.Decimal) ); String listName = "remoteAPIBeforeRename"; TestDataGenerator dgen = new TestDataGenerator("lists", listName, getProjectName()) @@ -1114,7 +1114,6 @@ public void testChangeListNameOverAPI() throws Exception @Test public void testChangeListName() { - String listNameBefore = TestDataGenerator.randomDomainName("Before Rename", DomainUtils.DomainKind.IntList); _listHelper.createList(PROJECT_VERIFY, listNameBefore, @@ -1962,19 +1961,19 @@ private List> getListAuditEventsSince(String listName, int p ).getRows(); } - private List getQueryFormFieldNamesDecoded() + private List getQueryFormFieldNamesDecoded() { ArrayList ret = new ArrayList<>(); Locator.tag("input").attributeStartsWith("name", "quf_") .findElements(getDriver()).stream() .map(el -> el.getDomAttribute("name")) .map(s -> s.substring(4)) - .forEach(name -> ret.add(name)); + .forEach(ret::add); Locator.tag("input").attributeStartsWith("name", "%_quf_") .findElements(getDriver()).stream() .map(el -> el.getDomAttribute("name")) .map(name -> EscapeUtil.decode(name.substring(6))) - .forEach(name -> ret.add(name)); + .forEach(ret::add); return ret; } @@ -2017,12 +2016,10 @@ public void testTrickyCharacterFields() throws IOException // These validate Issue 52069 Issue 52070 Issue 52071 testTricky("Tricky Field Character", false); testTricky("TrickyField Character Auto Key", true); - } private void testTricky(String listName, boolean autoKey) throws IOException { - String keyField = "Key Field \"`~!@#$%^&*()_-+={}[]|\\:;<>,.?/\u5668\u9aa8"; String keyField_Bulk = "\"" + keyField.replace("\"", "\"\"") + "\"" ; String intField = "Int Field \"`~!@#$%^&*()_-+={}[]|\\:;<>,.?/\u00a5\u00e6"; @@ -2141,7 +2138,6 @@ private void testTricky(String listName, boolean autoKey) throws IOException expectedValues.add(Map.of(EscapeUtil.fieldKeyEncodePart(keyField), "3", EscapeUtil.fieldKeyEncodePart(intField), "300", EscapeUtil.fieldKeyEncodePart(trickyField), "303")); - } else { @@ -2232,7 +2228,6 @@ private void testTricky(String listName, boolean autoKey) throws IOException assertEquals(String.format("Row detail for column '%s' not as expected.", expectedFields.get(i)), expectedFields.get(i), actualFields.get(i)); } - } private void validateDataRegionTableForTricky(List> expectedValue)