diff --git a/src/org/labkey/test/components/pipeline/PipelineTriggerWizard.java b/src/org/labkey/test/components/pipeline/PipelineTriggerWizard.java index 33f9c887f5..e51f06c82d 100644 --- a/src/org/labkey/test/components/pipeline/PipelineTriggerWizard.java +++ b/src/org/labkey/test/components/pipeline/PipelineTriggerWizard.java @@ -64,7 +64,12 @@ public static PipelineTriggerWizard beginAt(WebDriverWrapper driver, String cont public static PipelineTriggerWizard beginAt(WebDriverWrapper driver, String containerPath, String pipelineTask) { - driver.beginAt(WebTestHelper.buildURL("pipeline", containerPath, "createPipelineTrigger", Map.of("pipelineTask", pipelineTask))); + return beginAt(driver, containerPath, Map.of("pipelineTask", pipelineTask)); + } + + public static PipelineTriggerWizard beginAt(WebDriverWrapper driver, String containerPath, Map params) + { + driver.beginAt(WebTestHelper.buildURL("pipeline", containerPath, "createPipelineTrigger", params)); return new PipelineTriggerWizard(driver.getDriver()); } @@ -156,6 +161,11 @@ public PipelineTriggerWizard goToConfiguration() return this; } + public String getLocation() + { + return elementCache().locationInput.get(); + } + public PipelineTriggerWizard setLocation(String value) { elementCache().locationInput.set(value); @@ -223,6 +233,12 @@ public PipelineTriggerWizard setCopy(String value) return this; } + public String getParameterFunction() + { + showAdvanced(); + return elementCache().paramFunctionInput.get(); + } + public PipelineTriggerWizard setParameterFunction(String function) { showAdvanced(); @@ -231,6 +247,13 @@ public PipelineTriggerWizard setParameterFunction(String function) return this; } + public boolean isParameterFunctionPresent() + { + showAdvanced(); + getWrapper().shortWait().until(ExpectedConditions.visibilityOf(elementCache().addCustomParam)); + return elementCache().paramFunctionInput.getComponentElement().isDisplayed(); + } + private void showAdvanced() { if (!Locator.byClass("advanced-settings").findWhenNeeded(this).isDisplayed()) @@ -310,9 +333,9 @@ protected class ElementCache extends Component.ElementCache //details page elements Input nameInput = new Input(Locator.tagWithName("input", "name").findWhenNeeded(this), getDriver()); Input descriptionInput = new Input(Locator.tagWithName("textarea", "description").findWhenNeeded(this), getDriver()); - OptionSelect typeSelect = new OptionSelect(Locator.tagWithName("select", "type").findWhenNeeded(this)); - OptionSelect taskSelect = new OptionSelect(Locator.tagWithName("select", "pipelineId").findWhenNeeded(this)); - OptionSelect usernameInput = new OptionSelect(Locator.tagWithName("select", "username").findWhenNeeded(this)); + OptionSelect typeSelect = new OptionSelect<>(Locator.tagWithName("select", "type").findWhenNeeded(this)); + OptionSelect taskSelect = new OptionSelect<>(Locator.tagWithName("select", "pipelineId").findWhenNeeded(this)); + OptionSelect usernameInput = new OptionSelect<>(Locator.tagWithName("select", "username").findWhenNeeded(this)); Input assayProviderInput = new Input(Locator.tagWithName("input", "assay provider").findWhenNeeded(this), getDriver()); Checkbox enabledCheckbox = new Checkbox(Locator.tagWithName("input", "enabled").findWhenNeeded(this)); //configuration page elements @@ -323,12 +346,12 @@ protected class ElementCache extends Component.ElementCache Input containerMoveInput = new Input(Locator.tagWithName("input", "moveContainer").findWhenNeeded(this), getDriver()); Input subdirectoryMoveInput = new Input(Locator.tagWithName("input", "moveDirectory").findWhenNeeded(this), getDriver()); Input copyInput = new Input(Locator.tagWithName("input", "copy").findWhenNeeded(this), getDriver()); - Input paramFunctionInput = new Input(Locator.tagWithName("textarea", "parameterFunction").findWhenNeeded(this), getDriver()); + Input paramFunctionInput = new Input(Locator.id("parameter-function").findWhenNeeded(this), getDriver()); WebElement showAdvanced = Locator.byClass("custom-config__button").withText("Show Advanced Settings").findWhenNeeded(this); WebElement addCustomParam = Locator.byClass("custom-config__button").withText("Add Custom Parameter").findWhenNeeded(this); Input assayProtocolInput = new Input(Locator.tagWithName("input", "protocolName").findWhenNeeded(this), getDriver()); Input configurationFileInput = new Input(Locator.name("configFileName").findWhenNeeded(this), getDriver()); - //navgiation elements + //navigation elements WebElement detailsButton = Locator.linkContainingText("Details").findWhenNeeded(this); WebElement configurationButton = Locator.linkContainingText("Configuration").findWhenNeeded(this); diff --git a/src/org/labkey/test/tests/ClientAPITest.java b/src/org/labkey/test/tests/ClientAPITest.java index a04a151032..b7c571e7c7 100644 --- a/src/org/labkey/test/tests/ClientAPITest.java +++ b/src/org/labkey/test/tests/ClientAPITest.java @@ -27,6 +27,7 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.labkey.remoteapi.CommandException; +import org.labkey.remoteapi.CommandResponse; import org.labkey.remoteapi.Connection; import org.labkey.remoteapi.SimpleGetCommand; import org.labkey.remoteapi.SimplePostCommand; @@ -83,6 +84,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.labkey.test.WebTestHelper.getHttpResponse; @@ -1527,6 +1529,82 @@ protected HttpUriRequest getHttpRequest(Connection connection, String folderPath } } + private record CountCase(Map filters, int expectedCount) {} + + private static final String MAX_ROWS_PARAM = "query.maxRows"; + private static final String OFFSET_PARAM = "query.offset"; + private static final String INCLUDE_TOTAL_COUNT_PARAM = "includeTotalCount"; + private static final String INCLUDE_METADATA_PARAM = "includeMetadata"; + + // GH Issue 1607 + @Test + public void testSelectRowsCountOnly() throws Exception + { + Connection cn = createDefaultConnection(); + List countCases = List.of( + new CountCase(Map.of(), 7), + new CountCase(Map.of("query.Age~gt", 30), 5), + new CountCase(Map.of("query.FirstName~eq", "Nobody"), 0), + new CountCase(Map.of("query.Age~eq", "notANumber"), 0)); + + for (double apiVersion : List.of(8.3, 9.1, 17.1)) + { + for (CountCase countCase : countCases) + { + String description = "apiVersion " + apiVersion + ", filters " + countCase.filters(); + + log("Verify count-only request: " + description); + CommandResponse countOnly = selectPeople(cn, apiVersion, countCase.filters(), Map.of(MAX_ROWS_PARAM, 0, INCLUDE_TOTAL_COUNT_PARAM, true)); + assertEquals("Wrong count-only rowCount: " + description, countCase.expectedCount(), getRowCount(countOnly)); + List rows = countOnly.getProperty("rows"); + assertTrue("Count-only request should return no rows: " + description, rows.isEmpty()); + + CommandResponse paged = selectPeople(cn, apiVersion, countCase.filters(), Map.of(MAX_ROWS_PARAM, 1)); + assertEquals("Count-only rowCount should match paged rowCount: " + description, getRowCount(paged), getRowCount(countOnly)); + + log("Verify count-only request without metadata and with an offset: " + description); + CommandResponse noMetaData = selectPeople(cn, apiVersion, countCase.filters(), Map.of(MAX_ROWS_PARAM, 0, INCLUDE_TOTAL_COUNT_PARAM, true, INCLUDE_METADATA_PARAM, false, OFFSET_PARAM, 100)); + assertEquals("Wrong count-only rowCount without metadata: " + description, countCase.expectedCount(), getRowCount(noMetaData)); + assertNull("Count-only request with includeMetadata=false should not return metaData: " + description, noMetaData.getProperty("metaData")); + + log("Verify maxRows=0 without an explicit includeTotalCount=true stays metadata only: " + description); + CommandResponse metaDataOnly = selectPeople(cn, apiVersion, countCase.filters(), Map.of(MAX_ROWS_PARAM, 0)); + assertNull("Metadata-only request should not return rowCount: " + description, metaDataOnly.getProperty("rowCount")); + assertNotNull("Metadata-only request should return metaData: " + description, metaDataOnly.getProperty("metaData")); + metaDataOnly = selectPeople(cn, apiVersion, countCase.filters(), Map.of(MAX_ROWS_PARAM, 0, INCLUDE_TOTAL_COUNT_PARAM, false)); + assertNull("includeTotalCount=false request should not return rowCount: " + description, metaDataOnly.getProperty("rowCount")); + } + } + + log("Verify count-only request with a JSON body"); + SimplePostCommand post = new SimplePostCommand("query", "selectRows.api"); + post.setRequiredVersion(17.1); + post.setJsonObject(new JSONObject(Map.of("schemaName", "lists", "query.queryName", LIST_NAME, + "query.Age~gt", 30, MAX_ROWS_PARAM, 0, INCLUDE_TOTAL_COUNT_PARAM, true))); + CommandResponse postResponse = post.execute(cn, API_FOLDER_PATH); + assertEquals("Wrong count-only rowCount for JSON body", 5, getRowCount(postResponse)); + List postRows = postResponse.getProperty("rows"); + assertTrue("Count-only JSON body request should return no rows", postRows.isEmpty()); + } + + private CommandResponse selectPeople(Connection cn, double apiVersion, Map filters, Map params) throws IOException, CommandException + { + Map allParams = new HashMap<>(filters); + allParams.putAll(params); + allParams.put("schemaName", "lists"); + allParams.put("query.queryName", LIST_NAME); + + SimpleGetCommand command = new SimpleGetCommand("query", "selectRows.api"); + command.setRequiredVersion(apiVersion); + command.setParameters(allParams); + return command.execute(cn, API_FOLDER_PATH); + } + + private int getRowCount(CommandResponse response) + { + return ((Number) response.getProperty("rowCount")).intValue(); + } + @Test public void suggestedColumnsInQueryDetailsTest() throws Exception { diff --git a/src/org/labkey/test/tests/assay/UploadLargeExcelAssayTest.java b/src/org/labkey/test/tests/assay/UploadLargeExcelAssayTest.java index 96ec0ad1fd..c035763383 100644 --- a/src/org/labkey/test/tests/assay/UploadLargeExcelAssayTest.java +++ b/src/org/labkey/test/tests/assay/UploadLargeExcelAssayTest.java @@ -141,7 +141,7 @@ public void testUpload200kRows() throws Exception clickButton("Save and Finish"); var assayJobsPage2 = new AssayUploadJobsPage(getDriver()); - var pipelineDetailsPage2 = assayJobsPage2.clickJobStatus("200k take 2", 3 * getDefaultWaitForPage()); + var pipelineDetailsPage2 = assayJobsPage2.clickJobStatus("200k take 2", 7 * getDefaultWaitForPage()); pipelineDetailsPage2.waitForComplete(12 * WebDriverWrapper.WAIT_FOR_PAGE); var qPage = SourceQueryPage.beginAt(this, getProjectName(), "assay.General.large_assay_2", "Data");