Skip to content
35 changes: 24 additions & 11 deletions src/org/labkey/test/components/domain/AdvancedSettingsDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -170,16 +170,10 @@ public AdvancedSettingsDialog setRecommendedVariable(boolean checked)
return this;
}

public boolean isUniqueConstraint()
public AdvancedSettingsDialog setSingleFieldIndex(SingleFieldIndexType type)
{
return elementCache().uniqueConstraint.get();
}

public AdvancedSettingsDialog setUniqueConstraint(boolean checked)
{
elementCache().uniqueConstraint.set(checked);
getWrapper().waitFor(()-> elementCache().uniqueConstraint.get().equals(checked),
"uniqueConstraint checkbox was not set as expected", 1000);
if (type == null) type = SingleFieldIndexType.NO_INDEX;
elementCache().indexSelect.selectByVisibleText(type.getText());
return this;
}

Expand Down Expand Up @@ -214,6 +208,25 @@ public DomainFieldRow cancel()
return _row;
}

public enum SingleFieldIndexType
{
NO_INDEX("No Index"),
INDEX("Index"),
UNIQUE_INDEX("Index and require unique values");

private final String _text;

SingleFieldIndexType(String text)
{
_text = text;
}

public String getText()
{
return _text;
}
}

@Override
protected ElementCache newElementCache()
{
Expand Down Expand Up @@ -256,8 +269,8 @@ protected class ElementCache extends ModalDialog.ElementCache
Locator.input("domainpropertiesrow-recommendedVariable").findWhenNeeded(this));
public Checkbox enableMissingValues = new Checkbox(
Locator.input("domainpropertiesrow-mvEnabled").findWhenNeeded(this));
public Checkbox uniqueConstraint = new Checkbox(
Locator.input("domainpropertiesrow-uniqueConstraint").findWhenNeeded(this));
public Select indexSelect = SelectWrapper.Select(Locator.tagWithAttribute("select", "name", "domainpropertiesrow-singleFieldConstraint"))
.findWhenNeeded(this);
}

}
35 changes: 26 additions & 9 deletions src/org/labkey/test/tests/DataClassTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.labkey.test.TestFileUtils;
import org.labkey.test.WebTestHelper;
import org.labkey.test.categories.Daily;
import org.labkey.test.components.domain.AdvancedSettingsDialog;
import org.labkey.test.components.domain.BaseDomainDesigner;
import org.labkey.test.components.domain.DomainFormPanel;
import org.labkey.test.pages.core.admin.BaseSettingsPage.DATE_FORMAT;
Expand All @@ -49,6 +50,7 @@
public class DataClassTest extends BaseWebDriverTest
{
private static final String PROJECT_NAME = "DataClassTestProject";
boolean IS_POSTGRES = WebTestHelper.getDatabaseType() == WebTestHelper.DatabaseType.PostgreSQL;

@Override
public List<String> getAssociatedModules()
Expand Down Expand Up @@ -262,35 +264,40 @@ public void testFieldUniqueConstraint()
DomainFormPanel domainFormPanel = createPage.getDomainEditor();
domainFormPanel.manuallyDefineFields(fieldName1)
.setType(FieldDefinition.ColumnType.Integer)
.expand().clickAdvancedSettings().setUniqueConstraint(true).apply();
log("Add another field with a unique constraint");
.expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.UNIQUE_INDEX).apply();
log("Add another field with a non-unique constraint");
String fieldName2 = "fieldName_2";
domainFormPanel.addField(fieldName2)
.setType(FieldDefinition.ColumnType.DateAndTime)
.expand().clickAdvancedSettings().setUniqueConstraint(true).apply();
.expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.INDEX).apply();
log("Add another field which does not have a unique constraint");
String fieldName3 = "FieldName@3";
domainFormPanel.addField(fieldName3)
.setType(FieldDefinition.ColumnType.Boolean);
createPage.clickSave();

viewRawTableMetadata(dataClassName);
verifyTableIndices("unique_constraint_test_", List.of("field_name1", "fieldname_2"));
verifyTableIndices("unique_constraint_test_", List.of("field_Name1", "fieldName_2"));
assertTextNotPresent("unique_constraint_test_fieldname_3");
verifyTableIndexNonUnique("unique_constraint_test_", "field_Name1", true);
verifyTableIndexNonUnique("unique_constraint_test_", "fieldName_2", false);

