From 9ddd6d02d5a5fb649b1aacd52459c0d1a96b9d0c Mon Sep 17 00:00:00 2001 From: Xing Yang <5168106+XingY@users.noreply.github.com> Date: Mon, 16 Dec 2024 07:06:06 -0800 Subject: [PATCH] Add restrictions on names of domains - automated tests (#2189) --- data/samples/ParentSamples.xlsx | Bin 9057 -> 9057 bytes src/org/labkey/test/AssayAPITest.java | 7 +- src/org/labkey/test/BaseWebDriverTest.java | 16 +++- src/org/labkey/test/Locator.java | 2 +- .../ui/grids/FieldSelectionDialog.java | 5 +- .../labkey/test/params/FieldDefinition.java | 5 +- .../labkey/test/tests/AbstractAssayTest.java | 4 +- src/org/labkey/test/tests/ClientAPITest.java | 5 +- .../labkey/test/tests/CustomizeViewTest.java | 3 +- .../DataClassFolderExportImportTest.java | 4 +- src/org/labkey/test/tests/DataRegionTest.java | 3 +- src/org/labkey/test/tests/FilterTest.java | 3 +- src/org/labkey/test/tests/GpatAssayTest.java | 27 +++++-- .../labkey/test/tests/JavaClientApiTest.java | 2 +- .../tests/SampleTypeNameExpressionTest.java | 70 ++++++++++-------- .../labkey/test/tests/SchemaBrowserTest.java | 8 +- src/org/labkey/test/tests/list/ListTest.java | 22 ++++-- src/org/labkey/test/util/EscapeUtil.java | 2 + .../labkey/test/util/TestDataGenerator.java | 27 +++++++ 19 files changed, 152 insertions(+), 63 deletions(-) diff --git a/data/samples/ParentSamples.xlsx b/data/samples/ParentSamples.xlsx index f7aef2a480f8f2a37d844fe7f6af4027c13c78af..3c64e18e948ae175f4c4563a052ea2f443e96183 100644 GIT binary patch delta 2144 zcmV-m2%q=iM&U-V$_52E1&nW$lg|bme{FB0I1v7R()|a-cWRrr04iNU09~baRi)YX z?o;K06Hozj#x$v_{qH*_A#FFOQ?7eaV#nj*@iQ~enDZ~&rq-UB=quiaIyu9-#@d`0 zRl5%LZ_CW^bgh@PEojYK7V0mo*S}o+{@eM6i>F7;i=PykrgSf6sWw zTG&}}(NGCXu||C-7%lpeG1=6}#Mng*ty+DD5QtMS_-a+U2w=p=zLw zV&Bx4sw~z+n~Q)vygH7Hf8Dw78!`4>W1iZP5m{Mgq<-op*ml!dmVJj{gd60X4zk<} zLP3YR4b?x|x~AJ{hu~nSiZ>dsc>gif{L?V)eOCditM9I2oBmBYYN>7StG3{qP8Ao zC{2CCBi7vWv6GlHdt`*(Q5r8!iTR_pyNM_i?$3`5xw&5h1 z<;+MjPn}UrJF+VL)h9114~g2b5Qgt7?SHU*4^Bc#AtF>PDcasv zZMQu;&V*R_BeG2at@__P2`XKQ3#ycn>`CUCdE?jfyMtEb4V;(O6f_ydlz;8UPVyxowoi66J#1rmS5eH2{mr1_7rED=D{PQAV@Bdqqz^f-vAOc{I zgp%H#m9^Xc!v{>oeJQ)BT@UvB<4DCltgL#Kb!ZWQ*Pw=m?^JlS``;ipZNTgi1ZDI- z$m?SXUZ4RHJW3J$0h5dlVKFJ%BSl+qATj3^99rgjnHv-wTIQV01qFweIWKdgfp%iQ?09uHaz39-8pj`jcm0F0A?8XbR4N&`UAOACZ5C*5`~d0Uwz+ui!$?<(1>S9#11RhvuHef9abtom=-Zvc~#0~7_{tCZ(bvyK}x0e{MvE)B3m&7Pbwaq9G~Y3~@37SeVi z|K0){vS{LCd(QoO&P|i$mn^+c(59$VibxP54-~INq4E?xZ&v;SdB!p&SXn7ZQ40nw zv&)Nw*OXTp9(7fNwgni^k(8mlPSM`lnqqAD9wak?b0{b7DlM6HN1fxE@eh^*j>7N? zOMkFTFw1ZU^y`s`j!3~rWPQ+O4-gzf2@;ewm;?m>cr9pY{v7C)iBlG~tzD;M+$me| zK^)y*rWlP)(*(_|kKytYyj|Zv^;P{sb-Ut#vP5voH85N0?1kxr@*bFGEmH}eDBTuI zX6)K6d{=#iB!rlkz&dz1yr%7KKslhp|r<8#1Ty zoX*4d?(MVrF6M9{j|u)GlE^2s4Y{Tyr16w^0%U#e^RJP81Cx;h6tfc^LIVXj1&nW$ zlUgBC0ezFLAuSv`stBgB0ssIp1^@sU0000000000000000I&>`$_yHl5F#o8mya18QUL$}X955K W5dZ)H0000000000004ZG`66i0`u(2( delta 2149 zcmV-r2%7idM&U-V$_52Pc@Z~~lg|bme^GCvI1qk6>HY)ao!SON0F|yn09~baRi)YX z?x}LY38;W`#x$v_{qH*_A#FFOQ?7eaV#nj*^EWf!nDZ~&rZ%3r>?+YlCON~V!P{IE zRlADJZ;QA(qQ3=ZVPshPP@5B6-ae(C^A> z-Hm8XehOT}2CUk`o+!(fjm!Pe1H zO_fX0iKRLNXtX1J6hFa;kPj)?e;()HG$e{7f39>553Hp3Nmkwg%XmC%soFGZ)~U3p6fYuk0!y*s9}Kcz$9+}9F2Mou zOmuOO^NlnLzGQu^79iviJ~C}=I~Z$E5XQ7tT((T{nP?U0a39yNYHq-uf0Y6hZp``L zeI+?G7U&CNg^}eUd+ctQDve&&k%_)_5IovKtG=*yg$n+RlazSL!L9@<=n8DO7FbDU`<5Tm#0qRmEt1k8o~G`^_h#QA80m$%V7)5$ zg3!>BNul~jTi0wm?hqXIRq;mS74JWmo_`v~z3)0;ef8Z{eAB&2M=y=-ebp9X6PccC zLr^c{(t-QVG&aNLeO0IuB;{jzu>HZSRSAsAglZ$Sh-MaPn?+_U^lTRbYO(uQ5r5;pf=1#J2b|vzIX}T=6W8IY#K7uXUNNf3`HCt%UPX6 zBj{;x^a-{D?ZLO|s#C)Z8mxdGp?EsM0kv@IxEA#T+w!SnTQi#2P@ObMV^`Nlza+x{ z75hKt)CKL??*W(~lG|J@S z2LO|i0~E813Nr!;e$-?R$pQcXW0S`WA%9zsn=lZC-z)V$Aiom>VRJ!{RT?(xzE!>K zJ{vOxE51|zdPx-;vt!n{%fCTLd(t6)zlsevmVs2zQ(D3QaR`*S*{j9*Fj z{vX1`DYdW{{Q=%k$;U>DpRTOr27eoW5H`8O`p;#vou~`)=V>}Cm+Ms;#`8%O&Z2Z2 zF4tJ4UtV5jC9YLe{w0gN7I?zFtH452kY$`Lr-Ux@AwO>d4(`7?@T~d)61WG{h)K}L zvodDeZ+yj8ghV%N=!uMbv4<5%iQp+F{P$U75TI9uMSiO>^%PeYaiEHRY@~zg~ zbQnF)QbrodTPo4ZILk(JF6dkC5GD5d!kC4QSUwP_CJiJtEI|zv-UqzfZD%<+EAG(? zmf-sb%7d_e@&!p=pMA_duD2Pj7H9Rh`|F?OAH!T71=UWu+*hV_{%8C<0+VvRpH84M z3pj$zvQh_fJ^s;s0h5sf6a~3A{54avj~g=qf4U8w4X{Mbo}4ieb^6w{cZ>+7X*=2e zy#+R8(Zt90ocr~ho5qWMReE2bO;O7Pksw4KNM4IV<_UVqmi`=h#xf~bSxZRJ0SsEC zmlrWtl-C-bbge+!0*vQK(on7vw6#`Ij1AvH#Z2HF(utc|SIoMj&aqrHR1kJRI;qnu_UOhZ_RsBM?yW)V-Sa8ZUFk9>NmFb=I9+_qbCSyEO+AWsM z*p*xOrT}q!NY`%j-aC_djDL%c+Lh?hKp;F9i}oc>%G>nrK3k%65>94*IP=LoBN3fN zGzvf3x6kI=nEgd{Oz LIST_COLUMNS = List.of( new FieldDefinition("FirstName", FieldDefinition.ColumnType.String).setLabel("First Name").setDescription("The first name").setRequired(true), @@ -626,7 +627,7 @@ public void validateDatasetNameIsNotBlank() "});\n"; Map error = (Map)executeAsyncScript(create); - assertEquals("Unexpected error message", "Dataset name cannot be empty.", error.get("exception")); + assertEquals("Unexpected error message", "StudyDatasetVisit name must not be blank.", error.get("exception")); } @Test diff --git a/src/org/labkey/test/tests/CustomizeViewTest.java b/src/org/labkey/test/tests/CustomizeViewTest.java index 155dcaf366..86053cd3bd 100644 --- a/src/org/labkey/test/tests/CustomizeViewTest.java +++ b/src/org/labkey/test/tests/CustomizeViewTest.java @@ -43,13 +43,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.labkey.test.params.FieldDefinition.DOMAIN_TRICKY_CHARACTERS; @Category({Daily.class}) @BaseWebDriverTest.ClassTimeout(minutes = 8) public class CustomizeViewTest extends BaseWebDriverTest { public static final String PROJECT_NAME = "CustomizeViewTest"; - public static final String LIST_NAME = "People" + INJECT_CHARS_1; + public static final String LIST_NAME = "People" + DOMAIN_TRICKY_CHARACTERS; private final static String LIST_KEY_COLUMN = "Key"; private final static String LAST_NAME_COLUMN = "LastName" + INJECT_CHARS_2; private final static String FIRST_NAME_COLUMN = "FirstName"; diff --git a/src/org/labkey/test/tests/DataClassFolderExportImportTest.java b/src/org/labkey/test/tests/DataClassFolderExportImportTest.java index 565e33c82a..e2bf7910b4 100644 --- a/src/org/labkey/test/tests/DataClassFolderExportImportTest.java +++ b/src/org/labkey/test/tests/DataClassFolderExportImportTest.java @@ -84,7 +84,7 @@ public void testExportImportSimpleDataClass() throws Exception { String subfolder = "simpleDataClassExportFolder"; String subfolderPath = getProjectName() + "/" + subfolder; - String testDataClass = "testData?<>*/Class"; // having the dataClass with non-file-legal chars in it is intentional, + String testDataClass = "testData_/Class"; // having the dataClass with non-file-legal chars in it is intentional, // the import/export processes will write temp-files with names derived from // the dataClass name. This ensures that the sanitized name on export can // be successfully matched up with the intended dataClass on import @@ -181,7 +181,7 @@ public void testExportImportMissingValueDataClass() throws Exception String subfolder = "missingValueDataClassExportFolder"; String subfolderPath = getProjectName() + "/" + subfolder; - String testDataClass = "missing?Value*Data//Class"; // having the dataClass with non-file-legal chars in it is intentional, + String testDataClass = "missing_Value+Data//Class"; // having the dataClass with non-file-legal chars in it is intentional, // the import/export processes will write temp-files with names derived from // the dataClass name. This ensures that the sanitized name on export can // be successfully matched up with the intended dataClass on import diff --git a/src/org/labkey/test/tests/DataRegionTest.java b/src/org/labkey/test/tests/DataRegionTest.java index caeae843dc..5b4556597a 100644 --- a/src/org/labkey/test/tests/DataRegionTest.java +++ b/src/org/labkey/test/tests/DataRegionTest.java @@ -39,12 +39,13 @@ import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.labkey.test.params.FieldDefinition.DOMAIN_TRICKY_CHARACTERS; @Category({Daily.class, Data.class}) @BaseWebDriverTest.ClassTimeout(minutes = 6) public class DataRegionTest extends AbstractQWPTest { - private static final String LIST_NAME = "WebColors" + INJECT_CHARS_1; + private static final String LIST_NAME = "WebColors" + DOMAIN_TRICKY_CHARACTERS; private static final FieldDefinition.ColumnType LIST_KEY_TYPE = FieldDefinition.ColumnType.Integer; private static final String LIST_KEY_NAME = "Key"; diff --git a/src/org/labkey/test/tests/FilterTest.java b/src/org/labkey/test/tests/FilterTest.java index 47030e3a3c..b47d47b47d 100644 --- a/src/org/labkey/test/tests/FilterTest.java +++ b/src/org/labkey/test/tests/FilterTest.java @@ -47,6 +47,7 @@ import static org.junit.Assert.assertEquals; import static org.labkey.test.params.FieldDefinition.ColumnType; +import static org.labkey.test.params.FieldDefinition.DOMAIN_TRICKY_CHARACTERS; import static org.labkey.test.params.FieldDefinition.LookupInfo; import static org.labkey.test.util.PermissionsHelper.MemberType; @@ -59,7 +60,7 @@ public class FilterTest extends BaseWebDriverTest protected final static String R_VIEW = TRICKY_CHARACTERS + "R report"; protected final static String FACET_TEST_LIST = "FacetList"; - protected final static String LIST_NAME_COLORS = TRICKY_CHARACTERS_NO_QUOTES + "Colors"; + protected final static String LIST_NAME_COLORS = "Colors" + DOMAIN_TRICKY_CHARACTERS; protected final static String LIST_KEY_NAME2 = "Color"; protected final FieldDefinition _listColKey = new FieldDefinition("Color", ColumnType.String); diff --git a/src/org/labkey/test/tests/GpatAssayTest.java b/src/org/labkey/test/tests/GpatAssayTest.java index 6a2cc88439..3d424a7038 100644 --- a/src/org/labkey/test/tests/GpatAssayTest.java +++ b/src/org/labkey/test/tests/GpatAssayTest.java @@ -15,6 +15,7 @@ */ package org.labkey.test.tests; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -37,8 +38,10 @@ import org.labkey.test.pages.core.admin.BaseSettingsPage; import org.labkey.test.params.FieldDefinition; import org.labkey.test.util.DataRegionTable; +import org.labkey.test.util.EscapeUtil; import org.labkey.test.util.LogMethod; import org.labkey.test.util.LoggedParam; +import org.labkey.test.util.TestDataGenerator; import org.labkey.test.util.core.webdav.WebDavUploadHelper; import org.openqa.selenium.WebElement; @@ -53,6 +56,7 @@ import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.labkey.test.params.FieldDefinition.DOMAIN_TRICKY_CHARACTERS; @Category({Assays.class, BVT.class}) @BaseWebDriverTest.ClassTimeout(minutes = 7) @@ -62,7 +66,7 @@ public class GpatAssayTest extends BaseWebDriverTest private static final File GPAT_ASSAY_XLSX = TestFileUtils.getSampleData("GPAT/trial01a.xlsx"); private static final File GPAT_ASSAY_TSV = TestFileUtils.getSampleData("GPAT/trial02.tsv"); private static final File GPAT_ASSAY_FNA_1 = TestFileUtils.getSampleData("GPAT/trial03.fna"); - private static final String ASSAY_NAME_XLS = "XLS Assay " + TRICKY_CHARACTERS; + private static final String ASSAY_NAME_XLS = "XLS Assay " + DOMAIN_TRICKY_CHARACTERS; private static final String ASSAY_NAME_XLSX = "XLSX Assay"; private static final String ASSAY_NAME_TSV = "TSV Assay"; private static final String ASSAY_NAME_FNA = "FASTA Assay"; @@ -118,7 +122,7 @@ public void testSteps() { // Issue 36077: SelectRows: SchemaKey decoding of public schema name causes request failure Connection cn = createDefaultConnection(); - SelectRowsCommand selectCmd = new SelectRowsCommand("assay.General." + ASSAY_NAME_XLS, "Runs"); + SelectRowsCommand selectCmd = new SelectRowsCommand("assay.General." + EscapeUtil.fieldKeyEncodePart(ASSAY_NAME_XLS), "Runs"); selectCmd.setRequiredVersion(17.1); SelectRowsResponse selectResp = selectCmd.execute(cn, getProjectName()); assertEquals(1, selectResp.getRowCount().intValue()); @@ -333,15 +337,20 @@ public void testMultipleFileUploadSingleRowInAssayRun() @Test public void testUpdateAssayDesign() throws IOException, CommandException { + File trialData = TestFileUtils.getSampleData("GPAT/renameAssayTrial.xls"); + + String invalidAssayName = TestDataGenerator.randomInvalidDomainName(10); + ReactAssayDesignerPage assayDesignerPage = startCreateGpatAssay(trialData, invalidAssayName); + List errors = assayDesignerPage.clickSaveExpectingErrors(); + assayDesignerPage.clickCancel(); + Assert.assertTrue("Error msg not as expected during assay creation", errors.contains("Invalid Assay Design name \"" + invalidAssayName + "\". Assay Design name must start with a letter or a number.")); BaseSettingsPage.resetSettings(createDefaultConnection(), "/"); BaseSettingsPage.resetSettings(createDefaultConnection(), getProjectName()); - File trialData = TestFileUtils.getSampleData("GPAT/renameAssayTrial.xls"); - - String originalAssayName = "A Assay Name"; + String originalAssayName = TestDataGenerator.randomDomainName(); log(String.format("Create an assay named '%s'.", originalAssayName)); - ReactAssayDesignerPage assayDesignerPage = startCreateGpatAssay(trialData, originalAssayName); + assayDesignerPage = startCreateGpatAssay(trialData, originalAssayName); DomainFormPanel runProperties = assayDesignerPage.goToRunFields(); @@ -389,7 +398,7 @@ public void testUpdateAssayDesign() throws IOException, CommandException checker().verifyEquals(String.format("Value in column '%s' is not as expected.", runDateTime02), defaultDateTimeFormat.format(date), rowMap.get(runDateTime02)); - String newAssayName = "Updated Assay Name"; + String newAssayName = TestDataGenerator.randomDomainName(); log(String.format("Edit the assay design and rename it to '%s'.", newAssayName)); assayDesignerPage = _assayHelper.clickEditAssayDesign(false); @@ -397,6 +406,10 @@ public void testUpdateAssayDesign() throws IOException, CommandException .verifyTrue("The 'Name' field should be enabled and editable. Fatal error.", assayDesignerPage.isNameEnabled()); + assayDesignerPage.setName(invalidAssayName); + errors = assayDesignerPage.clickSaveExpectingErrors(); + Assert.assertTrue("Error msg not as expected during assay update", errors.contains("Invalid Assay Design name \"" + invalidAssayName + "\". Assay Design name must start with a letter or a number.")); + assayDesignerPage.setName(newAssayName); log("Convert the date, time and dateTime run fields to different (compatible) types."); diff --git a/src/org/labkey/test/tests/JavaClientApiTest.java b/src/org/labkey/test/tests/JavaClientApiTest.java index 76566158cf..09cf72624b 100644 --- a/src/org/labkey/test/tests/JavaClientApiTest.java +++ b/src/org/labkey/test/tests/JavaClientApiTest.java @@ -94,7 +94,7 @@ public class JavaClientApiTest extends BaseWebDriverTest { public static final String PROJECT_NAME = JavaClientApiTest.class.getSimpleName() + " Project " + TRICKY_CHARACTERS_FOR_PROJECT_NAMES; - public static final String LIST_NAME = "People" + FieldDefinition.TRICKY_CHARACTERS; + public static final String LIST_NAME = "People" + FieldDefinition.DOMAIN_TRICKY_CHARACTERS; public static final String LAST_NAME = "LastName" + FieldDefinition.TRICKY_CHARACTERS; public static final String USER_NAME = "user1@javaclientapi.test"; public static final String USER2_NAME = "user2@javaclientapi.test"; diff --git a/src/org/labkey/test/tests/SampleTypeNameExpressionTest.java b/src/org/labkey/test/tests/SampleTypeNameExpressionTest.java index b7692bab06..58c2eca4fb 100644 --- a/src/org/labkey/test/tests/SampleTypeNameExpressionTest.java +++ b/src/org/labkey/test/tests/SampleTypeNameExpressionTest.java @@ -34,6 +34,7 @@ import org.labkey.test.params.FieldDefinition; import org.labkey.test.params.experiment.SampleTypeDefinition; import org.labkey.test.util.DataRegionTable; +import org.labkey.test.util.EscapeUtil; import org.labkey.test.util.PortalHelper; import org.labkey.test.util.SampleTypeHelper; import org.labkey.test.util.TestDataGenerator; @@ -57,6 +58,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.labkey.test.params.FieldDefinition.DOMAIN_TRICKY_CHARACTERS; @Category({Daily.class}) @BaseWebDriverTest.ClassTimeout(minutes = 5) @@ -65,7 +67,8 @@ public class SampleTypeNameExpressionTest extends BaseWebDriverTest private static final String PROJECT_NAME = "SampleType_Name_Expression_Test"; private static final String DEFAULT_SAMPLE_PARENT_VALUE = "SS"; - private static final String PARENT_SAMPLE_TYPE = "Parent_SampleType"; + private static final String PARENT_SAMPLE_TYPE = "PS" + DOMAIN_TRICKY_CHARACTERS; + private static final String PARENT_SAMPLE_TYPE_INPUT = "PS" + DOMAIN_TRICKY_CHARACTERS.replace("/", "$S"); private static final String PARENT_SAMPLE_01 = "parent01"; private static final String PARENT_SAMPLE_02 = "parent02"; @@ -193,18 +196,21 @@ public void testDeriveFromCommentLikeParents() final String sampleTypeName = "ParentNamesExprTest"; log("Verify import tsv to create derivative would ignore lines starting with #"); - String nameExpression = "${MaterialInputs/" + PARENT_SAMPLE_TYPE + "}-child"; - String data = "MaterialInputs/" + PARENT_SAMPLE_TYPE + "\n"; + String nameExpression = "${MaterialInputs/" + PARENT_SAMPLE_TYPE_INPUT + "}-child"; + String data = "MaterialInputs/" + PARENT_SAMPLE_TYPE + "\n"; // unencoded header data += PARENT_SAMPLE_01 + "\n"; - data += PARENT_SAMPLE_01 + "," + PARENT_SAMPLE_02 + "," + PARENT_SAMPLE_03 + "\n"; - // tsv lines starting with # should be ignored - data += PARENT_SAMPLE_03 + "\n"; - data += PARENT_SAMPLE_03 + "," + PARENT_SAMPLE_02 + "\n"; SampleTypeHelper sampleHelper = new SampleTypeHelper(this); sampleHelper.createSampleType(new SampleTypeDefinition(sampleTypeName) .setNameExpression(nameExpression), data); + data = "MaterialInputs/" + PARENT_SAMPLE_TYPE_INPUT + "\n"; // "/" encoded in header + data += PARENT_SAMPLE_01 + "," + PARENT_SAMPLE_02 + "," + PARENT_SAMPLE_03 + "\n"; + // tsv lines starting with # should be ignored + data += PARENT_SAMPLE_03 + "\n"; + data += PARENT_SAMPLE_03 + "," + PARENT_SAMPLE_02 + "\n"; + sampleHelper.bulkImport(data); + DataRegionTable materialTable = new DataRegionTable("Material", this); List names = materialTable.getColumnDataAsText("Name"); Collections.reverse(names); @@ -220,7 +226,7 @@ public void testDeriveFromCommentLikeParents() assertEquals("Sample names are not as expected", expectedNames, names); log("Verify import tsv should successfully create derivatives from parent starting with #, as long as this is not the 1st field in the row"); - data = "Description\tMaterialInputs/" + PARENT_SAMPLE_TYPE + "\n"; + data = "Description\tMaterialInputs/" + EscapeUtil.fieldKeyEncodePart(PARENT_SAMPLE_TYPE) + "\n"; // fully encoded data += "Parent with leading # should work\t" + PARENT_SAMPLE_03 + "\n"; data += "Parents with leading # should work\t" + PARENT_SAMPLE_03 + "," + PARENT_SAMPLE_02 + "\n"; @@ -288,7 +294,7 @@ public void testWithTrickyCharacters() SampleTypeHelper sampleTypeHelper = new SampleTypeHelper(this); - final String sampleTypeName = "TrickyNameExprTest"; + final String sampleTypeName = "Tricky_" + TestDataGenerator.randomDomainName(); CreateSampleTypePage createPage = sampleTypeHelper.goToCreateNewSampleType(); @@ -387,33 +393,33 @@ public void testInputsExpression() null, "Pat"); verifyNames( - "InputsExpressionTest2", - "Name\tB\tMaterialInputs/InputsExpressionTest2", + "Inputs/ExpressionTest2", + "Name\tB\tMaterialInputs/Inputs$SExpressionTest2", "${Inputs:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", null, "Bat", false); verifyNames( - "InputsWithDataTypeExpression", - "Name\tB\tMaterialInputs/InputsWithDataTypeExpression", - "${Inputs/InputsWithDataTypeExpression:first:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", + "Inputs/WithDataTypeExpression", + "Name\tB\tMaterialInputs/Inputs/WithDataTypeExpression", + "${Inputs/Inputs$SWithDataTypeExpression:first:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", null, "Red"); verifyNames( - "InputsWithDataTypeExpression2", - "Name\tB\tMaterialInputs/InputsWithDataTypeExpression2", - "${Inputs/InputsWithDataTypeExpression2:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", + "Inputs/WithDataTypeExpression2", + "Name\tB\tMaterialInputs/Inputs$SWithDataTypeExpression2", + "${Inputs/Inputs$SWithDataTypeExpression2:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", null, "Ted", false); verifyNames( - "MaterialWithDataTypeExpression", - "Name\tB\tMaterialInputs/MaterialWithDataTypeExpression", - "${MaterialInputs/MaterialWithDataTypeExpression:first:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", + "Material/WithDataTypeExpression", + "Name\tB\tMaterialInputs/Material/WithDataTypeExpression", + "${MaterialInputs/Material$SWithDataTypeExpression:first:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", null, "Ned"); verifyNames( - "MaterialWithDataTypeExpression2", - "Name\tB\tMaterialInputs/MaterialWithDataTypeExpression2", - "${MaterialInputs/MaterialWithDataTypeExpression2:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", + "Material/WithDataTypeExpression2", + "Name\tB\tMaterialInputs/Material$SWithDataTypeExpression2", + "${MaterialInputs/Material$SWithDataTypeExpression2:defaultValue('" + DEFAULT_SAMPLE_PARENT_VALUE + "')}_${batchRandomId}", null, "Med", false); } @@ -564,7 +570,7 @@ public void testDeriveSampleFromSampleDetailsPage() throws Exception SampleTypeHelper sampleHelper = new SampleTypeHelper(this); final String sampleType = "DerivedUI_SampleType"; - final String nameExpression = String.format("DUI_${genId}_${materialInputs/%s/Str}", PARENT_SAMPLE_TYPE); + final String nameExpression = String.format("DUI_${genId}_${materialInputs/%s/Str}", PARENT_SAMPLE_TYPE_INPUT); // TODO: When Issue 44760 this test can be updated to use a parent alias in the name expression. @@ -591,7 +597,7 @@ public void testDeriveSampleFromSampleDetailsPage() throws Exception checker().verifyTrue(String.format("Doesn't look like there is a link to the parent sample '%s'.", PARENT_SAMPLE_01), isElementPresent(Locator.linkWithText(PARENT_SAMPLE_01))); - final String ancestorNameExpression = String.format("GrandChild_${MaterialInputs/%s/..[MaterialInputs/%s]/Str}_${genId}", sampleType, PARENT_SAMPLE_TYPE); + final String ancestorNameExpression = String.format("GrandChild_${MaterialInputs/%s/..[MaterialInputs/%s]/Str}_${genId}", sampleType, PARENT_SAMPLE_TYPE_INPUT); log("Change the sample type name expression to support grandparent property lookup: " + ancestorNameExpression); goToProjectHome(); SampleTypeHelper sampleTypeHelper = new SampleTypeHelper(this); @@ -731,14 +737,20 @@ public void testNameExpressionPreview() throws IOException, CommandException createPage.addParentAlias(parentAlias, String.format("Sample Type: %1$s (%2$s)", PARENT_SAMPLE_TYPE, PROJECT_NAME)); - log("Use a name expression using a field from the named parent."); - String nameExpression = String.format("SNP_${genId}_${%1$s/Int}_${materialInputs/%2$s/Str}", parentAlias, PARENT_SAMPLE_TYPE); + log("Use a name expression using a field from the named parent, with parent type not encoded."); + String nameExpressionBad = String.format("SNP_${genId}_${%1$s/Int}_${materialInputs/%2$s/Str}", parentAlias, PARENT_SAMPLE_TYPE); + createPage.setNameExpression(nameExpressionBad); + actualMsg = createPage.getNameExpressionPreview(); + checker().withScreenshot("Parent_Fields_Preview_Error") + .verifyTrue("Tool-tip message does not contain expected example.", actualMsg.contains("Unable to generate example name from the current pattern. Check for syntax errors.")); + // Make the tooltip go away. + mouseOver(createPage.getComponentElement()); + log("Use a name expression using a field from the named parent, with parent type encoded correctly."); + String nameExpression = String.format("SNP_${genId}_${%1$s/Int}_${materialInputs/%2$s/Str}", parentAlias, PARENT_SAMPLE_TYPE_INPUT); createPage.setNameExpression(nameExpression); - expectedMsg = generateExpectedToolTip("SNP_1001_3_parentStrValue"); actualMsg = createPage.getNameExpressionPreview(); - log("Verify that the preview shows the fields as expected."); checker().withScreenshot("Parent_Fields_Preview_Error") .verifyEquals("Tool-tip message does not contain expected example.", expectedMsg, actualMsg); diff --git a/src/org/labkey/test/tests/SchemaBrowserTest.java b/src/org/labkey/test/tests/SchemaBrowserTest.java index f3b8db4627..1d0922eebc 100644 --- a/src/org/labkey/test/tests/SchemaBrowserTest.java +++ b/src/org/labkey/test/tests/SchemaBrowserTest.java @@ -26,6 +26,8 @@ import java.util.Arrays; import java.util.List; +import static org.labkey.test.params.FieldDefinition.DOMAIN_TRICKY_CHARACTERS; + @Category({Daily.class}) @BaseWebDriverTest.ClassTimeout(minutes = 4) public class SchemaBrowserTest extends BaseWebDriverTest @@ -34,9 +36,9 @@ public class SchemaBrowserTest extends BaseWebDriverTest public static final String TEST_DESC_BOOKS = "This is a test description on books"; public static final String TEST_DESC_AUTHORS = "This is a test description on authors"; public static final String TEST_DESC_PUBLISHERS = "This is a test description on publishers"; - public static final String AUTHORS_LIST = "Authors" + TRICKY_CHARACTERS_NO_QUOTES; - public static final String PUBLISHERS_LIST = "Publishers" + TRICKY_CHARACTERS_NO_QUOTES; - public static final String BOOKS_LIST = "Books" + TRICKY_CHARACTERS_NO_QUOTES; + public static final String AUTHORS_LIST = "Authors" + DOMAIN_TRICKY_CHARACTERS; + public static final String PUBLISHERS_LIST = "Publishers" + DOMAIN_TRICKY_CHARACTERS; + public static final String BOOKS_LIST = "Books" + DOMAIN_TRICKY_CHARACTERS; @Override public List getAssociatedModules() diff --git a/src/org/labkey/test/tests/list/ListTest.java b/src/org/labkey/test/tests/list/ListTest.java index 4d99a190f0..650e559ece 100644 --- a/src/org/labkey/test/tests/list/ListTest.java +++ b/src/org/labkey/test/tests/list/ListTest.java @@ -18,6 +18,7 @@ import org.hamcrest.CoreMatchers; import org.hamcrest.MatcherAssert; +import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; @@ -80,6 +81,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.labkey.test.params.FieldDefinition.ColumnType; +import static org.labkey.test.params.FieldDefinition.DOMAIN_TRICKY_CHARACTERS; import static org.labkey.test.util.DataRegionTable.DataRegion; @Category({Daily.class, Data.class, Hosting.class}) @@ -88,7 +90,7 @@ public class ListTest extends BaseWebDriverTest { protected final static String PROJECT_VERIFY = "ListVerifyProject" ;//+ TRICKY_CHARACTERS_FOR_PROJECT_NAMES; private final static String PROJECT_OTHER = "OtherListVerifyProject"; - protected final static String LIST_NAME_COLORS = TRICKY_CHARACTERS_NO_QUOTES + "Colors"; + protected final static String LIST_NAME_COLORS = "A_Colors_" + DOMAIN_TRICKY_CHARACTERS; protected final static ColumnType LIST_KEY_TYPE = ColumnType.String; protected final static String LIST_KEY_NAME = "Key"; protected final static String LIST_KEY_NAME2 = "Color"; @@ -143,7 +145,7 @@ public class ListTest extends BaseWebDriverTest private final String TEST_FAIL3 = LIST_KEY_NAME2 + "\t" + FAKE_COL_NAME + "\t" + _listColMonth.getName() + "\n" + LIST_ROW1; private final static String TEST_VIEW = "list_view"; - private final static String LIST2_NAME_CARS = TRICKY_CHARACTERS_NO_QUOTES + "Cars"; + private final static String LIST2_NAME_CARS = "Cars_" + DOMAIN_TRICKY_CHARACTERS; protected final static ColumnType LIST2_KEY_TYPE = ColumnType.String; protected final static String LIST2_KEY_NAME = "Car"; @@ -563,7 +565,7 @@ public void testCustomViews() clickAndWait(Locator.linkWithText("view history")); checker().wrapAssertion(()->assertTextPresent(":History")); checker().wrapAssertion(()->assertTextPresent("record was modified", 2)); // An existing list record was modified - checker().wrapAssertion(()->assertTextPresent("were modified", 8)); // The column(s) of domain >assertTextPresent("were modified", 8)); // The column(s) of LIST_NAME_COLORS domain were modified checker().wrapAssertion(()->assertTextPresent("Bulk inserted", 2)); checker().wrapAssertion(()->assertTextPresent("A new list record was inserted", 1)); checker().wrapAssertion(()->assertTextPresent("was created", 2)); // Once for the list, once for the domain @@ -866,7 +868,7 @@ public void testChangeListName() throws Exception @Test public void listSelfJoinTest() { - final String listName = "listSelfJoin" + TRICKY_CHARACTERS; + final String listName = "listSelfJoin" + DOMAIN_TRICKY_CHARACTERS; final String dummyBase = "dummyCol"; final String dummyCol = dummyBase + TRICKY_CHARACTERS; final String lookupField = "lookupField" + TRICKY_CHARACTERS; @@ -1149,10 +1151,20 @@ public void doRenameFieldsTest() String listName = "new"; String origFieldName = "BarBar"; String newFieldName = "FooFoo"; + String invalidListName = TestDataGenerator.randomInvalidDomainName(5); + EditListDefinitionPage listDefinitionPage = _listHelper.beginCreateList(PROJECT_VERIFY, invalidListName); + listDefinitionPage.manuallyDefineFieldsWithAutoIncrementingKey("key"); + List errors = listDefinitionPage.clickSaveExpectingErrors(); + Assert.assertTrue("Error msg not as expected during list creation", errors.contains("Invalid IntList name \"" + invalidListName + "\". IntList name must start with a letter or a number.")); + _listHelper.createList(PROJECT_VERIFY, listName, "key", new FieldDefinition(origFieldName, ColumnType.String).setLabel(origFieldName).setDescription("first column")); - EditListDefinitionPage listDefinitionPage = _listHelper.goToEditDesign(listName); + listDefinitionPage = _listHelper.goToEditDesign(listName); + listDefinitionPage.setName(invalidListName); + errors = listDefinitionPage.clickSaveExpectingErrors(); + Assert.assertTrue("Error msg not as expected during list renaming", errors.contains("Invalid IntList name \"" + invalidListName + "\". IntList name must start with a letter or a number.")); + listDefinitionPage.setName(listName); listDefinitionPage.getFieldsPanel() .getField(origFieldName) .setName(newFieldName) diff --git a/src/org/labkey/test/util/EscapeUtil.java b/src/org/labkey/test/util/EscapeUtil.java index d34cefab3c..04ea2811a5 100644 --- a/src/org/labkey/test/util/EscapeUtil.java +++ b/src/org/labkey/test/util/EscapeUtil.java @@ -102,6 +102,7 @@ public static String fieldKeyEncodePart(String str) str = StringUtils.replace(str, "}", "$B"); str = StringUtils.replace(str, "~", "$T"); str = StringUtils.replace(str, ",", "$C"); + str = StringUtils.replace(str, ".", "$P"); return str; } @@ -113,6 +114,7 @@ public static String fieldKeyDecodePart(String str) str = StringUtils.replace(str, "$A", "&"); str = StringUtils.replace(str, "$S", "/"); str = StringUtils.replace(str, "$D", "$"); + str = StringUtils.replace(str, "$P", "."); return str; } } diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 3c30be8a52..f5c22f11d9 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -68,6 +68,8 @@ public class TestDataGenerator // chose a Character random from this String public static final String CHARSET_STRING = "ABCDEFG01234abcdefvxyz~!@#$%^&*()-+=_{}[]|:;\"',.<>"; public static final String ALPHANUMERIC_STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvxyz"; + public static final String DOMAIN_SPECIAL_STRING = "+- _.:&()/"; + public static final String ILLEGAL_DOMAIN_NAME_CHARSET = "<>[]{};,`\"~!@#$%^*=|?\\"; private final Map _columns = new CaseInsensitiveLinkedHashMap<>(); private final Map> _dataSuppliers = new CaseInsensitiveHashMap<>(); @@ -328,6 +330,31 @@ public static String randomString(int size, @Nullable String exclusion, @Nullabl return val.toString(); } + public static String randomDomainName() + { + return randomDomainName(10); + } + + public static String randomInvalidDomainName(int size) + { + return randomString(size, null, ILLEGAL_DOMAIN_NAME_CHARSET); + } + + public static String randomDomainName(int size) + { + String domainName = ""; + do + { + String prefix = randomString(1, null, ALPHANUMERIC_STRING); // domain needs to start with alphanumeric char + final String charset = ALPHANUMERIC_STRING + DOMAIN_SPECIAL_STRING; + domainName = prefix + randomString(size - 1, null, charset); + domainName = domainName.trim(); + } + while (domainName.length() < size || Pattern.matches("(.*\\s--[^ ].*)|(.*\\s-[^- ].*)", domainName)); // domain name must not contain space followed by dash. (command like: Issue 49161) + + return domainName; + } + public static int randomInt(int min, int max) { if (min >= max)