log("Remove a field unique constraint and add a new one");
goToProjectHome();
CreateDataClassPage updatePage = goToDataClass(dataClassName);
domainFormPanel = updatePage.getDomainEditor();
domainFormPanel.getField(fieldName2)
.expand().clickAdvancedSettings().setUniqueConstraint(false)
domainFormPanel.getField(fieldName1)
.expand().clickAdvancedSettings().setSingleFieldIndex(null)
.apply();
domainFormPanel.getField(fieldName3)
.expand().clickAdvancedSettings().setUniqueConstraint(true)
.expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.UNIQUE_INDEX)
.apply();
updatePage.clickSave();
viewRawTableMetadata(dataClassName);
verifyTableIndices("unique_constraint_test_", List.of("field_name1", "fieldname_3"));
assertTextNotPresent("unique_constraint_test_fieldname_2");
verifyTableIndices("unique_constraint_test_", List.of("fieldName_2", "FieldName_3"));
assertTextNotPresent("unique_constraint_test_field_name1");
verifyTableIndexNonUnique("unique_constraint_test_", "fieldName_2", false);
verifyTableIndexNonUnique("unique_constraint_test_", "FieldName_3", true);
}

@Test
Expand Down Expand Up @@ -406,6 +413,16 @@ private void verifyTableIndices(String prefix, List<String> indexSuffixes)
assertTextPresentCaseInsensitive(prefix + suffix);
}

private void verifyTableIndexNonUnique(String prefix, String suffix, boolean isUnique)
{
String boolDisplay = isUnique ? "0" : "1";
if (IS_POSTGRES) boolDisplay = isUnique ? "false" : "true";
String fieldKey = prefix + suffix;
if (IS_POSTGRES) fieldKey = fieldKey.toLowerCase();
Locator locator = Locator.xpath("//td[contains(text(), '" + fieldKey + "')]/preceding-sibling::td[2][text()='" + boolDisplay + "']");
checker().verifyTrue("Non_Unique value not as expected in metadata for locator: " + locator, locator.existsIn(getDriver()));
}

private CreateDataClassPage goToCreateNewDataClass()
{
DataRegionTable drt = DataRegion(getDriver()).find();
Expand Down
33 changes: 25 additions & 8 deletions src/org/labkey/test/tests/SampleTypeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.labkey.test.categories.Daily;
import org.labkey.test.components.CustomizeView;
import org.labkey.test.components.assay.AssayConstants;
import org.labkey.test.components.domain.AdvancedSettingsDialog;
import org.labkey.test.components.domain.BaseDomainDesigner;
import org.labkey.test.components.domain.DomainFormPanel;
import org.labkey.test.components.ext4.Window;
Expand Down Expand Up @@ -105,6 +106,7 @@ public class SampleTypeTest extends BaseWebDriverTest
private static final String LOWER_CASE_SAMPLE_TYPE = CASE_INSENSITIVE_SAMPLE_TYPE.toLowerCase();
private static final String UPPER_CASE_SAMPLE_TYPE = CASE_INSENSITIVE_SAMPLE_TYPE.toUpperCase();
private static final TestUser USER_FOR_FILTERTEST = new TestUser("[email protected]");
boolean IS_POSTGRES = WebTestHelper.getDatabaseType() == WebTestHelper.DatabaseType.PostgreSQL;

@Override
public List<String> getAssociatedModules()
Expand Down Expand Up @@ -1825,40 +1827,45 @@ public void testFieldUniqueConstraint()
.goToCreateNewSampleType()
.setName(sampleTypeName);

log("Add a field with a unique constraint");
log("Add a field with a non-unique constraint");
String fieldName1 = "field Name1";
DomainFormPanel domainFormPanel = createPage.getFieldsPanel();
domainFormPanel.manuallyDefineFields(fieldName1)
.setType(ColumnType.Integer)
.expand().clickAdvancedSettings().setUniqueConstraint(true).apply();
.expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.INDEX).apply();
log("Add another field with a unique constraint");
String fieldName2 = "fieldName_2";
domainFormPanel.addField(fieldName2)
.setType(ColumnType.DateAndTime)
.expand().clickAdvancedSettings().setUniqueConstraint(true).apply();
.expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.UNIQUE_INDEX).apply();
log("Add another field which does not have a unique constraint");
String fieldName3 = "FieldName@3";
domainFormPanel.addField(fieldName3)
.setType(ColumnType.Boolean);
createPage.clickSave();

viewRawTableMetadata(sampleTypeName);
verifyTableIndices("unique_constraint_test_", List.of("field_name1", "fieldname_2"));
verifyTableIndices("unique_constraint_test_", List.of("field_Name1", "fieldName_2"));
assertTextNotPresent("unique_constraint_test_fieldname_3");
verifyTableIndexNonUnique("unique_constraint_test_", "field_Name1", false);
verifyTableIndexNonUnique("unique_constraint_test_", "fieldName_2", true);

log("Remove a field unique constraint and add a new one");
goToProjectHome();
UpdateSampleTypePage updatePage = sampleHelper.goToEditSampleType(sampleTypeName);
domainFormPanel = updatePage.getFieldsPanel();
domainFormPanel.getField(fieldName2)
.expand().clickAdvancedSettings().setUniqueConstraint(false)
.expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.INDEX)
.apply();
domainFormPanel.getField(fieldName3)
.expand().clickAdvancedSettings().setUniqueConstraint(true)
.expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.UNIQUE_INDEX)
.apply();
updatePage.clickSave();
viewRawTableMetadata(sampleTypeName);
verifyTableIndices("unique_constraint_test_", List.of("field_name1", "fieldname_3"));
assertTextNotPresent("unique_constraint_test_fieldname_2");
verifyTableIndices("unique_constraint_test_", List.of("field_name1", "FieldName_3"));
verifyTableIndexNonUnique("unique_constraint_test_", "field_Name1", false);
verifyTableIndexNonUnique("unique_constraint_test_", "fieldName_2", false);
verifyTableIndexNonUnique("unique_constraint_test_", "FieldName_3", true);
}

@Test
Expand Down Expand Up @@ -2020,6 +2027,16 @@ private void verifyTableIndices(String prefix, List<String> indexSuffixes)
assertTextPresentCaseInsensitive(prefix + suffix);
}

private void verifyTableIndexNonUnique(String prefix, String suffix, boolean isUnique)
{
String boolDisplay = isUnique ? "0" : "1";
if (IS_POSTGRES) boolDisplay = isUnique ? "false" : "true";
String fieldKey = prefix + suffix;
if (IS_POSTGRES) fieldKey = fieldKey.toLowerCase();
Locator locator = Locator.xpath("//td[contains(text(), '" + fieldKey + "')]/preceding-sibling::td[2][text()='" + boolDisplay + "']");
checker().verifyTrue("Non_Unique value not as expected in metadata for locator: " + locator, locator.existsIn(getDriver()));
}

private void setFileAttachment(int index, File attachment)
{
DataRegionTable drt = DataRegionTable.findDataRegionWithinWebpart(this, "Sample Type Contents");
Expand Down
49 changes: 37 additions & 12 deletions src/org/labkey/test/tests/list/ListTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.labkey.test.categories.Data;
import org.labkey.test.categories.Hosting;
import org.labkey.test.components.CustomizeView;
import org.labkey.test.components.domain.AdvancedSettingsDialog;
import org.labkey.test.components.domain.BaseDomainDesigner;
import org.labkey.test.components.domain.ConditionalFormatDialog;
import org.labkey.test.components.domain.DomainFieldRow;
Expand Down Expand Up @@ -101,6 +102,7 @@ public class ListTest extends BaseWebDriverTest
protected final static String LIST_NAME_HTML_KEY = "A_HtmlKey_" + DOMAIN_TRICKY_CHARACTERS;
protected final static ColumnType LIST_KEY_TYPE = ColumnType.String;
protected final static String LIST_KEY_NAME = "Key";
boolean IS_POSTGRES = WebTestHelper.getDatabaseType() == WebTestHelper.DatabaseType.PostgreSQL;

protected final static String LIST_KEY_NAME2 = "Color \"`~!@#$%^&*()_-+={}[]|\\:;<>,.?/";
protected final static String LIST_KEY_NAME2_BULK = "\"Color \"\"`~!@#$%^&*()_-+={}[]|\\:;<>,.?/\"";
Expand Down Expand Up @@ -1589,45 +1591,58 @@ public void testFieldUniqueConstraint()
viewRawTableMetadata(listName);
verifyTableIndices("unique_constraint_list_", Collections.emptyList());

// set two fields to have unique constraints
// set fields to have constraints
EditListDefinitionPage listDefinitionPage = _listHelper.goToEditDesign(listName);
listDefinitionPage.getFieldsPanel()
.getField(fieldName1).expand().clickAdvancedSettings().setUniqueConstraint(true)
.getField(fieldName1).expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.UNIQUE_INDEX)
.apply();
listDefinitionPage.getFieldsPanel()
.getField(fieldName2).expand().clickAdvancedSettings().setUniqueConstraint(true)
.getField(fieldName2).expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.UNIQUE_INDEX)
.apply();
// set one field to have non-unique constraint
listDefinitionPage.getFieldsPanel()
.getField(fieldName3).expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.INDEX)
.apply();
listDefinitionPage.clickSave();

AuditLogHelper.DetailedAuditEventRow expectedDomainEvent = new AuditLogHelper.DetailedAuditEventRow(null, listName, null,
"The descriptor of domain " + listName + " was updated.",
"", null, null, "Indices: > [field Name1, unique: true, fieldName_2, unique: true]");
"", null, null, "Indices: > [FieldName@3, unique: false, field Name1, unique: true, fieldName_2, unique: true]");
boolean pass = _auditLogHelper.validateLastDomainAuditEvents(listName, getProjectName(), expectedDomainEvent, Collections.emptyMap());
checker().verifyTrue("Domain audit comment not as expected after updating field unique constraint", pass);

viewRawTableMetadata(listName);
verifyTableIndices("unique_constraint_list_", List.of("field_name1", "fieldname_2"));
assertTextNotPresent("unique_constraint_list_fieldname_3");
verifyTableIndices("unique_constraint_list_", List.of("field_Name1", "fieldName_2", "FieldName_3"));
verifyTableIndexNonUnique("unique_constraint_list_", "field_Name1", true);
verifyTableIndexNonUnique("unique_constraint_list_", "fieldName_2", true);
verifyTableIndexNonUnique("unique_constraint_list_", "FieldName_3", false);

// remove a field unique constraint and add a new one
// remove a field unique constraint, change a field from unique -> non-unique, and change one from non-unique -> unique
listDefinitionPage = _listHelper.goToEditDesign(listName);
listDefinitionPage.getFieldsPanel()
.getField(fieldName2).expand().clickAdvancedSettings().setUniqueConstraint(false)
.getField(fieldName1).expand().clickAdvancedSettings().setSingleFieldIndex(null)
.apply();
listDefinitionPage.getFieldsPanel()
.getField(fieldName2).expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.INDEX)
.apply();
listDefinitionPage.getFieldsPanel()
.getField(fieldName3).expand().clickAdvancedSettings().setUniqueConstraint(true)
.getField(fieldName3).expand().clickAdvancedSettings().setSingleFieldIndex(AdvancedSettingsDialog.SingleFieldIndexType.UNIQUE_INDEX)
.apply();
listDefinitionPage.clickSave();

String expectedDataChanges = "Indices: [field name1, unique: true, fieldname@3, unique: false, fieldname_2, unique: true] > [FieldName@3, unique: true, fieldName_2, unique: false]";
if (!IS_POSTGRES) expectedDataChanges = "Indices: [FieldName@3, unique: false, field Name1, unique: true, fieldName_2, unique: true] > [FieldName@3, unique: true, fieldName_2, unique: false]";
expectedDomainEvent = new AuditLogHelper.DetailedAuditEventRow(null, listName, null,
"The descriptor of domain " + listName + " was updated.",
"", null, null, "Indices: [field name1, unique: true, fieldname_2, unique: true] > [FieldName@3, unique: true, field Name1, unique: true]");
"", null, null, expectedDataChanges);
pass = _auditLogHelper.validateLastDomainAuditEvents(listName, getProjectName(), expectedDomainEvent, Collections.emptyMap());
checker().verifyTrue("Domain audit comment not as expected after updating field unique constraint", pass);

viewRawTableMetadata(listName);
verifyTableIndices("unique_constraint_list_", List.of("field_name1", "fieldname_3"));
assertTextNotPresent("unique_constraint_list_fieldname_2");
verifyTableIndices("unique_constraint_list_", List.of("fieldName_2", "FieldName_3"));
assertTextNotPresent("unique_constraint_list_field_name1");
verifyTableIndexNonUnique("unique_constraint_list_", "fieldName_2", false);
verifyTableIndexNonUnique("unique_constraint_list_", "FieldName_3", true);
}

@Test // Issue 52247
Expand Down Expand Up @@ -1698,6 +1713,16 @@ private void verifyTableIndices(String prefix, List<String> indexSuffixes)
assertTextPresentCaseInsensitive(prefix + suffix);
}

private void verifyTableIndexNonUnique(String prefix, String suffix, boolean isUnique)
{
String boolDisplay = isUnique ? "0" : "1";
if (IS_POSTGRES) boolDisplay = isUnique ? "false" : "true";
String fieldKey = prefix + suffix;
if (IS_POSTGRES) fieldKey = fieldKey.toLowerCase();
Locator locator = Locator.xpath("//td[contains(text(), '" + fieldKey + "')]/preceding-sibling::td[2][text()='" + boolDisplay + "']");
checker().verifyTrue("Non_Unique value not as expected in metadata for locator: " + locator, locator.existsIn(getDriver()));
}

/**
* Test "tricky characters" in field names, including key field. This will test CrUD operation for list items in
* lists with an auto-key and user defined key. This will also use file import for validation.
Expand Down