From 0712b74721da84d7e5aa238f50240eff7be5e136 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Tue, 19 May 2026 15:18:31 -0700 Subject: [PATCH 1/6] Reserve column names in domain templates --- api/schemas/domainTemplate.xsd | 9 +++ .../api/exp/api/SampleTypeDomainKind.java | 1 + .../labkey/api/exp/property/DomainKind.java | 46 +++++++++++--- .../api/exp/property/DomainTemplate.java | 60 +++++++++++++------ .../experiment/api/DataClassDomainKind.java | 4 +- .../api/ExpDataClassDataTestCase.jsp | 29 ++++++++- .../org/labkey/list/model/ListDomainKind.java | 5 +- 7 files changed, 123 insertions(+), 31 deletions(-) diff --git a/api/schemas/domainTemplate.xsd b/api/schemas/domainTemplate.xsd index 12614675f79..e5472bfa5cc 100644 --- a/api/schemas/domainTemplate.xsd +++ b/api/schemas/domainTemplate.xsd @@ -46,6 +46,15 @@ + + + + Additional column names that should be considered reserved by the DomainKind for any + domain created from this template. These names are unioned with the DomainKind's + statically reserved set. + + + diff --git a/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java b/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java index 472427fbc1f..614ee2d1ff5 100644 --- a/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java +++ b/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java @@ -270,6 +270,7 @@ public Set getBaseProperties(Domain domain) public @NotNull Set getReservedPropertyNames(Domain domain, User user, boolean forCreate) { Set reserved = new CaseInsensitiveHashSet(RESERVED_NAMES); + reserved.addAll(getTemplateReservedPropertyNames(domain)); if (domain == null) { diff --git a/api/src/org/labkey/api/exp/property/DomainKind.java b/api/src/org/labkey/api/exp/property/DomainKind.java index da4cda6b2d0..860db419713 100644 --- a/api/src/org/labkey/api/exp/property/DomainKind.java +++ b/api/src/org/labkey/api/exp/property/DomainKind.java @@ -61,9 +61,9 @@ abstract public class DomainKind implements Handler abstract public String getKindName(); /** - * Return a class of DomainKind's bean which carries domain specific properties. - * This class will be used when marshalling/unmarshalling via Jackson during Create and Save/Update Domain - * @return Class of DomainKind's bean with domain specific properties + * Return a class of DomainKind's bean which carries domain-specific properties. + * This class will be used when marshaling/unmarshaling via Jackson during Create and Save/Update Domain + * @return Class of DomainKind's bean with domain-specific properties */ abstract public Class getTypeClass(); @@ -108,17 +108,47 @@ public Map processArguments(Container container, User user, Map< abstract public void deletePropertyDescriptor(Domain domain, User user, PropertyDescriptor pd); /** - * Return the set of names that should not be allowed for properties. E.g. - * the names of columns from the hard table underlying this type + * Return the set of names that should not be allowed for properties. E.g., the names of columns + * from the hard table underlying this type. + *

+ * Subclasses should typically override this method and union their kind-specific reserved set with + * {@link #getTemplateReservedPropertyNames(Domain)} (or with {@code super.getReservedPropertyNames(...)} + * when the override does not also override the {@code forCreate} variant). Doing so ensures that + * names declared in a {@code DomainTemplate}'s {@code } element are honored. + * * @return set of strings containing the names. This will be compared ignoring case */ - abstract public Set getReservedPropertyNames(Domain domain, User user); + public Set getReservedPropertyNames(Domain domain, User user) + { + return getTemplateReservedPropertyNames(domain); + } public Set getReservedPropertyNames(Domain domain, User user, boolean forCreate) { return getReservedPropertyNames(domain, user); } + /** + * Returns reserved column names declared in the {@link DomainTemplate} that this domain was created from + * (if any). These extend the kind's statically reserved set. + */ + @NotNull + protected Set getTemplateReservedPropertyNames(@Nullable Domain domain) + { + if (domain == null) + return Collections.emptySet(); + + TemplateInfo info = domain.getTemplateInfo(); + if (info == null) + return Collections.emptySet(); + + DomainTemplate template = DomainTemplate.findTemplate(info, getKindName()); + if (template == null) + return Collections.emptySet(); + + return template.getReservedColumnNames(); + } + public Set getReservedPropertyNamePrefixes() { return Collections.emptySet(); @@ -132,14 +162,14 @@ public Set getReservedPropertyNamePrefixes() abstract public Set getMandatoryPropertyNames(Domain domain); // CONSIDER: have DomainKind supply and IDomainInstance or similar - // so that it can hold instance data (e.g. a DatasetDefinition) + // so that it can hold instance data (e.g., a DatasetDefinition) /** * Get DomainKind specific properties. * @param domain The domain design. * @param container Container * @param user User - * @return Return object that holds DomainKind specific properties. + * @return Return an object that holds DomainKind specific properties. */ abstract public @Nullable T getDomainKindProperties(GWTDomain domain, Container container, User user); diff --git a/api/src/org/labkey/api/exp/property/DomainTemplate.java b/api/src/org/labkey/api/exp/property/DomainTemplate.java index 5eb5ec5b761..00788895d72 100644 --- a/api/src/org/labkey/api/exp/property/DomainTemplate.java +++ b/api/src/org/labkey/api/exp/property/DomainTemplate.java @@ -15,6 +15,7 @@ */ package org.labkey.api.exp.property; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlObject; @@ -60,7 +61,6 @@ import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; @@ -69,10 +69,6 @@ import java.util.Objects; import java.util.Set; -/** - * User: kevink - * Date: 1/6/16 - */ public class DomainTemplate { private final String _moduleName; @@ -83,6 +79,7 @@ public class DomainTemplate private final String _domainKind; private final GWTDomain _domain; private final Map _options; + private final Set _reservedColumnNames; private final InitialDataSettings _initialData; /** @@ -132,7 +129,7 @@ public static DomainTemplate parse(String moduleName, String groupName, DomainTe } catch (IllegalArgumentException ex) { - return new DomainTemplate(Objects.toString(templateName, ""), moduleName, groupName, Arrays.asList(ex.getMessage())); + return new DomainTemplate(Objects.toString(templateName, ""), moduleName, groupName, List.of(ex.getMessage())); } } @@ -148,8 +145,9 @@ private static DomainTemplate _parse(String templateName, String moduleName, Str throw new IllegalArgumentException("Unknown template domain kind"); List indices = getDomainTemplateUniqueIndices(templateName, template, properties); - Set mandatoryFieldNames = getDomainTemplateMandatoryFields(templateName, template, properties); + Set mandatoryFieldNames = getDomainTemplateMandatoryFields(template); Map options = getDomainTemplateOptions(templateName, template, properties); + Set reservedColumnNames = getDomainTemplateReservedColumnNames(template); GWTDomain domain = new GWTDomain<>(); domain.setName(templateName); @@ -162,17 +160,33 @@ private static DomainTemplate _parse(String templateName, String moduleName, Str return new DomainTemplate( templateName, groupName, moduleName, - domainKind, domain, options, + domainKind, domain, options, reservedColumnNames, importData ); } + private static Set getDomainTemplateReservedColumnNames(DomainTemplateType template) + { + if (!template.isSetReservedColumnNames()) + return Collections.emptySet(); + + CaseInsensitiveHashSet set = new CaseInsensitiveHashSet(); + for (String name : template.getReservedColumnNames().getColumnArray()) + { + String validName = StringUtils.trimToNull(name); + if (validName != null) + set.add(validName); + } + + return Collections.unmodifiableSet(set); + } + @Nullable private static String getDomainKind(String templateName, DomainTemplateType template, List properties) { List> domainKinds = PropertyService.get().getDomainKinds(); - for (DomainKind domainKind : domainKinds) + for (DomainKind domainKind : domainKinds) { if (domainKind.matchesTemplateXML(templateName, template, properties)) { @@ -198,7 +212,7 @@ private static List getDomainTemplateProperties(String te } } - return Collections.unmodifiableList(new ArrayList<>(properties.values())); + return List.copyOf(properties.values()); } private static List getDomainTemplateUniqueIndices(String templateName, DomainTemplateType template, List properties) @@ -227,7 +241,7 @@ private static List getDomainTemplateUniqueIndices(String templateName return Collections.unmodifiableList(indices); } - private static Set getDomainTemplateMandatoryFields(String templateName, DomainTemplateType template, List properties) + private static Set getDomainTemplateMandatoryFields(DomainTemplateType template) { CaseInsensitiveHashSet set = new CaseInsensitiveHashSet(); @@ -266,9 +280,9 @@ private static Map getDomainTemplateOptions(String templateName, { Map optionsMap = new HashMap<>(); - if (template instanceof ListTemplateType) + if (template instanceof ListTemplateType listTemplate) { - ListOptionsType options = ((ListTemplateType)template).getOptions(); + ListOptionsType options = listTemplate.getOptions(); String keyName = options.getKeyCol(); optionsMap.put("keyName", keyName); @@ -276,9 +290,9 @@ private static Map getDomainTemplateOptions(String templateName, if (options.isSetKeyType()) optionsMap.put("keyType", options.getKeyType()); } - else if (template instanceof DataClassTemplateType) + else if (template instanceof DataClassTemplateType dataClassTemplate) { - DataClassOptionsType options = ((DataClassTemplateType)template).getOptions(); + DataClassOptionsType options = dataClassTemplate.getOptions(); if (options != null) { optionsMap.put("nameExpression", options.getNameExpression()); @@ -288,9 +302,9 @@ else if (template instanceof DataClassTemplateType) optionsMap.put("category", options.getCategory()); } } - else if (template instanceof SampleSetTemplateType) + else if (template instanceof SampleSetTemplateType sampleTypeTemplate) { - SampleSetOptionsType options = ((SampleSetTemplateType)template).getOptions(); + SampleSetOptionsType options = sampleTypeTemplate.getOptions(); if (options != null) { optionsMap.put("nameExpression", options.getNameExpression()); @@ -338,8 +352,9 @@ private static InitialDataSettings getImportDataSettings(String templateName, Do } private DomainTemplate(@NotNull String name, @NotNull String groupName, @NotNull String moduleName, - @NotNull String domainKind, @NotNull GWTDomain domain, - @NotNull Map options, @Nullable InitialDataSettings initialData) + @NotNull String domainKind, @NotNull GWTDomain domain, + @NotNull Map options, @NotNull Set reservedColumnNames, + @Nullable InitialDataSettings initialData) { _moduleName = moduleName; _templateGroup = groupName; @@ -348,6 +363,7 @@ private DomainTemplate(@NotNull String name, @NotNull String groupName, @NotNull _errors = null; _domain = domain; _options = options; + _reservedColumnNames = reservedColumnNames; _initialData = initialData; } @@ -361,6 +377,7 @@ private DomainTemplate(@NotNull String name, @NotNull String groupName, @NotNull _domainKind = null; _domain = null; _options = null; + _reservedColumnNames = Collections.emptySet(); _initialData = null; } @@ -568,6 +585,11 @@ public Set getMandatoryPropertyNames() return _domain.getMandatoryFieldNames(); } + @NotNull + public Set getReservedColumnNames() + { + return _reservedColumnNames; + } private static class InitialDataSettings { diff --git a/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java b/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java index 3b9d5d1cc8e..097d4ea4df7 100644 --- a/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java +++ b/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java @@ -234,7 +234,9 @@ public Set getBaseProperties(Domain domain) @Override public @NotNull Set getReservedPropertyNames(Domain domain, User user) { - return RESERVED_NAMES; + Set reserved = new CaseInsensitiveHashSet(RESERVED_NAMES); + reserved.addAll(getTemplateReservedPropertyNames(domain)); + return reserved; } @Override diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp index 1d316902bd2..c2f946cae29 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp @@ -76,6 +76,7 @@ <%@ page import="org.labkey.api.query.QueryUpdateService" %> <%@ page import="org.labkey.api.query.SchemaKey" %> <%@ page import="org.labkey.api.query.UserSchema" %> +<%@ page import="org.labkey.api.query.ValidationException" %> <%@ page import="org.labkey.api.search.SearchService" %> <%@ page import="org.labkey.api.security.SecurityManager" %> <%@ page import="org.labkey.api.security.User" %> @@ -543,11 +544,37 @@ public void testDataClassFromTemplate() throws Exception assertEquals("TestingFromTemplate", t.getTemplateGroupName()); assertEquals("testingFromTemplate", t.getTableName()); - DomainKind kind = domain.getDomainKind(); + DomainKind kind = domain.getDomainKind(); assertTrue(kind instanceof DataClassDomainKind); Set mandatory = kind.getMandatoryPropertyNames(domain); assertTrue("Expected template to set 'aa' as mandatory: " + mandatory, mandatory.contains("aa")); + // Verify from the template are honored by the DomainKind + Set reservedNames = kind.getReservedPropertyNames(domain, user); + assertTrue("Expected template reserved name 'reservedOne' in: " + reservedNames, + reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("reservedOne"))); + assertTrue("Expected template reserved name 'ReservedTwo' in: " + reservedNames, + reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("ReservedTwo"))); + + // Attempt to add a field whose name collides with a template-reserved name (mixed case) + GWTDomain origGwt = DomainUtil.getDomainDescriptor(user, domain); + GWTDomain updateGwt = new GWTDomain<>(origGwt); + List updatedFields = new ArrayList<>(updateGwt.getFields()); + updatedFields.add(new GWTPropertyDescriptor("RESERVEDONE", "http://www.w3.org/2001/XMLSchema#string")); + updateGwt.setFields(updatedFields); + ValidationException ve = DomainUtil.updateDomainDescriptor(origGwt, updateGwt, c, user); + assertTrue("Expected a validation error when adding a reserved-name field", ve.hasErrors()); + assertTrue("Expected error message to flag the reserved name: " + ve.getMessage(), + ve.getMessage().toLowerCase().contains("reserved")); + + // A non-reserved field name should validate cleanly + GWTDomain okUpdate = new GWTDomain<>(origGwt); + List okFields = new ArrayList<>(okUpdate.getFields()); + okFields.add(new GWTPropertyDescriptor("nonReservedField", "http://www.w3.org/2001/XMLSchema#string")); + okUpdate.setFields(okFields); + ValidationException okVe = DomainUtil.validateProperties(domain, okUpdate, kind, origGwt, user); + assertFalse("Did not expect validation errors for a non-reserved field: " + okVe.getMessage(), okVe.hasErrors()); + ExpDataClassImpl dataClass = (ExpDataClassImpl)ExperimentService.get().getDataClass(c, domainName); assertNotNull(dataClass); diff --git a/list/src/org/labkey/list/model/ListDomainKind.java b/list/src/org/labkey/list/model/ListDomainKind.java index 8ae2881d322..a5e5a048b66 100644 --- a/list/src/org/labkey/list/model/ListDomainKind.java +++ b/list/src/org/labkey/list/model/ListDomainKind.java @@ -184,7 +184,6 @@ public Priority getPriority(String domainURI) return getKindName().equals(lsid.getNamespacePrefix()) ? Priority.MEDIUM : null; } - @Override public Set getBaseProperties(Domain domain) { @@ -250,7 +249,9 @@ public PropertyStorageSpec getPropertySpec(PropertyDescriptor pd, Domain domain) @Override public @NotNull Set getReservedPropertyNames(Domain domain, User user) { - return RESERVED_NAMES; + Set reserved = new CaseInsensitiveHashSet(RESERVED_NAMES); + reserved.addAll(getTemplateReservedPropertyNames(domain)); + return reserved; } @Override From 28554ba8074a45b63fe99e4529a1d33cdee81da0 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Wed, 20 May 2026 09:21:19 -0700 Subject: [PATCH 2/6] Reuse project --- .../api/ExpDataClassDataTestCase.jsp | 337 +++++++----------- 1 file changed, 134 insertions(+), 203 deletions(-) diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp index c2f946cae29..a0b697c7a84 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp @@ -96,7 +96,6 @@ <%@ page import="org.labkey.remoteapi.query.SelectRowsResponse" %> <%@ page import="java.sql.SQLException" %> <%@ page import="java.util.ArrayList" %> -<%@ page import="java.util.Arrays" %> <%@ page import="java.util.Collection" %> <%@ page import="java.util.Collections" %> <%@ page import="java.util.HashSet" %> @@ -111,43 +110,52 @@ <%@ page import="static org.labkey.api.util.IntegerUtils.asInteger" %> <%@ page import="static org.labkey.api.util.IntegerUtils.asLong" %> <%@ page import="static org.hamcrest.Matchers.containsString" %> +<%@ page import="org.junit.BeforeClass" %> +<%@ page import="org.junit.AfterClass" %> <%@ page extends="org.labkey.api.jsp.JspTest.BVT" %> <%! +static final String PROJECT_NAME = "_testDataClass"; ExpProvisionedTableTestHelper helper = new ExpProvisionedTableTestHelper(); Container c; +static User _user; + +@BeforeClass +public static void setUp() +{ + _user = TestContext.get().getUser(); +} @Before -public void setUp() +public void ensureProject() { - // NOTE: We need to use a project to create the DataClass so we can insert rows into sub-folders - c = ContainerManager.getForPath("_testDataClass"); - if (c != null) - ContainerManager.deleteAll(c, TestContext.get().getUser()); - c = ContainerManager.createContainer(ContainerManager.getRoot(), "_testDataClass", TestContext.get().getUser()); + // Some tests delete the project so ensure it is available for the next test + c = ContainerManager.ensureContainer(PROJECT_NAME, _user); } @After -public void tearDown() throws InterruptedException +public void drainQueue() throws InterruptedException { // Wait for the indexer to finish working on the data we just added to help avoid deadlocks SearchService.get().drainQueue(SearchService.PRIORITY.crawl, 15, TimeUnit.SECONDS); - ContainerManager.deleteAll(c, TestContext.get().getUser()); } +@AfterClass +public static void tearDown() +{ + Container project = ContainerManager.getForPath(PROJECT_NAME); + if (project != null) + ContainerManager.deleteAll(project, _user); +} // validate name is not null @Test public void nameNotNull() throws Exception { - final User user = TestContext.get().getUser(); - try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("foo", "string")); - - ExperimentServiceImpl.get().createDataClass(c, user, null, null, props, emptyList(), null, null); + List props = List.of(new GWTPropertyDescriptor("foo", "string")); + ExperimentServiceImpl.get().createDataClass(c, _user, null, null, props, emptyList(), null, null); } catch (ApiUsageException e) { @@ -158,14 +166,10 @@ public void nameNotNull() throws Exception @Test // Issue 51321 public void reservedNameFirst() throws Exception { - final User user = TestContext.get().getUser(); - try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("foo", "string")); - - ExperimentServiceImpl.get().createDataClass(c, user, "First", null, props, emptyList(), null, null); + List props = List.of(new GWTPropertyDescriptor("foo", "string")); + ExperimentServiceImpl.get().createDataClass(c, _user, "First", null, props, emptyList(), null, null); } catch (ApiUsageException e) { @@ -176,14 +180,10 @@ public void reservedNameFirst() throws Exception @Test // Issue 51321 public void reservedNameAll() throws Exception { - final User user = TestContext.get().getUser(); - try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("foo", "string")); - - ExperimentServiceImpl.get().createDataClass(c, user, "All", null, props, emptyList(), null, null); + List props = List.of(new GWTPropertyDescriptor("foo", "string")); + ExperimentServiceImpl.get().createDataClass(c, _user, "All", null, props, emptyList(), null, null); } catch (ApiUsageException e) { @@ -195,15 +195,11 @@ public void reservedNameAll() throws Exception @Test public void nameScale() throws Exception { - final User user = TestContext.get().getUser(); - try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("foo", "string")); - + List props = List.of(new GWTPropertyDescriptor("foo", "string")); String name = StringUtils.repeat("a", 1000); - ExperimentServiceImpl.get().createDataClass(c, user, name, null, props, emptyList(), null, null); + ExperimentServiceImpl.get().createDataClass(c, _user, name, null, props, emptyList(), null, null); } catch (ApiUsageException e) { @@ -215,17 +211,12 @@ public void nameScale() throws Exception @Test public void nameExpressionScale() throws Exception { - final User user = TestContext.get().getUser(); - try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("foo", "string")); - + List props = List.of(new GWTPropertyDescriptor("foo", "string")); DataClassDomainKindProperties options = new DataClassDomainKindProperties(); options.setNameExpression(StringUtils.repeat("a", 1000)); - - ExperimentServiceImpl.get().createDataClass(c, user, "testing", options, props, emptyList(), null, null); + ExperimentServiceImpl.get().createDataClass(c, _user, "testing", options, props, emptyList(), null, null); } catch (ApiUsageException e) { @@ -233,25 +224,21 @@ public void nameExpressionScale() throws Exception } } - @Test public void testDataClass() throws Exception { - final User user = TestContext.get().getUser(); - final Container sub = ContainerManager.createContainer(c, "sub", TestContext.get().getUser()); + final Container sub = ContainerManager.createContainer(c, "sub", _user); final String dataClassName = "testing"; - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("aa", "int")); - props.add(new GWTPropertyDescriptor("bb", "string")); - - List indices = new ArrayList<>(); - indices.add(new GWTIndex(Arrays.asList("aa"), true)); - + List props = List.of( + new GWTPropertyDescriptor("aa", "int"), + new GWTPropertyDescriptor("bb", "string") + ); + List indices = List.of(new GWTIndex(List.of("aa"), true)); DataClassDomainKindProperties options = new DataClassDomainKindProperties(); options.setNameExpression("JUNIT-${genId}-${aa}"); - final ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, user, dataClassName, options, props, indices, null, null); + final ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, dataClassName, options, props, indices, null, null); assertNotNull(dataClass); final Domain domain = dataClass.getDomain(); @@ -264,20 +251,16 @@ public void testDataClass() throws Exception String expectedSubName = "JUNIT-3-30"; testInsertIntoSubfolder(dataClass, table, sub, expectedSubName); testTruncateRows(dataClass, table, expectedName, expectedSubName); - testBulkImport(dataClass, table, user); - testInsertAliases(dataClass, table); - testEmptyInsert(dataClass, table, user); - testDeleteExpData(dataClass, user, 3); - testDeleteExpDataClass(dataClass, user, table, domain.getTypeURI()); + testBulkImport(dataClass, table); + testInsertAliases(table); + testEmptyInsert(table, _user); + testDeleteExpData(dataClass, _user, 3); + testDeleteExpDataClass(dataClass, _user, table, domain.getTypeURI()); } private void testNameExpressionGeneration(ExpDataClassImpl dataClass, TableInfo table, String expectedName) throws Exception { - List> rows = new ArrayList<>(); - Map row = new CaseInsensitiveHashMap<>(); - row.put("aa", 20); - row.put("bb", "hi"); - rows.add(row); + List> rows = List.of(CaseInsensitiveHashMap.of("aa", 20, "bb", "hi")); List> ret; try (DbScope.Transaction tx = table.getSchema().getScope().beginTransaction()) @@ -301,13 +284,8 @@ private void testNameExpressionGeneration(ExpDataClassImpl dataClass, TableInfo private void testInsertIntoSubfolder(ExpDataClassImpl dataClass, TableInfo table, Container sub, String expectedSubName) throws Exception { - List> rows = new ArrayList<>(); - Map row = new CaseInsensitiveHashMap<>(); - row.put("aa", 30); - row.put("bb", "bye"); String expectedComment = "waving in the wind"; - row.put("flag", expectedComment); - rows.add(row); + List> rows = List.of(CaseInsensitiveHashMap.of("aa", 30, "bb", "bye", "flag", expectedComment)); List> ret; try (DbScope.Transaction tx = table.getSchema().getScope().beginTransaction()) @@ -328,11 +306,7 @@ private void testInsertIntoSubfolder(ExpDataClassImpl dataClass, TableInfo table private void testInsertDuplicate(ExpDataClassImpl dataClass, TableInfo table) throws Exception { - List> rows = new ArrayList<>(); - Map row = new CaseInsensitiveHashMap<>(); - row.put("aa", 20); - row.put("bb", "bye"); - rows.add(row); + List> rows = List.of(CaseInsensitiveHashMap.of("aa", 20, "bb", "bye")); try (DbScope.Transaction tx = table.getSchema().getScope().beginTransaction()) { @@ -357,32 +331,24 @@ private void testTruncateRows(ExpDataClassImpl dataClass, TableInfo table, Strin { // TODO: truncate rows API doesn't support truncating from all containers //count = table.getUpdateService().truncateRows(user, c, null, null); - count = ExperimentServiceImpl.get().truncateDataClass(dataClass, TestContext.get().getUser(), null); + count = ExperimentServiceImpl.get().truncateDataClass(dataClass, _user, null); tx.commit(); } - assertEquals(2, count); + assertEquals(2, count); assertEquals(0, dataClass.getDatas().size()); assertNull(ExperimentService.get().getExpData(dataClass, expectedName)); assertNull(ExperimentService.get().getExpData(dataClass, expectedSubName)); } -private void testBulkImport(ExpDataClassImpl dataClass, TableInfo table, User user) throws Exception +private void testBulkImport(ExpDataClassImpl dataClass, TableInfo table) throws Exception { - List> rows = new ArrayList<>(); - Map row = new CaseInsensitiveHashMap<>(); - row.put("aa", 40); - row.put("bb", "qq"); - row.put("alias", "a"); - rows.add(row); + List> rows = List.of( + CaseInsensitiveHashMap.of("aa", 40, "bb", "qq", "alias", "a"), + CaseInsensitiveHashMap.of("aa", 50, "bb", "zz", "alias", "a,b,c") + ); - row = new CaseInsensitiveHashMap<>(); - row.put("aa", 50); - row.put("bb", "zz"); - row.put("alias", "a,b,c"); - rows.add(row); - - int count = table.getUpdateService().loadRows(user, c, MapDataIterator.of(rows), new DataIteratorContext(), null); + int count = table.getUpdateService().loadRows(_user, c, MapDataIterator.of(rows), new DataIteratorContext(), null); assertEquals(2, count); assertEquals(2, dataClass.getDatas().size()); @@ -422,24 +388,19 @@ private void testDeleteExpDataClass(ExpDataClassImpl dataClass, User user, Table assertNull(dbTable); } -private void testInsertAliases(ExpDataClassImpl dataClass, TableInfo table) throws Exception +private void testInsertAliases(TableInfo table) throws Exception { - List> rows = new ArrayList<>(); - Map row = new CaseInsensitiveHashMap<>(); - row.put("aa", 20); - row.put("bb", "bye"); - row.put("alias", "aa,bb"); - rows.add(row); + Map row = CaseInsensitiveHashMap.of("aa", 20, "bb", "bye", "alias", "aa,bb"); long insertedRowId; try (DbScope.Transaction tx = table.getSchema().getScope().beginTransaction()) { - List> ret = helper.insertRows(c, rows, table.getName()); + List> ret = helper.insertRows(c, List.of(row), table.getName()); insertedRowId = asLong(ret.getFirst().get("rowId")); tx.commit(); } - verifyAliases(table, insertedRowId, Set.of("aa","bb")); + verifyAliases(table, insertedRowId, Set.of("aa", "bb")); } private void verifyAliases(TableInfo table, long expDataRowId, Set expectedAliases) throws Exception @@ -497,11 +458,10 @@ private void verifyAliasesViaSelectRows(String schemaName, String queryName, lon } // Issue 35013: Importing a file with zero rows into a DataClass results in NPE -private void testEmptyInsert(ExpDataClassImpl dataClass, TableInfo table, User user) throws Exception +private void testEmptyInsert(TableInfo table, User user) throws Exception { - List> rows = new ArrayList<>(); BatchValidationException errors = new BatchValidationException(); - int count = table.getUpdateService().importRows(user, c, MapDataIterator.of(rows), errors, null, null); + int count = table.getUpdateService().importRows(user, c, MapDataIterator.of(List.of()), errors, null, null); if (errors.hasErrors()) throw errors; assertEquals(0, count); @@ -510,22 +470,10 @@ private void testEmptyInsert(ExpDataClassImpl dataClass, TableInfo table, User u @Test public void testDataClassFromTemplate() throws Exception { - if (!AppProps.getInstance().isDevMode()) // Skip test in production mode if necessary modules are not available - { - Assume.assumeTrue("List module is required to test data class templates", ModuleLoader.getInstance().getModule("list") != null); - Assume.assumeTrue("simpletest module is required to test data class templates", ModuleLoader.getInstance().getModule("simpletest") != null); - } - - final User user = TestContext.get().getUser(); - final Container sub = ContainerManager.createContainer(c, "sub2", TestContext.get().getUser()); + requireSimpleTestModule(); + final Container sub = ContainerManager.createContainer(c, "sub2", _user); final String domainName = "mydataclass"; - Set activeModules = new HashSet<>(c.getActiveModules()); - Module m = ModuleLoader.getInstance().getModule("simpletest"); - assertNotNull("This test requires 'simplemodule' to be deployed", m); - activeModules.add(m); - c.setActiveModules(activeModules); - DomainTemplateGroup templateGroup = DomainTemplateGroup.get(c, "TestingFromTemplate"); assertNotNull(templateGroup); assertFalse( @@ -535,7 +483,7 @@ public void testDataClassFromTemplate() throws Exception DomainTemplate template = templateGroup.getTemplate("testingFromTemplate"); assertNotNull(template); - final Domain domain = template.createAndImport(c, user, domainName, true, false); + final Domain domain = template.createAndImport(c, _user, domainName, true, false); assertNotNull(domain); TemplateInfo t = domain.getTemplateInfo(); @@ -550,19 +498,19 @@ public void testDataClassFromTemplate() throws Exception assertTrue("Expected template to set 'aa' as mandatory: " + mandatory, mandatory.contains("aa")); // Verify from the template are honored by the DomainKind - Set reservedNames = kind.getReservedPropertyNames(domain, user); + Set reservedNames = kind.getReservedPropertyNames(domain, _user); assertTrue("Expected template reserved name 'reservedOne' in: " + reservedNames, reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("reservedOne"))); assertTrue("Expected template reserved name 'ReservedTwo' in: " + reservedNames, reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("ReservedTwo"))); // Attempt to add a field whose name collides with a template-reserved name (mixed case) - GWTDomain origGwt = DomainUtil.getDomainDescriptor(user, domain); + GWTDomain origGwt = DomainUtil.getDomainDescriptor(_user, domain); GWTDomain updateGwt = new GWTDomain<>(origGwt); List updatedFields = new ArrayList<>(updateGwt.getFields()); updatedFields.add(new GWTPropertyDescriptor("RESERVEDONE", "http://www.w3.org/2001/XMLSchema#string")); updateGwt.setFields(updatedFields); - ValidationException ve = DomainUtil.updateDomainDescriptor(origGwt, updateGwt, c, user); + ValidationException ve = DomainUtil.updateDomainDescriptor(origGwt, updateGwt, c, _user); assertTrue("Expected a validation error when adding a reserved-name field", ve.hasErrors()); assertTrue("Expected error message to flag the reserved name: " + ve.getMessage(), ve.getMessage().toLowerCase().contains("reserved")); @@ -572,14 +520,14 @@ public void testDataClassFromTemplate() throws Exception List okFields = new ArrayList<>(okUpdate.getFields()); okFields.add(new GWTPropertyDescriptor("nonReservedField", "http://www.w3.org/2001/XMLSchema#string")); okUpdate.setFields(okFields); - ValidationException okVe = DomainUtil.validateProperties(domain, okUpdate, kind, origGwt, user); + ValidationException okVe = DomainUtil.validateProperties(domain, okUpdate, kind, origGwt, _user); assertFalse("Did not expect validation errors for a non-reserved field: " + okVe.getMessage(), okVe.hasErrors()); ExpDataClassImpl dataClass = (ExpDataClassImpl)ExperimentService.get().getDataClass(c, domainName); assertNotNull(dataClass); // add ConceptURI mappings for this container - String listName = createConceptLookupList(c, user); + String listName = createConceptLookupList(c, _user); Lookup lookup = new Lookup(c, "lists", listName); ConceptURIProperties.setLookup(c, "http://cpas.labkey.com/Experiment#Testing", lookup); @@ -597,9 +545,9 @@ public void testDataClassFromTemplate() throws Exception String expectedSubName = "TEST-3-30"; testInsertIntoSubfolder(dataClass, table, sub, expectedSubName); testTruncateRows(dataClass, table, expectedName, expectedSubName); - testBulkImport(dataClass, table, user); - testDeleteExpData(dataClass, user, 2); - testDeleteExpDataClass(dataClass, user, table, domain.getTypeURI()); + testBulkImport(dataClass, table); + testDeleteExpData(dataClass, _user, 2); + testDeleteExpDataClass(dataClass, _user, table, domain.getTypeURI()); } private String createConceptLookupList(Container c, User user) throws Exception @@ -610,44 +558,26 @@ private String createConceptLookupList(Container c, User user) throws Exception list.getDomain().addProperty(new PropertyStorageSpec("Key", JdbcType.INTEGER)); list.getDomain().addProperty(new PropertyStorageSpec("Value", JdbcType.VARCHAR)); list.save(user); - List lis = new ArrayList<>(); ListItem li = list.createListItem(); li.setProperty(list.getDomain().getPropertyByName("Key"), 20); li.setProperty(list.getDomain().getPropertyByName("Value"), "Value 20"); - lis.add(li); - list.insertListItems(user, c, lis); + list.insertListItems(user, c, List.of(li)); return listName; } - @Test public void testDomainTemplate() throws Exception { - if (!AppProps.getInstance().isDevMode()) // Skip test in production mode if necessary modules are not available - { - Assume.assumeTrue("List module is required to test domain templates", ModuleLoader.getInstance().getModule("list") != null); - Assume.assumeTrue("simpletest module is required to test domain templates", ModuleLoader.getInstance().getModule("simpletest") != null); - } - - final User user = TestContext.get().getUser(); - final Container sub = ContainerManager.createContainer(c, "sub3", user); - - Set activeModules = new HashSet<>(c.getActiveModules()); - Module m = ModuleLoader.getInstance().getModule("simpletest"); - assertNotNull("This test requires 'simplemodule' to be deployed", m); - activeModules.add(m); - c.setActiveModules(activeModules); - + requireSimpleTestModule(); + final Container sub = ContainerManager.createContainer(c, "sub3", _user); DomainTemplateGroup templateGroup = DomainTemplateGroup.get(c, "todolist"); assertNotNull(templateGroup); - assertFalse( - "Errors in template: " + StringUtils.join(templateGroup.getErrors(), ", "), - templateGroup.hasErrors()); + assertFalse("Errors in template: " + StringUtils.join(templateGroup.getErrors(), ", "), templateGroup.hasErrors()); - List created = templateGroup.createAndImport(sub, user, true, true); + List created = templateGroup.createAndImport(sub, _user, true, true); // verify the "Priority" list was created and data was imported - UserSchema listSchema = QueryService.get().getUserSchema(user, sub, "lists"); + UserSchema listSchema = QueryService.get().getUserSchema(_user, sub, "lists"); TableInfo priorityTable = listSchema.getTable("Priority"); Collection> priorities = new TableSelector(priorityTable).getMapCollection(); @@ -665,7 +595,7 @@ public void testDomainTemplate() throws Exception try (DbScope.Transaction tx = priorityTable.getSchema().getScope().beginTransaction()) { BatchValidationException errors = new BatchValidationException(); - ret = priorityTable.getUpdateService().insertRows(user, sub, rows, errors, null, null); + ret = priorityTable.getUpdateService().insertRows(_user, sub, rows, errors, null, null); if (errors.hasErrors()) throw errors; tx.commit(); @@ -693,7 +623,7 @@ public void testDomainTemplate() throws Exception try (DbScope.Transaction tx = milestoneTable.getSchema().getScope().beginTransaction()) { BatchValidationException errors = new BatchValidationException(); - ret = milestoneTable.getUpdateService().insertRows(user, sub, rows, errors, null, null); + ret = milestoneTable.getUpdateService().insertRows(_user, sub, rows, errors, null, null); if (errors.hasErrors()) throw errors; tx.commit(); @@ -705,7 +635,7 @@ public void testDomainTemplate() throws Exception } // verify the "TodoList" DataClass was created and data was imported - UserSchema expSchema = QueryService.get().getUserSchema(user, sub, helper.expDataSchemaKey); + UserSchema expSchema = QueryService.get().getUserSchema(_user, sub, helper.expDataSchemaKey); TableInfo table = expSchema.getTable("TodoList"); assertNotNull("data class not in query schema", table); @@ -718,22 +648,20 @@ public void testDomainTemplate() throws Exception ExpData data = ExperimentServiceImpl.get().getExpData(dataClass, "TODO-1"); Collection aliases = data.getAliases(); - assertTrue("Expected aliases to contain 'xsd' and 'domain templates', got: " + aliases, aliases.containsAll(Arrays.asList("xsd", "domain templates"))); + assertTrue("Expected aliases to contain 'xsd' and 'domain templates', got: " + aliases, aliases.containsAll(List.of("xsd", "domain templates"))); } - // Issue 25224: NPE trying to delete a folder with a DataClass with at least one result row in it @Test public void testContainerDelete() throws Exception { - final User user = TestContext.get().getUser(); - final Container sub = ContainerManager.createContainer(c, "sub", user); + final Container sub = ContainerManager.createContainer(c, "sub", _user); final String dataClassName = "testing"; List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("aa", "int")); - final ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, user, dataClassName, null, props, emptyList(), null, null); + final ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, dataClassName, null, props, emptyList(), null, null); final long dataClassId = dataClass.getRowId(); TableInfo table = getDataClassTable(dataClassName); @@ -791,7 +719,7 @@ public void testContainerDelete() throws Exception assertNotNull(dbTable); // delete - ContainerManager.deleteAll(c, user); + ContainerManager.deleteAll(c, _user); // verify deleted assertNull(ExperimentServiceImpl.get().getDataClass(dataClassId)); @@ -807,19 +735,17 @@ public void testContainerDelete() throws Exception @Test public void testLargeUniqueOnSingleColumnOnly() throws ExperimentException { - final User user = TestContext.get().getUser(); - List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("aa", "int")); props.add(new GWTPropertyDescriptor("bb", "multiLine")); List indices = new ArrayList<>(); - indices.add(new GWTIndex(Arrays.asList("aa", "bb"), true)); + indices.add(new GWTIndex(List.of("aa", "bb"), true)); boolean sqlServer = ExperimentService.get().getSchema().getSqlDialect().isSqlServer(); try { - final ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, user, "largeUnique", null, props, indices, null, null); + final ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, "largeUnique", null, props, indices, null, null); if (sqlServer) fail("Expected exception creating large index over two columns"); } @@ -835,8 +761,6 @@ public void testLargeUniqueOnSingleColumnOnly() throws ExperimentException @Test public void testLargeUnique() throws Exception { - final User user = TestContext.get().getUser(); - boolean sqlServer = ExperimentService.get().getSchema().getSqlDialect().isSqlServer(); List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("aa", "int")); @@ -844,23 +768,21 @@ public void testLargeUnique() throws Exception prop.setScale(20000); props.add(prop); - List indices = new ArrayList<>(); - indices.add(new GWTIndex(Arrays.asList("bb"), true)); - + List indices = List.of(new GWTIndex(List.of("bb"), true)); DataClassDomainKindProperties options = new DataClassDomainKindProperties(); options.setNameExpression("JUNIT-${genId}-${aa}"); ExpDataClassImpl dataClass; try { - dataClass = ExperimentServiceImpl.get().createDataClass(c, user, "largeUnique2", options, props, indices, null, null); + dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, "largeUnique2", options, props, indices, null, null); } catch (IllegalArgumentException e) { // Not supported on SQL Server, so create with no indices assertTrue("Expected exception creating large index over two columns", e.getMessage().contains("Index over large columns is not supported")); assertTrue(sqlServer); - dataClass = ExperimentServiceImpl.get().createDataClass(c, user, "largeUnique2", options, props, List.of(), null, null); + dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, "largeUnique2", options, props, List.of(), null, null); } List> rows = new ArrayList<>(); @@ -906,22 +828,20 @@ private ArrayListMap newArrayListMap() @Test public void testDataClassWithVocabularyProperties() throws Exception { - User user = TestContext.get().getUser(); - String dataClassName = "DataClassesWithVocabularyProperties"; int dataClassAge = 2; int updatedDataClassAge = 4; String dataClassType = "TypeB"; String dataClassColor = "Orange"; - Domain testDomain = helper.createVocabularyTestDomain(user, c); + Domain testDomain = helper.createVocabularyTestDomain(_user, c); Map vocabularyPropertyURIs = helper.getVocabularyPropertyURIS(testDomain); final String colorPropertyURI = vocabularyPropertyURIs.get(ExpProvisionedTableTestHelper.colorPropertyName); final String agePropertyURI = vocabularyPropertyURIs.get(ExpProvisionedTableTestHelper.agePropertyName); final String typePropertyURI = vocabularyPropertyURIs.get(ExpProvisionedTableTestHelper.typePropertyName); - ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, user, dataClassName, null, + ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, dataClassName, null, List.of(new GWTPropertyDescriptor("OtherProp", "string")), emptyList(), null, null); assertNotNull(dataClass); @@ -981,17 +901,15 @@ public void testDataClassWithVocabularyProperties() throws Exception @Test public void testViewSupportForVocabularyDomains() throws Exception { - User user = TestContext.get().getUser(); - // Create a sample type with name String sampleName = "CarLocations"; String sampleOneLocation = "California"; - ExpSampleTypeImpl st = SampleTypeServiceImpl.get().createSampleType(c, user, + ExpSampleTypeImpl st = SampleTypeServiceImpl.get().createSampleType(c, _user, sampleName, null, List.of(new GWTPropertyDescriptor("name", "string")), emptyList(), -1, -1, -1, -1, null, null); - UserSchema schema = QueryService.get().getUserSchema(user, c, SchemaKey.fromParts("Samples")); + UserSchema schema = QueryService.get().getUserSchema(_user, c, SchemaKey.fromParts("Samples")); // Insert a sample into sample type ArrayListMap row = newArrayListMap(); @@ -1016,12 +934,12 @@ public void testViewSupportForVocabularyDomains() throws Exception prop1.setLookupSchema(lookUpSchema); prop1.setLookupQuery(sampleName); - GWTDomain domain = new GWTDomain(); + GWTDomain domain = new GWTDomain<>(); domain.setName(domainName); domain.setDescription(domainDescription); domain.setFields(List.of(prop1)); - Domain lookUpDomain = DomainUtil.createDomain("Vocabulary", domain, null, c, user, domainName, null, false); + Domain lookUpDomain = DomainUtil.createDomain("Vocabulary", domain, null, c, _user, domainName, null, false); Map vocabularyPropertyURIs = helper.getVocabularyPropertyURIS(lookUpDomain); final String locationPropertyURI = vocabularyPropertyURIs.get(locationPropertyName); @@ -1030,10 +948,10 @@ public void testViewSupportForVocabularyDomains() throws Exception String dataClassName = "CarsDataClasses"; String carName1 = "Tesla"; - ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, user, dataClassName, null, + ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, dataClassName, null, List.of(new GWTPropertyDescriptor("OtherProp", "string")), emptyList(), null, null); - UserSchema userSchema = QueryService.get().getUserSchema(user, c, helper.expDataSchemaKey); + UserSchema userSchema = QueryService.get().getUserSchema(_user, c, helper.expDataSchemaKey); // insert a data class with vocab look up prop using row id of inserted sample ArrayListMap rowToInsert = newArrayListMap(); @@ -1063,7 +981,6 @@ public void testViewSupportForVocabularyDomains() throws Exception @Test public void testInsertOptionUpdate() throws Exception { - final User user = TestContext.get().getUser(); final String dataClassName = "DataClassWithImportOption"; List props = new ArrayList<>(); @@ -1072,7 +989,7 @@ public void testInsertOptionUpdate() throws Exception String longFieldName = "Field100 ABCDEFGHIJKLMNOPQRSTUVWXYZ%()=+-[]_|*`'\":;<>?!@#^AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSSTTU)"; props.add(new GWTPropertyDescriptor(longFieldName, "string")); - ExpDataClass dataClass = ExperimentServiceImpl.get().createDataClass(c, user, dataClassName, null, props, emptyList(), null, null); + ExpDataClass dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, dataClassName, null, props, emptyList(), null, null); List> rowsToAdd = new ArrayList<>(); rowsToAdd.add(CaseInsensitiveHashMap.of("name", "D-1", "prop", "a", longFieldName, "Very", "alias", "Much", "flag", "c100")); rowsToAdd.add(CaseInsensitiveHashMap.of("name", "D-1-d", "prop", "c", longFieldName, "Long", "alias", "Extended", "flag", "c200")); @@ -1088,7 +1005,7 @@ public void testInsertOptionUpdate() throws Exception DataIteratorContext context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.IMPORT); - var count = qus.loadRows(user, c, MapDataIterator.of(rowsToAdd), context, null); + var count = qus.loadRows(_user, c, MapDataIterator.of(rowsToAdd), context, null); assertFalse(context.getErrors().hasErrors()); assertEquals(3, count); @@ -1105,7 +1022,7 @@ public void testInsertOptionUpdate() throws Exception context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.UPDATE); - count = qus.loadRows(user, c, MapDataIterator.of(rowsToUpdate), context, null); + count = qus.loadRows(_user, c, MapDataIterator.of(rowsToUpdate), context, null); assertFalse(context.getErrors().hasErrors()); assertEquals(3, count); @@ -1115,7 +1032,7 @@ public void testInsertOptionUpdate() throws Exception rowsToUpdate.add(CaseInsensitiveHashMap.of("rowId", dataClass.getData(c, "D-1").getRowId(), "DataInputs/DataClassWithImportOption", "D-1-d")); try { - qus.updateRows(user, c, rowsToUpdate, null, new BatchValidationException(), null, null); + qus.updateRows(_user, c, rowsToUpdate, null, new BatchValidationException(), null, null); fail("Expected to throw exception"); } catch (Exception e) @@ -1137,7 +1054,7 @@ public void testInsertOptionUpdate() throws Exception String aliasAlias = "alias"; String flagAlias = "flag$"; - List> rows = Arrays.asList(ts.getMapArray()); + List> rows = List.of(ts.getMapArray()); assertEquals("D-1", rows.get(0).get("Name")); assertEquals("D-1-d", rows.get(1).get("Name")); @@ -1174,7 +1091,7 @@ public void testInsertOptionUpdate() throws Exception context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.MERGE); - count = qus.loadRows(user, c, MapDataIterator.of(rowsToMerge), context, null); + count = qus.loadRows(_user, c, MapDataIterator.of(rowsToMerge), context, null); assertFalse(context.getErrors().hasErrors()); assertEquals(2, count); @@ -1182,7 +1099,7 @@ public void testInsertOptionUpdate() throws Exception ts = new TableSelector(table, columnNames, null, new Sort("Name")); ts.setForDisplay(true); - rows = Arrays.asList(ts.getMapArray()); + rows = List.of(ts.getMapArray()); assertEquals(4, rows.size()); assertEquals("D-1", rows.get(0).get("Name")); @@ -1218,33 +1135,26 @@ public void testInsertOptionUpdate() throws Exception assertEquals("cEight", rows.get(3).get(flagAlias)); } -private @NotNull TableInfo getDataClassTable(String dataClassName) -{ - UserSchema schema = QueryService.get().getUserSchema(TestContext.get().getUser(), c, ExpSchema.SCHEMA_EXP_DATA); - return schema.getTableOrThrow(dataClassName); -} - @Test // Issue 52886 public void testUpdateAuditForLongField() throws Exception { - User user = TestContext.get().getUser(); - String dataClassName = "DataClassesWithLongFields"; String fieldName = "longField " + StringUtils.repeat("AB CD", 20); - ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, user, dataClassName, null, + ExpDataClassImpl dataClass = ExperimentServiceImpl.get().createDataClass(c, _user, dataClassName, null, List.of(new GWTPropertyDescriptor(fieldName, "string")), emptyList(), null, null); assertNotNull(dataClass); - List> rowsToAdd = new ArrayList<>(); - rowsToAdd.add(CaseInsensitiveHashMap.of("name", "A-1", "prop", "a", fieldName, "Initial")); + List> rowsToAdd = List.of( + CaseInsensitiveHashMap.of("name", "A-1", "prop", "a", fieldName, "Initial") + ); TableInfo table = getDataClassTable(dataClassName); QueryUpdateService qus = table.getUpdateService(); assertNotNull(qus); DataIteratorContext context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.IMPORT); context.getConfigParameters().put(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, AuditBehaviorType.DETAILED); - var count = qus.loadRows(user, c, MapDataIterator.of(rowsToAdd), context, null); + var count = qus.loadRows(_user, c, MapDataIterator.of(rowsToAdd), context, null); assertFalse("Unexpected errors from import", context.getErrors().hasErrors()); assertEquals("Number of rows inserted not as expected", 1, count); for (Map row : rowsToAdd) @@ -1256,12 +1166,12 @@ public void testUpdateAuditForLongField() throws Exception if (results.next()) { rowId = results.getInt(FieldKey.fromParts("RowId")); - row.put("RowId", rowId); // intentional side-effect to help in retrieving update events as well + row.put("RowId", rowId); // intentional side effect to help in retrieving update events as well SimpleFilter filter = SimpleFilter.createContainerFilter(c); filter.addCondition(FieldKey.fromParts("rowPk"), String.valueOf(rowId)); filter.addCondition(FieldKey.fromParts("queryName"), dataClassName); - List events = AuditLogService.get().getAuditEvents(c, user, "QueryUpdateAuditEvent", filter, null); + List events = AuditLogService.get().getAuditEvents(c, _user, "QueryUpdateAuditEvent", filter, null); assertEquals("Number of audit events not as expected", 1, events.size()); } } @@ -1272,7 +1182,7 @@ public void testUpdateAuditForLongField() throws Exception context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.UPDATE); context.getConfigParameters().put(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, AuditBehaviorType.DETAILED); - count = qus.loadRows(user, c, MapDataIterator.of(rowsToUpdate), context, null); + count = qus.loadRows(_user, c, MapDataIterator.of(rowsToUpdate), context, null); assertFalse("Unexpected errors from update", context.getErrors().hasErrors()); assertEquals("Number of rows updated not as expected", 1, count); @@ -1281,10 +1191,31 @@ public void testUpdateAuditForLongField() throws Exception SimpleFilter filter = SimpleFilter.createContainerFilter(c); filter.addCondition(FieldKey.fromParts("rowPk"), String.valueOf(row.get("rowId"))); filter.addCondition(FieldKey.fromParts("queryName"), dataClassName); - List events = AuditLogService.get().getAuditEvents(c, user, "QueryUpdateAuditEvent", filter, new Sort("-RowId")); + List events = AuditLogService.get().getAuditEvents(c, _user, "QueryUpdateAuditEvent", filter, new Sort("-RowId")); assertEquals("Number of audit events not as expected", 2, events.size()); // should have one for insert and one for update String oldRecordMap = ((DetailedAuditTypeEvent) events.getFirst()).getOldRecordMap(); assertTrue("Old record map (" + oldRecordMap + ") does not contain expected field", oldRecordMap.contains(encodeURIComponent(fieldName) + "=Initial")); } } + +private @NotNull TableInfo getDataClassTable(String dataClassName) +{ + UserSchema schema = QueryService.get().getUserSchema(_user, c, ExpSchema.SCHEMA_EXP_DATA); + return schema.getTableOrThrow(dataClassName); +} + +private void requireSimpleTestModule() +{ + if (!AppProps.getInstance().isDevMode()) // Skip test in production mode if necessary modules are not available + { + Assume.assumeTrue("List module is required to test data class templates", ModuleLoader.getInstance().getModule("list") != null); + Assume.assumeTrue("simpletest module is required to test data class templates", ModuleLoader.getInstance().getModule("simpletest") != null); + } + + Set activeModules = new HashSet<>(c.getActiveModules()); + Module m = ModuleLoader.getInstance().getModule("simpletest"); + assertNotNull("This test requires 'simpletest' module to be deployed", m); + activeModules.add(m); + c.setActiveModules(activeModules); +} %> From 7bbbc31cfde241fad3c0d09ddbca96586a3a8d76 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Wed, 20 May 2026 10:14:31 -0700 Subject: [PATCH 3/6] Sample type test --- .../api/ExpDataClassDataTestCase.jsp | 21 +- .../api/ExpProvisionedTableTestHelper.java | 23 +- .../experiment/api/ExpSampleTypeTestCase.jsp | 344 +++++++++--------- 3 files changed, 203 insertions(+), 185 deletions(-) diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp index a0b697c7a84..c7d6fd4aed9 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp @@ -17,7 +17,6 @@ <%@ page import="org.apache.commons.lang3.StringUtils" %> <%@ page import="org.jetbrains.annotations.NotNull" %> <%@ page import="org.junit.After" %> -<%@ page import="org.junit.Assume" %> <%@ page import="org.junit.Before" %> <%@ page import="org.junit.Test" %> <%@ page import="org.labkey.api.action.ApiUsageException" %> @@ -67,8 +66,6 @@ <%@ page import="org.labkey.api.gwt.client.model.GWTDomain" %> <%@ page import="org.labkey.api.gwt.client.model.GWTIndex" %> <%@ page import="org.labkey.api.gwt.client.model.GWTPropertyDescriptor" %> -<%@ page import="org.labkey.api.module.Module" %> -<%@ page import="org.labkey.api.module.ModuleLoader" %> <%@ page import="org.labkey.api.query.BatchValidationException" %> <%@ page import="org.labkey.api.query.DefaultSchema" %> <%@ page import="org.labkey.api.query.FieldKey" %> @@ -470,7 +467,7 @@ private void testEmptyInsert(TableInfo table, User user) throws Exception @Test public void testDataClassFromTemplate() throws Exception { - requireSimpleTestModule(); + ExpProvisionedTableTestHelper.requireSimpleTestModule(c); final Container sub = ContainerManager.createContainer(c, "sub2", _user); final String domainName = "mydataclass"; @@ -568,7 +565,7 @@ private String createConceptLookupList(Container c, User user) throws Exception @Test public void testDomainTemplate() throws Exception { - requireSimpleTestModule(); + ExpProvisionedTableTestHelper.requireSimpleTestModule(c); final Container sub = ContainerManager.createContainer(c, "sub3", _user); DomainTemplateGroup templateGroup = DomainTemplateGroup.get(c, "todolist"); assertNotNull(templateGroup); @@ -1204,18 +1201,4 @@ private @NotNull TableInfo getDataClassTable(String dataClassName) return schema.getTableOrThrow(dataClassName); } -private void requireSimpleTestModule() -{ - if (!AppProps.getInstance().isDevMode()) // Skip test in production mode if necessary modules are not available - { - Assume.assumeTrue("List module is required to test data class templates", ModuleLoader.getInstance().getModule("list") != null); - Assume.assumeTrue("simpletest module is required to test data class templates", ModuleLoader.getInstance().getModule("simpletest") != null); - } - - Set activeModules = new HashSet<>(c.getActiveModules()); - Module m = ModuleLoader.getInstance().getModule("simpletest"); - assertNotNull("This test requires 'simpletest' module to be deployed", m); - activeModules.add(m); - c.setActiveModules(activeModules); -} %> diff --git a/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java b/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java index f1a4fbc64d6..823ca36e40c 100644 --- a/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java +++ b/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.Nullable; import org.junit.Assert; +import org.junit.Assume; import org.labkey.api.collections.ArrayListMap; import org.labkey.api.data.Container; import org.labkey.api.data.TableInfo; @@ -10,6 +11,8 @@ import org.labkey.api.exp.query.ExpSchema; import org.labkey.api.gwt.client.model.GWTDomain; import org.labkey.api.gwt.client.model.GWTPropertyDescriptor; +import org.labkey.api.module.Module; +import org.labkey.api.module.ModuleLoader; import org.labkey.api.query.BatchValidationException; import org.labkey.api.query.QueryService; import org.labkey.api.query.QueryUpdateService; @@ -17,6 +20,7 @@ import org.labkey.api.query.UserSchema; import org.labkey.api.query.ValidationException; import org.labkey.api.security.User; +import org.labkey.api.settings.AppProps; import org.labkey.api.util.TestContext; import java.io.StringWriter; @@ -24,8 +28,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import static org.hamcrest.CoreMatchers.hasItem; @@ -119,7 +125,22 @@ public List> updateRows(Container c, List values, Collection expected) throws Exception + public static void requireSimpleTestModule(Container c) + { + if (!AppProps.getInstance().isDevMode()) // Skip test in production mode if necessary modules are not available + { + Assume.assumeTrue("List module is required to test domain templates", ModuleLoader.getInstance().getModule("list") != null); + Assume.assumeTrue("simpletest module is required to test domain templates", ModuleLoader.getInstance().getModule("simpletest") != null); + } + + Module m = ModuleLoader.getInstance().getModule("simpletest"); + Assert.assertNotNull("This test requires 'simpletest' module to be deployed", m); + Set activeModules = new HashSet<>(c.getActiveModules()); + activeModules.add(m); + c.setActiveModules(activeModules); + } + + static void assertMultiValue(Collection values, Collection expected) { Assert.assertNotNull(values); for (var expect : expected) diff --git a/experiment/src/org/labkey/experiment/api/ExpSampleTypeTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpSampleTypeTestCase.jsp index 9cc144a4f9f..c4b6970e3d8 100644 --- a/experiment/src/org/labkey/experiment/api/ExpSampleTypeTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpSampleTypeTestCase.jsp @@ -45,6 +45,12 @@ <%@ page import="org.labkey.api.exp.api.ExperimentService" %> <%@ page import="org.labkey.api.exp.api.SampleTypeService" %> <%@ page import="org.labkey.api.exp.property.Domain" %> +<%@ page import="org.labkey.api.exp.property.DomainKind" %> +<%@ page import="org.labkey.api.exp.property.DomainTemplate" %> +<%@ page import="org.labkey.api.exp.property.DomainTemplateGroup" %> +<%@ page import="org.labkey.api.exp.property.DomainUtil" %> +<%@ page import="org.labkey.api.gwt.client.model.GWTDomain" %> +<%@ page import="org.labkey.api.query.ValidationException" %> <%@ page import="org.labkey.api.exp.query.ExpSchema" %> <%@ page import="org.labkey.api.exp.query.SamplesSchema" %> <%@ page import="org.labkey.api.gwt.client.AuditBehaviorType" %> @@ -91,37 +97,43 @@ <%@ page import="org.labkey.api.view.ViewServlet" %> <%@ page import="org.labkey.api.util.JsonUtil" %> <%@ page import="org.labkey.api.settings.LookAndFeelProperties" %> +<%@ page import="org.junit.BeforeClass" %> +<%@ page import="org.junit.AfterClass" %> <%@ page extends="org.labkey.api.jsp.JspTest.BVT" %> <%! private static final String PROJECT_NAME = "_testSampleType"; -private final ExpProvisionedTableTestHelper helper = new ExpProvisionedTableTestHelper(); +private static final ExpProvisionedTableTestHelper helper = new ExpProvisionedTableTestHelper(); private Container c; +static User _user; + +@BeforeClass +public static void setUp() +{ + _user = TestContext.get().getUser(); +} @Before -public void setUp() +public void ensureProject() { - // NOTE: We need to use a project to create the sample type so we can insert rows into sub-folders - c = ContainerManager.getForPath(PROJECT_NAME); - if (c != null) - ContainerManager.deleteAll(c, TestContext.get().getUser()); - c = ContainerManager.createContainer(ContainerManager.getRoot(), PROJECT_NAME, TestContext.get().getUser()); + // Some tests delete the project so ensure it is available for the next test + c = ContainerManager.ensureContainer(PROJECT_NAME, _user); } @After -public void tearDown() throws InterruptedException +public void drainQueue() throws InterruptedException { // Wait for the indexer to finish working on the data we just added to help avoid deadlocks SearchService.get().drainQueue(SearchService.PRIORITY.crawl, 15, TimeUnit.SECONDS); - ContainerManager.deleteAll(c, TestContext.get().getUser()); } -private void assertExpectedName(ExpSampleType st, String expectedName) +@AfterClass +public static void tearDown() { - ExpMaterial s = st.getSample(c, expectedName); - assertNotNull("Expected to create sample with name '" + expectedName + "'", s); - assertEquals(expectedName, s.getName()); + Container project = ContainerManager.getForPath(PROJECT_NAME); + if (project != null) + ContainerManager.deleteAll(project, _user); } // validate name is not null @@ -130,10 +142,7 @@ public void nameNotNull() throws Exception { try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("name", "string")); - - createSampleType(null, props, null); + createSampleType(null, List.of(new GWTPropertyDescriptor("name", "string")), null); } catch (ApiUsageException ee) { @@ -146,10 +155,7 @@ public void reservedNameFirst() throws Exception { try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("name", "string")); - - createSampleType("First", props, null); + createSampleType("First", List.of(new GWTPropertyDescriptor("name", "string")), null); } catch (ApiUsageException ee) { @@ -162,10 +168,7 @@ public void reservedNameAll() throws Exception { try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("name", "string")); - - createSampleType("All", props, null); + createSampleType("All", List.of(new GWTPropertyDescriptor("name", "string")), null); } catch (ApiUsageException ee) { @@ -179,10 +182,7 @@ public void nameScale() throws Exception { try { - List props = new ArrayList<>(); - props.add(new GWTPropertyDescriptor("name", "string")); - - createSampleType(StringUtils.repeat("a", 1000), props, null); + createSampleType(StringUtils.repeat("a", 1000), List.of(new GWTPropertyDescriptor("name", "string")), null); } catch (ApiUsageException ee) { @@ -201,7 +201,7 @@ public void nameExpressionScale() throws Exception props.add(new GWTPropertyDescriptor("prop", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - createSampleType("Samples", props, StringUtils.repeat("a", 1000)); + createSampleType(generateSampleTypeName(), props, StringUtils.repeat("a", 1000)); } catch (ApiUsageException ee) { @@ -219,7 +219,7 @@ public void idColsUnset_nameExpressionNull_noNameProperty() throws Exception props.add(new GWTPropertyDescriptor("notName", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - createSampleType("Samples", props, null); + createSampleType(generateSampleTypeName(), props, null); fail("Expected exception"); } catch (ApiUsageException ee) @@ -236,7 +236,7 @@ public void idColsUnset_nameExpressionNull_hasNameProperty() throws Exception props.add(new GWTPropertyDescriptor("name", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - final ExpSampleType st = createSampleType("Samples", props, null); + final ExpSampleType st = createSampleType(generateSampleTypeName(), props, null); ExpMaterial sample = st.getSample(c, "bob"); assertNull(sample); @@ -244,7 +244,7 @@ public void idColsUnset_nameExpressionNull_hasNameProperty() throws Exception List> rows = new ArrayList<>(); rows.add(CaseInsensitiveHashMap.of("name", "bob", "age", 10)); - insertSampleRows("Samples", rows); + insertSampleRows(st.getName(), rows); assertExpectedName(st, "bob"); } @@ -258,21 +258,19 @@ public void idColsUnset_nameExpression_hasNameProperty() throws Exception props.add(new GWTPropertyDescriptor("prop", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - createSampleType("Samples", props, "S-${prop}.${age}"); + createSampleType(generateSampleTypeName(), props, "S-${prop}.${age}"); } // idCols not null, nameExpression null, no 'name' property -- ok @Test public void idColsSet_nameExpressionNull_noNameProperty() throws Exception { - final User user = TestContext.get().getUser(); - List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("prop", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - final ExpSampleType st = SampleTypeService.get().createSampleType(c, user, - "Samples", null, props, Collections.emptyList(), + final ExpSampleType st = SampleTypeService.get().createSampleType(c, _user, + generateSampleTypeName(), null, props, Collections.emptyList(), 0, 1, -1, -1, null, null); final String expectedName1 = "bob"; @@ -286,7 +284,7 @@ public void idColsSet_nameExpressionNull_noNameProperty() throws Exception rows.add(CaseInsensitiveHashMap.of("name", "bob", "prop", "blue", "age", 10)); rows.add(CaseInsensitiveHashMap.of("prop", "red", "age", 11)); - insertSampleRows("Samples", rows); + insertSampleRows(st.getName(), rows); assertExpectedName(st, expectedName1); assertExpectedName(st, expectedName2); @@ -296,16 +294,14 @@ public void idColsSet_nameExpressionNull_noNameProperty() throws Exception @Test public void idColsSet_nameExpressionNull_hasUnusedNameProperty() throws Exception { - final User user = TestContext.get().getUser(); - try { List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - SampleTypeService.get().createSampleType(c, user, - "Samples", null, props, Collections.emptyList(), + SampleTypeService.get().createSampleType(c, _user, + generateSampleTypeName(), null, props, Collections.emptyList(), 1, -1, -1, -1, null, null); fail("Expected exception"); } @@ -319,36 +315,27 @@ public void idColsSet_nameExpressionNull_hasUnusedNameProperty() throws Exceptio @Test public void idColsSet_nameExpressionNull_hasNameProperty() throws Exception { - final User user = TestContext.get().getUser(); - List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); props.add(new GWTPropertyDescriptor("prop", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - final ExpSampleType st = createSampleType("Samples", props, null); + final ExpSampleType st = createSampleType(generateSampleTypeName(), props, null); final String expectedName1 = "bob"; ExpMaterial sample1 = st.getSample(c, expectedName1); assertNull(sample1); - List> rows = new ArrayList<>(); - rows.add(CaseInsensitiveHashMap.of("name", "bob", "prop", "blue", "age", 10)); - - BatchValidationException errors = new BatchValidationException(); - QueryUpdateService svc = getSampleTypeUpdateService(st.getName()); - svc.insertRows(user, c, rows, errors, null, null); - if (errors.hasErrors()) - throw errors; - + insertSampleRows(st.getName(), List.of(CaseInsensitiveHashMap.of("name", expectedName1, "prop", "blue", "age", 10))); assertExpectedName(st, expectedName1); // try to insert without a value for 'name' property results in an error - rows = new ArrayList<>(); + List> rows = new ArrayList<>(); rows.add(CaseInsensitiveHashMap.of("prop", "red", "age", 11)); - errors = new BatchValidationException(); - svc.insertRows(user, c, rows, errors, null, null); + BatchValidationException errors = new BatchValidationException(); + QueryUpdateService svc = getSampleTypeUpdateService(st.getName()); + svc.insertRows(_user, c, rows, errors, null, null); assertTrue(errors.hasErrors()); assertTrue(errors.getMessage().contains("SampleID or Name is required for sample")); } @@ -357,16 +344,14 @@ public void idColsSet_nameExpressionNull_hasNameProperty() throws Exception @Test public void idColsSet_nameExpression_hasUnusedNameProperty() throws Exception { - final User user = TestContext.get().getUser(); - try { List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - SampleTypeService.get().createSampleType(c, user, - "Samples", null, props, Collections.emptyList(), + SampleTypeService.get().createSampleType(c, _user, + generateSampleTypeName(), null, props, Collections.emptyList(), 1, -1, -1, -1, "S-${name}.${age}", null); fail("Expected exception"); } @@ -379,16 +364,14 @@ public void idColsSet_nameExpression_hasUnusedNameProperty() throws Exception @Test public void testNameExpression() throws Exception { - final User user = TestContext.get().getUser(); - // setup List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); props.add(new GWTPropertyDescriptor("prop", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - final String sampleTypeName = "Samples"; - final ExpSampleType st = createSampleType(sampleTypeName, props, "S-${prop}.${age}.${genId:number('000')}"); + final ExpSampleType st = createSampleType(generateSampleTypeName(), props, "S-${prop}.${age}.${genId:number('000')}"); + String sampleTypeName = st.getName(); final String expectedName1 = "bob"; final String expectedName2 = "S-red.11.002"; @@ -420,7 +403,7 @@ public void testNameExpression() throws Exception // Issue 53400: Verify the aliquot naming pattern is case-insensitive st.setAliquotNameExpression("${aliquotedFrom}-ALI-${genId:number('0000')}"); - st.save(user); + st.save(_user); List> aliquotRows = new ArrayList<>(); aliquotRows.add(CaseInsensitiveHashMap.of("aliquotedFrom", expectedName1, "AliquotCount", 10)); @@ -461,7 +444,7 @@ public void testNameExpression() throws Exception // test the default aliquot naming pattern (${${AliquotedFrom}-:withCounter} st.setAliquotNameExpression(""); - st.save(user); + st.save(_user); aliquotRows = new ArrayList<>(); aliquotRows.add(CaseInsensitiveHashMap.of("aliquotedFrom", expectedName1)); @@ -506,7 +489,7 @@ public void testAliases() throws Exception List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - final ExpSampleType st = createSampleType("Samples", props, null); + final ExpSampleType st = createSampleType(generateSampleTypeName(), props, null); ExpMaterial fooSample; ExpMaterial booSample; @@ -611,31 +594,20 @@ public void testAliases() throws Exception @Test public void testBlankRows() throws Exception { - final User user = TestContext.get().getUser(); - // setup List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); props.add(new GWTPropertyDescriptor("age", "int")); - final ExpSampleType st = createSampleType("Samples", props, "S-${now:date}-${dailySampleCount}"); + final ExpSampleType st = createSampleType(generateSampleTypeName(), props, "S-${now:date}-${dailySampleCount}"); List allSamples = st.getSamples(c); assertTrue("Expected no samples", allSamples.isEmpty()); // insert via insertRows -- blank rows should be preserved - QueryUpdateService svc = getSampleTypeUpdateService(st.getName()); - // insert 3 rows with no values - List> rows = new ArrayList<>(); - rows.add(new CaseInsensitiveHashMap<>()); - rows.add(new CaseInsensitiveHashMap<>()); - rows.add(new CaseInsensitiveHashMap<>()); - - BatchValidationException errors = new BatchValidationException(); - List> inserted = svc.insertRows(user, c, rows, errors, null, null); - if (errors.hasErrors()) - throw errors; + List> rows = List.of(CaseInsensitiveHashMap.of(), CaseInsensitiveHashMap.of(), CaseInsensitiveHashMap.of()); + List> inserted = insertSampleRows(st.getName(), rows); assertEquals("Expected to generate 3 sample rows, got: " + inserted, 3, inserted.size()); @@ -655,11 +627,7 @@ public void testBlankRows() throws Exception "30\n"; DataLoader tsv = DataLoader.get().createLoader("upload.txt", "text/plain", new StringBufferInputStream(dataTxt), true, c, TabLoader.TSV_FILE_TYPE); var dataMaps = tsv.load(); - - errors = new BatchValidationException(); - var insertedRows = svc.insertRows(user, c, dataMaps, errors, null, null); - if (errors.hasErrors()) - throw errors; + var insertedRows = insertSampleRows(st.getName(), dataMaps); assertEquals("Expected to insert 2 samples, got: " + insertedRows.size(), 2, insertedRows.size()); assertEquals(0, insertedRows.getFirst().get("AliquotCount")); @@ -687,14 +655,17 @@ public void testBlankRows() throws Exception updated.put("name", material1.getName()); updated.put("lsid", material1.getLSID()); updated.put("age", age1 + 1); - svc.updateRows(user, c, Collections.singletonList(updated), null, errors, null, null); + + QueryUpdateService svc = getSampleTypeUpdateService(st.getName()); + BatchValidationException errors = new BatchValidationException(); + svc.updateRows(_user, c, Collections.singletonList(updated), null, errors, null, null); assertFalse(errors.hasErrors()); TableInfo table = getSampleTypeTable(st.getName()); var result = new TableSelector(table, new SimpleFilter("lsid", material1.getLSID()), null).getMap(); assertEquals(21, asInteger(result.get("age")).intValue()); // and a delete - svc.deleteRows(user, c, Collections.singletonList(updated), null, null); + svc.deleteRows(_user, c, Collections.singletonList(updated), null, null); allSamples = st.getSamples(c); assertEquals("Expected 5 total samples", 4, allSamples.size()); } @@ -703,8 +674,6 @@ public void testBlankRows() throws Exception @Test public void testUpdateSomeParents() throws Exception { - final User user = TestContext.get().getUser(); - // setup List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); @@ -723,7 +692,7 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("name", "P1-3")); rows.add(CaseInsensitiveHashMap.of("name", "P1-4,test")); - List> inserted = updateService.insertRows(user, c, rows, errors, null, null); + List> inserted = updateService.insertRows(_user, c, rows, errors, null, null); assertFalse(errors.hasErrors()); assertEquals("Number of parent1 samples inserted not as expected", 4, inserted.size()); @@ -734,7 +703,7 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("name", "P2-1")); rows.add(CaseInsensitiveHashMap.of("name", "P2-2")); rows.add(CaseInsensitiveHashMap.of("name", "P2-3")); - inserted = updateService.insertRows(user, c, rows, errors, null, null); + inserted = updateService.insertRows(_user, c, rows, errors, null, null); assertFalse(errors.hasErrors()); assertEquals("Number of parent2 samples inserted not as expected", 3, inserted.size()); @@ -748,7 +717,7 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("name", "C4", "MaterialInputs/Parent1Samples", "P1-2", "MaterialInputs/Parent2Samples", "P2-2")); rows.add(CaseInsensitiveHashMap.of("name", "C5", "MaterialInputs/Parent1Samples", "P1-1, \"P1-4,test\", P1-2")); - inserted = updateService.insertRows(user, c, rows, errors, null, null); + inserted = updateService.insertRows(_user, c, rows, errors, null, null); assertFalse(errors.hasErrors()); assertEquals("Number of child samples inserted not as expected", 5, inserted.size()); @@ -757,7 +726,7 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("rowId", parent2Type.getSample(c, "P2-1").getRowId(), "MaterialInputs/ChildSamples", "C1")); try { - getSampleTypeUpdateService(parent2Type.getName()).updateRows(user, c, rows, null, errors, null, null); + getSampleTypeUpdateService(parent2Type.getName()).updateRows(_user, c, rows, null, errors, null, null); fail("Expected to throw exception"); } catch (Exception e) @@ -788,7 +757,7 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("rowId", C1.getRowId(), "name", "C1", "MaterialInputs/Parent1Samples", "P1-1")); rows.add(CaseInsensitiveHashMap.of("rowId", C4.getRowId(), "name", "C5", "MaterialInputs/Parent1Samples", null)); // intentionally mix up name - updateService.mergeRows(user, c, MapDataIterator.of(rows), errors, null, null); + updateService.mergeRows(_user, c, MapDataIterator.of(rows), errors, null, null); assertThat(errors.getMessage(), containsString("RowId is not accepted when merging samples. Specify only the sample name instead.")); errors = new BatchValidationException(); } @@ -799,7 +768,7 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("Row Id", C1.getRowId(), "name", "C1", "MaterialInputs/Parent1Samples", "P1-1")); rows.add(CaseInsensitiveHashMap.of("Row Id", C4.getRowId(), "name", "C5", "MaterialInputs/Parent1Samples", null)); // intentionally mix up name - updateService.mergeRows(user, c, MapDataIterator.of(rows), errors, null, null); + updateService.mergeRows(_user, c, MapDataIterator.of(rows), errors, null, null); assertThat(errors.getMessage(), containsString("RowId is not accepted when merging samples. Specify only the sample name instead.")); errors = new BatchValidationException(); } @@ -813,7 +782,7 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("LSID", C1.getLSID(), "MaterialInputs/Parent1Samples", "P1-1")); rows.add(CaseInsensitiveHashMap.of("LSID", C4.getLSID(), "MaterialInputs/Parent1Samples", null)); - updateService.updateRows(user, c, rows, null, errors, null, null); + updateService.updateRows(_user, c, rows, null, errors, null, null); fail("Expected to throw exception"); } catch (Exception e) @@ -827,7 +796,7 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("LSID", C1.getLSID(), "MaterialInputs/Parent1Samples", "P1-1")); rows.add(CaseInsensitiveHashMap.of("LSID", C4.getLSID(), "MaterialInputs/Parent1Samples", null)); - updateService.mergeRows(user, c, MapDataIterator.of(rows), errors, null, null); + updateService.mergeRows(_user, c, MapDataIterator.of(rows), errors, null, null); assertThat(errors.getMessage(), containsString("LSID is no longer accepted as a key for sample merge")); errors = new BatchValidationException(); } @@ -837,15 +806,15 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("name", "C1", "MaterialInputs/Parent1Samples", "P1-1")); // change one parent but not the other rows.add(CaseInsensitiveHashMap.of("name", "C4", "MaterialInputs/Parent1Samples", null)); // remove one parent but not the other - updateService.mergeRows(user, c, MapDataIterator.of(rows), errors, null, null); + updateService.mergeRows(_user, c, MapDataIterator.of(rows), errors, null, null); assertFalse(errors.hasErrors()); - ExpLineage lineage = ExpLineageService.get().getLineage(c, user, C1, opts); + ExpLineage lineage = ExpLineageService.get().getLineage(c, _user, C1, opts); assertTrue("Expected 'C1' to be derived from 'P1-1'", lineage.getMaterials().contains(P11)); assertFalse("Expected 'C1' to no longer be derived from 'P1-2'", lineage.getMaterials().contains(P12)); assertTrue("Expected 'C1' to still be derived from 'P2-1'", lineage.getMaterials().contains(P21)); - lineage = ExpLineageService.get().getLineage(c, user, C4, opts); + lineage = ExpLineageService.get().getLineage(c, _user, C4, opts); assertFalse("Expected 'C4' to not be derived from 'P1-2'", lineage.getMaterials().contains(P12)); assertTrue("Expected 'C4' to still be derived from 'P2-2'", lineage.getMaterials().contains(P22)); @@ -853,18 +822,18 @@ public void testUpdateSomeParents() throws Exception rows.add(CaseInsensitiveHashMap.of("name", "C4", "MaterialInputs/Parent1Samples", "P1-1", "MaterialInputs/Parent2Samples", "P2-1")); // change both parents rows.add(CaseInsensitiveHashMap.of("name", "C2", "MaterialInputs/Parent1Samples", "", "MaterialInputs/Parent2Samples", null)); // remove both parents - updateService.mergeRows(user, c, MapDataIterator.of(rows), errors, null, null); + updateService.mergeRows(_user, c, MapDataIterator.of(rows), errors, null, null); assertFalse(errors.hasErrors()); - lineage = ExpLineageService.get().getLineage(c, user, C2, opts); + lineage = ExpLineageService.get().getLineage(c, _user, C2, opts); assertTrue("Expected 'C2' to have no parents'", lineage.getMaterials().isEmpty()); - lineage = ExpLineageService.get().getLineage(c, user, C4, opts); + lineage = ExpLineageService.get().getLineage(c, _user, C4, opts); assertEquals("Expected 'C4' to have two parents", 2, lineage.getMaterials().size()); assertTrue("Expected 'C4' to be derived from 'P1-1'", lineage.getMaterials().contains(P11)); assertTrue("Expected 'C4' to be derived from 'P2-1'", lineage.getMaterials().contains(P21)); - lineage = ExpLineageService.get().getLineage(c, user, C5, opts); + lineage = ExpLineageService.get().getLineage(c, _user, C5, opts); assertEquals("Expected 'C5' to have three parents", 3, lineage.getMaterials().size()); assertTrue("Expected 'C5' to be derived from 'P1-1'", lineage.getMaterials().contains(P11)); assertTrue("Expected 'C5' to be derived from 'P1-4,test'", lineage.getMaterials().contains(P14)); @@ -875,25 +844,24 @@ public void testUpdateSomeParents() throws Exception @Test public void testParentColAndDataInputDerivation() throws Exception { - final User user = TestContext.get().getUser(); - // setup List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); props.add(new GWTPropertyDescriptor("data", "int")); props.add(new GWTPropertyDescriptor("parent", "string")); - String sampleTypeName = "Samples"; - final ExpSampleType st = createSampleType(sampleTypeName, props, null); + final ExpSampleType st = createSampleType(generateSampleTypeName(), props, null); + String sampleTypeName = st.getName(); + String materialInputsName = "MaterialInputs/" + sampleTypeName; // insert and derive with both 'parent' column and 'DataInputs/Samples' List> rows = new ArrayList<>(); rows.add(CaseInsensitiveHashMap.of("name", "A", "data", 10, "parent", null)); rows.add(CaseInsensitiveHashMap.of("name", "B", "data", 11, "parent", "A")); - rows.add(CaseInsensitiveHashMap.of("name", "C", "data", 12, "parent", null, "MaterialInputs/Samples", "B")); - rows.add(CaseInsensitiveHashMap.of("name", "D", "data", 12, "parent", "B", "MaterialInputs/Samples", "C")); - rows.add(CaseInsensitiveHashMap.of("name", "E", "data", 12, "parent", null, "MaterialInputs/Samples", "B,C")); + rows.add(CaseInsensitiveHashMap.of("name", "C", "data", 12, "parent", null, materialInputsName, "B")); + rows.add(CaseInsensitiveHashMap.of("name", "D", "data", 12, "parent", "B", materialInputsName, "C")); + rows.add(CaseInsensitiveHashMap.of("name", "E", "data", 12, "parent", null, materialInputsName, "B,C")); rows.add(CaseInsensitiveHashMap.of("name", "F", "data", 12, "parent", null)); // lineage graph: @@ -904,10 +872,7 @@ public void testParentColAndDataInputDerivation() throws Exception // E <- B,C // F - BatchValidationException errors = new BatchValidationException(); - QueryUpdateService svc = getSampleTypeUpdateService(st.getName()); - List> inserted = svc.insertRows(user, c, rows, errors, null, null); - assertFalse(errors.hasErrors()); + List> inserted = insertSampleRows(sampleTypeName, rows); assertEquals(6, inserted.size()); // verify @@ -919,14 +884,14 @@ public void testParentColAndDataInputDerivation() throws Exception ExpMaterial A = st.getSample(c, "A"); assertEquals(0, A.getAliquotCount()); assertNotNull(A); - ExpLineage lineage = ExpLineageService.get().getLineage(c, user, A, opts); + ExpLineage lineage = ExpLineageService.get().getLineage(c, _user, A, opts); assertTrue(lineage.getMaterials().isEmpty()); assertNull(A.getRunId()); ExpMaterial B = st.getSample(c, "B"); assertEquals(0, A.getAliquotCount()); assertNotNull(B); - lineage = ExpLineageService.get().getLineage(c, user, B, opts); + lineage = ExpLineageService.get().getLineage(c, _user, B, opts); assertEquals(1, lineage.getMaterials().size()); assertTrue("Expected 'B' to be derived from 'A'", lineage.getMaterials().contains(A)); assertNotNull(B.getRunId()); @@ -934,21 +899,21 @@ public void testParentColAndDataInputDerivation() throws Exception ExpMaterial C = st.getSample(c, "C"); assertEquals(0, A.getAliquotCount()); assertNotNull(C); - lineage = ExpLineageService.get().getLineage(c, user, C, opts); + lineage = ExpLineageService.get().getLineage(c, _user, C, opts); assertEquals(1, lineage.getMaterials().size()); assertTrue("Expected 'C' to be derived from 'B'", lineage.getMaterials().contains(B)); ExpMaterial D = st.getSample(c, "D"); assertEquals(0, A.getAliquotCount()); assertNotNull(D); - lineage = ExpLineageService.get().getLineage(c, user, D, opts); + lineage = ExpLineageService.get().getLineage(c, _user, D, opts); assertEquals(2, lineage.getMaterials().size()); assertTrue("Expected 'D' to be derived from 'B'", lineage.getMaterials().contains(B)); assertTrue("Expected 'D' to be derived from 'C'", lineage.getMaterials().contains(C)); ExpMaterial E = st.getSample(c, "E"); assertNotNull(E); - lineage = ExpLineageService.get().getLineage(c, user, E, opts); + lineage = ExpLineageService.get().getLineage(c, _user, E, opts); assertTrue("Expected 'E' to be the seed", lineage.getSeeds().contains(E)); assertEquals(2, lineage.getMaterials().size()); assertTrue("Expected 'E' to be derived from 'B'", lineage.getMaterials().contains(B)); @@ -969,7 +934,7 @@ public void testParentColAndDataInputDerivation() throws Exception assertTrue("Expected lineage to include derivation run", lineage.getRuns().contains(derivationRun)); // verify lineage using the derivation run as a seed - lineage = ExperimentServiceImpl.get().getLineage(c, user, Set.of(derivationRun), new ExpLineageOptions(true, false, 1)); + lineage = ExperimentServiceImpl.get().getLineage(c, _user, Set.of(derivationRun), new ExpLineageOptions(true, false, 1)); assertTrue("Expected derivationRun to be the seed", lineage.getSeeds().contains(derivationRun)); assertEquals(2, lineage.getMaterials().size()); assertTrue("Expected 'B' to be input into derivationRun", lineage.getMaterials().contains(B)); @@ -978,14 +943,13 @@ public void testParentColAndDataInputDerivation() throws Exception // update 'D' to derive from 'B' and 'E' rows = new ArrayList<>(); - rows.add(CaseInsensitiveHashMap.of("rowId", D.getRowId(), "MaterialInputs/Samples", "B,E")); + rows.add(CaseInsensitiveHashMap.of("rowId", D.getRowId(), materialInputsName, "B,E")); - List> updated = svc.updateRows(user, c, rows, null, errors, null, null); - assertFalse(errors.hasErrors()); + List> updated = updateSampleRows(st.getName(), rows); assertEquals(1, updated.size()); ExpMaterial D2 = st.getSample(c, "D"); - lineage = ExpLineageService.get().getLineage(c, user, D2, opts); + lineage = ExpLineageService.get().getLineage(c, _user, D2, opts); assertEquals(2, lineage.getMaterials().size()); assertTrue("Expected 'D' to be derived from 'B'", lineage.getMaterials().contains(B)); assertTrue("Expected 'D' to be derived from 'E'", lineage.getMaterials().contains(E)); @@ -1026,7 +990,7 @@ public void testParentColAndDataInputDerivation() throws Exception url.addParameter("includeMetadata", false); url.addParameter("apiVersion", "17.1"); - var response = ViewServlet.GET(url, user, null); + var response = ViewServlet.GET(url, _user, null); assertEquals(200, response.getStatus()); var json = JsonUtil.DEFAULT_MAPPER.readTree(response.getContentAsString()); @@ -1057,15 +1021,13 @@ public void testParentColAndDataInputDerivation() throws Exception @Test public void testSampleTypeWithVocabularyProperties() throws Exception { - User user = TestContext.get().getUser(); - String sampleTypeName = "SamplesWithVocabularyProperties"; String sampleType = "TypeA"; String updatedSampleType = "TypeB"; String sampleColor = "Blue"; int sampleAge = 5; - Domain mockDomain = helper.createVocabularyTestDomain(user, c); + Domain mockDomain = helper.createVocabularyTestDomain(_user, c); Map vocabularyPropertyURIs = helper.getVocabularyPropertyURIS(mockDomain); // create a sample type @@ -1121,8 +1083,7 @@ public void testSampleTypeWithVocabularyProperties() throws Exception @Test public void testDetailedAuditLog() throws Exception { - User user = TestContext.get().getUser(); - UserSchema auditSchema = AuditLogService.get().createSchema(user, c); + UserSchema auditSchema = AuditLogService.get().createSchema(_user, c); TableInfo auditTable = auditSchema.getTable(SampleTimelineAuditEvent.EVENT_TYPE); Integer RowId = new SqlSelector(auditSchema.getDbSchema(), new SQLFragment("select max(rowid) FROM ").append(auditTable.getFromSQL("_"))) .getObject(Integer.class); @@ -1134,8 +1095,6 @@ public void testDetailedAuditLog() throws Exception props.add(new GWTPropertyDescriptor("Value", "float")); final ExpSampleType st = createSampleType("SamplesDAL", props, null); - BatchValidationException errors = new BatchValidationException(); - // insert a sample List> ret = insertSampleRows(st.getName(), List.of(CaseInsensitiveHashMap.of("Name", "A1", "Measure", "Initial", "Value", 1.0))); assertEquals(1, ret.size()); @@ -1144,7 +1103,7 @@ public void testDetailedAuditLog() throws Exception // check audit log SimpleFilter f = new SimpleFilter(new FieldKey(null, "RowId"), auditMaxRowid, CompareType.GT); - List events = AuditLogService.get().getAuditEvents(c, user, SampleTimelineAuditEvent.EVENT_TYPE, f, new Sort("-RowId")); + List events = AuditLogService.get().getAuditEvents(c, _user, SampleTimelineAuditEvent.EVENT_TYPE, f, new Sort("-RowId")); assertFalse(events.isEmpty()); assertNull(events.getFirst().getOldRecordMap()); assertNotNull(events.getFirst().getNewRecordMap()); @@ -1161,7 +1120,7 @@ public void testDetailedAuditLog() throws Exception updateSampleRows(st.getName(), List.of(CaseInsensitiveHashMap.of("RowId", rowid, "Measure", "Updated", "Value", 2.0))); // check audit log - events = AuditLogService.get().getAuditEvents(c, user, SampleTimelineAuditEvent.EVENT_TYPE, f, new Sort("-RowId")); + events = AuditLogService.get().getAuditEvents(c, _user, SampleTimelineAuditEvent.EVENT_TYPE, f, new Sort("-RowId")); assertFalse(events.isEmpty()); assertNotNull(events.getFirst().getOldRecordMap()); Map oldRecordMap = new CaseInsensitiveHashMap<>(PageFlowUtil.mapFromQueryString(events.getFirst().getOldRecordMap())); @@ -1182,7 +1141,7 @@ public void testDetailedAuditLog() throws Exception assertEquals(1, count); // check audit log - events = AuditLogService.get().getAuditEvents(c, user, SampleTimelineAuditEvent.EVENT_TYPE, f, new Sort("-RowId")); + events = AuditLogService.get().getAuditEvents(c, _user, SampleTimelineAuditEvent.EVENT_TYPE, f, new Sort("-RowId")); assertFalse(events.isEmpty()); assertNotNull(events.getFirst().getOldRecordMap()); oldRecordMap = new CaseInsensitiveHashMap<>(PageFlowUtil.mapFromQueryString(events.getFirst().getOldRecordMap())); @@ -1197,7 +1156,7 @@ public void testDetailedAuditLog() throws Exception assertEquals("3.0", newRecordMap.get("Value")); assertEquals(2, newRecordMap.size()); - st.delete(user); + st.delete(_user); } // Issue 43442: samples: not able to delete a Material not in a sample type @@ -1216,26 +1175,25 @@ public void testExpMaterialPermissions() throws Exception long stSampleId = (long) JdbcType.BIGINT.convert(ret.getFirst().get("rowid")); // verify insert, update aren't allowed, but read and delete are allowed - User user = TestContext.get().getUser(); - var schema = QueryService.get().getUserSchema(user, c, ExpSchema.SCHEMA_EXP); + var schema = QueryService.get().getUserSchema(_user, c, ExpSchema.SCHEMA_EXP); var materialsTable = schema.getTableOrThrow(ExpSchema.TableType.Materials.name()); var qus = materialsTable.getUpdateService(); assertNotNull(qus); - assertTrue(qus.hasPermission(user, ReadPermission.class)); - assertTrue(qus.hasPermission(user, DeletePermission.class)); - assertFalse(qus.hasPermission(user, InsertPermission.class)); - assertFalse(qus.hasPermission(user, UpdatePermission.class)); + assertTrue(qus.hasPermission(_user, ReadPermission.class)); + assertTrue(qus.hasPermission(_user, DeletePermission.class)); + assertFalse(qus.hasPermission(_user, InsertPermission.class)); + assertFalse(qus.hasPermission(_user, UpdatePermission.class)); // create a sample outside a SampleType var lsid = ExperimentService.get().generateLSID(c, ExpMaterial.class, "SampleNotInSampleType"); ExpMaterial m = ExperimentService.get().createExpMaterial(c, Lsid.parse(lsid)); - m.save(user); + m.save(_user); // verify we can't delete both samples when targeting the default 'Material' cpasType try { ExperimentServiceImpl.get().deleteMaterialByRowIds( - user, c, List.of(stSampleId, m.getRowId()), true, null, false, false); + _user, c, List.of(stSampleId, m.getRowId()), true, null, false, false); fail("Expected to throw exception"); } catch (Exception e) @@ -1247,7 +1205,7 @@ public void testExpMaterialPermissions() throws Exception try { ExperimentServiceImpl.get().deleteMaterialByRowIds( - user, c, List.of(stSampleId, m.getRowId()), true, st, false, false); + _user, c, List.of(stSampleId, m.getRowId()), true, st, false, false); fail("Expected to throw exception"); } catch (Exception e) @@ -1256,20 +1214,18 @@ public void testExpMaterialPermissions() throws Exception } // verify read via QUS - var rows = qus.getRows(user, c, List.of(CaseInsensitiveHashMap.of("rowId", m.getRowId()))); + var rows = qus.getRows(_user, c, List.of(CaseInsensitiveHashMap.of("rowId", m.getRowId()))); assertEquals("Failed to fetch material via QUS", 1, rows.size()); assertEquals(m.getLSID(), rows.getFirst().get("lsid")); // verify delete via QUS - rows = qus.deleteRows(user, c, List.of(CaseInsensitiveHashMap.of("rowId", m.getRowId())), null, null); + rows = qus.deleteRows(_user, c, List.of(CaseInsensitiveHashMap.of("rowId", m.getRowId())), null, null); assertEquals("Failed to delete material via QUS", 1, rows.size()); } @Test public void testInsertOptionUpdate() throws Exception { - final User user = TestContext.get().getUser(); - // create sample type List props = new ArrayList<>(); props.add(new GWTPropertyDescriptor("name", "string")); @@ -1299,7 +1255,7 @@ public void testInsertOptionUpdate() throws Exception DataIteratorContext context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.IMPORT); - var count = qus.loadRows(user, c, MapDataIterator.of(rowsToAdd), context, null); + var count = qus.loadRows(_user, c, MapDataIterator.of(rowsToAdd), context, null); assertFalse(context.getErrors().hasErrors()); assertEquals("Unexpected count from IMPORT on loadRows()", 3, count); @@ -1310,7 +1266,7 @@ public void testInsertOptionUpdate() throws Exception rows.add(CaseInsensitiveHashMap.of("rowId", sampleType.getSample(c, "S-1").getRowId(), "MaterialInputs/" + sampleTypeName, "S-1-1")); try { - qus.updateRows(user, c, rows, null, errors, null, null); + qus.updateRows(_user, c, rows, null, errors, null, null); fail("Expected to throw exception"); } catch (Exception e) @@ -1354,7 +1310,7 @@ public void testInsertOptionUpdate() throws Exception context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.UPDATE); - count = qus.loadRows(user, c, MapDataIterator.of(rowsToUpdate), context, null); + count = qus.loadRows(_user, c, MapDataIterator.of(rowsToUpdate), context, null); assertFalse(context.getErrors().hasErrors()); assertEquals("Unexpected count from UPDATE on loadRows()", 3, count); @@ -1388,7 +1344,7 @@ public void testInsertOptionUpdate() throws Exception rowsToUpdate.add(CaseInsensitiveHashMap.of("name", "S-1-absent", "intVal", 100)); context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.UPDATE); - qus.loadRows(user, c, MapDataIterator.of(rowsToUpdate), context, null); + qus.loadRows(_user, c, MapDataIterator.of(rowsToUpdate), context, null); assertTrue(context.getErrors().hasErrors()); String msg = !context.getErrors().getRowErrors().isEmpty() ? context.getErrors().getRowErrors().getFirst().toString() : "no message"; assertTrue(msg.contains("Sample does not exist: S-1-absent.")); @@ -1399,7 +1355,7 @@ public void testInsertOptionUpdate() throws Exception Map auditOptions = new HashMap<>(); auditOptions.put(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, AuditBehaviorType.DETAILED); context.setConfigParameters(auditOptions); - qus.loadRows(user, c, MapDataIterator.of(rowsToUpdate), context, null); + qus.loadRows(_user, c, MapDataIterator.of(rowsToUpdate), context, null); assertTrue(context.getErrors().hasErrors()); msg = !context.getErrors().getRowErrors().isEmpty() ? context.getErrors().getRowErrors().getFirst().toString() : "no message"; assertTrue(msg.contains("Sample does not exist: S-1-absent.")); @@ -1412,7 +1368,7 @@ public void testInsertOptionUpdate() throws Exception context = new DataIteratorContext(); context.setInsertOption(QueryUpdateService.InsertOption.UPDATE); - qus.loadRows(user, c, MapDataIterator.of(rowsToUpdate), context, null); + qus.loadRows(_user, c, MapDataIterator.of(rowsToUpdate), context, null); assertFalse(context.getErrors().hasErrors()); assertEquals(3, count); rows = getSampleRows(sampleTypeName); @@ -1421,14 +1377,72 @@ public void testInsertOptionUpdate() throws Exception assertNull(rows.get(2).get("AliquotedFromLSID")); } +@Test +public void testSampleTypeFromTemplateReservedColumnNames() throws Exception +{ + ExpProvisionedTableTestHelper.requireSimpleTestModule(c); + final String domainName = "SamplesFromTemplate"; + + DomainTemplateGroup templateGroup = DomainTemplateGroup.get(c, "todolist"); + assertNotNull(templateGroup); + assertFalse("Errors in template: " + StringUtils.join(templateGroup.getErrors(), ", "), templateGroup.hasErrors()); + + DomainTemplate template = templateGroup.getTemplate("Samples"); + assertNotNull(template); + + final Domain domain = template.createAndImport(c, _user, domainName, true, false); + assertNotNull(domain); + + DomainKind kind = domain.getDomainKind(); + + // Verify from the template are honored by the DomainKind + Set reservedNames = kind.getReservedPropertyNames(domain, _user); + assertTrue("Expected template reserved name 'reservedOne' in: " + reservedNames, + reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("reservedOne"))); + assertTrue("Expected template reserved name 'ReservedTwo' in: " + reservedNames, + reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("ReservedTwo"))); + + // Attempt to add a field whose name collides with a template-reserved name (mixed case to exercise case-insensitivity) + GWTDomain origGwt = DomainUtil.getDomainDescriptor(_user, domain.getTypeURI(), c); + GWTDomain updateGwt = new GWTDomain<>(origGwt); + List updatedFields = new ArrayList<>(updateGwt.getFields()); + updatedFields.add(new GWTPropertyDescriptor("RESERVEDONE", "http://www.w3.org/2001/XMLSchema#string")); + updateGwt.setFields(updatedFields); + ValidationException ve = DomainUtil.updateDomainDescriptor(origGwt, updateGwt, c, _user); + assertTrue("Expected a validation error when adding a reserved-name field", ve.hasErrors()); + assertTrue("Expected error message to flag the reserved name: " + ve.getMessage(), + ve.getMessage().toLowerCase().contains("reserved")); + + // Sanity check: a non-reserved field name should validate cleanly + GWTDomain okUpdate = new GWTDomain<>(origGwt); + List okFields = new ArrayList<>(okUpdate.getFields()); + okFields.add(new GWTPropertyDescriptor("nonReservedField", "http://www.w3.org/2001/XMLSchema#string")); + okUpdate.setFields(okFields); + ValidationException okVe = DomainUtil.validateProperties(domain, okUpdate, kind, origGwt, _user); + assertFalse("Did not expect validation errors for a non-reserved field: " + okVe.getMessage(), okVe.hasErrors()); +} + +private void assertExpectedName(ExpSampleType st, String expectedName) +{ + ExpMaterial s = st.getSample(c, expectedName); + assertNotNull("Expected to create sample with name '" + expectedName + "'", s); + assertEquals(expectedName, s.getName()); +} + +private static int increment = 0; +private static String generateSampleTypeName() +{ + return "Samples-" + increment++; +} + private ExpSampleType createSampleType(String sampleTypeName, List props, @Nullable String nameExpression) throws Exception { - return SampleTypeService.get().createSampleType(c, TestContext.get().getUser(), sampleTypeName, null, props, emptyList(), -1, -1, -1, -1, nameExpression, null); + return SampleTypeService.get().createSampleType(c, _user, sampleTypeName, null, props, emptyList(), -1, -1, -1, -1, nameExpression, null); } private @NotNull UserSchema getSampleSchema() { - UserSchema schema = QueryService.get().getUserSchema(TestContext.get().getUser(), c, SamplesSchema.SCHEMA_SAMPLES); + UserSchema schema = QueryService.get().getUserSchema(_user, c, SamplesSchema.SCHEMA_SAMPLES); assertNotNull(schema); return schema; } @@ -1446,7 +1460,7 @@ private @NotNull QueryUpdateService getSampleTypeUpdateService(String sampleType return updateService; } -private List> getSampleRows(String sampleType) +private List> getSampleRows(String sampleType) { TableInfo table = getSampleTypeTable(sampleType); return Arrays.asList(new TableSelector(table, null, new Sort("Name")).getMapArray()); @@ -1456,7 +1470,7 @@ private List> insertSampleRows(String sampleType, List> ret = svc.insertRows(TestContext.get().getUser(), c, rows, errors, null, null); + List> ret = svc.insertRows(_user, c, rows, errors, null, null); if (errors.hasErrors()) throw errors; return ret; @@ -1467,7 +1481,7 @@ private int mergeSampleRows(String sampleType, List> rows) t BatchValidationException errors = new BatchValidationException(); QueryUpdateService svc = getSampleTypeUpdateService(sampleType); Map config = Map.of(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, AuditBehaviorType.DETAILED); - int count = svc.mergeRows(TestContext.get().getUser(), c, MapDataIterator.of(rows), errors, config, null); + int count = svc.mergeRows(_user, c, MapDataIterator.of(rows), errors, config, null); if (errors.hasErrors()) throw errors; return count; @@ -1478,7 +1492,7 @@ private List> updateSampleRows(String sampleType, List config = Map.of(DetailedAuditLogDataIterator.AuditConfigs.AuditBehavior, AuditBehaviorType.DETAILED); - List> ret = svc.updateRows(TestContext.get().getUser(), c, rows, null, errors, config, null); + List> ret = svc.updateRows(_user, c, rows, null, errors, config, null); if (errors.hasErrors()) throw errors; return ret; From 458817d3e4b6d2664bde9c5b18ae80cef11910c0 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Wed, 20 May 2026 10:39:55 -0700 Subject: [PATCH 4/6] List test --- .../api/ExpDataClassDataTestCase.jsp | 40 +++++-------------- .../api/ExpProvisionedTableTestHelper.java | 34 ++++++++++++++++ .../experiment/api/ExpSampleTypeTestCase.jsp | 32 +-------------- 3 files changed, 45 insertions(+), 61 deletions(-) diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp index c7d6fd4aed9..6f01330218d 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp @@ -73,7 +73,6 @@ <%@ page import="org.labkey.api.query.QueryUpdateService" %> <%@ page import="org.labkey.api.query.SchemaKey" %> <%@ page import="org.labkey.api.query.UserSchema" %> -<%@ page import="org.labkey.api.query.ValidationException" %> <%@ page import="org.labkey.api.search.SearchService" %> <%@ page import="org.labkey.api.security.SecurityManager" %> <%@ page import="org.labkey.api.security.User" %> @@ -473,9 +472,7 @@ public void testDataClassFromTemplate() throws Exception DomainTemplateGroup templateGroup = DomainTemplateGroup.get(c, "TestingFromTemplate"); assertNotNull(templateGroup); - assertFalse( - "Errors in template: " + StringUtils.join(templateGroup.getErrors(), ", "), - templateGroup.hasErrors()); + assertFalse("Errors in template: " + StringUtils.join(templateGroup.getErrors(), ", "), templateGroup.hasErrors()); DomainTemplate template = templateGroup.getTemplate("testingFromTemplate"); assertNotNull(template); @@ -494,31 +491,7 @@ public void testDataClassFromTemplate() throws Exception Set mandatory = kind.getMandatoryPropertyNames(domain); assertTrue("Expected template to set 'aa' as mandatory: " + mandatory, mandatory.contains("aa")); - // Verify from the template are honored by the DomainKind - Set reservedNames = kind.getReservedPropertyNames(domain, _user); - assertTrue("Expected template reserved name 'reservedOne' in: " + reservedNames, - reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("reservedOne"))); - assertTrue("Expected template reserved name 'ReservedTwo' in: " + reservedNames, - reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("ReservedTwo"))); - - // Attempt to add a field whose name collides with a template-reserved name (mixed case) - GWTDomain origGwt = DomainUtil.getDomainDescriptor(_user, domain); - GWTDomain updateGwt = new GWTDomain<>(origGwt); - List updatedFields = new ArrayList<>(updateGwt.getFields()); - updatedFields.add(new GWTPropertyDescriptor("RESERVEDONE", "http://www.w3.org/2001/XMLSchema#string")); - updateGwt.setFields(updatedFields); - ValidationException ve = DomainUtil.updateDomainDescriptor(origGwt, updateGwt, c, _user); - assertTrue("Expected a validation error when adding a reserved-name field", ve.hasErrors()); - assertTrue("Expected error message to flag the reserved name: " + ve.getMessage(), - ve.getMessage().toLowerCase().contains("reserved")); - - // A non-reserved field name should validate cleanly - GWTDomain okUpdate = new GWTDomain<>(origGwt); - List okFields = new ArrayList<>(okUpdate.getFields()); - okFields.add(new GWTPropertyDescriptor("nonReservedField", "http://www.w3.org/2001/XMLSchema#string")); - okUpdate.setFields(okFields); - ValidationException okVe = DomainUtil.validateProperties(domain, okUpdate, kind, origGwt, _user); - assertFalse("Did not expect validation errors for a non-reserved field: " + okVe.getMessage(), okVe.hasErrors()); + helper.verifyReservedColumnNames(c, _user, domain); ExpDataClassImpl dataClass = (ExpDataClassImpl)ExperimentService.get().getDataClass(c, domainName); assertNotNull(dataClass); @@ -571,7 +544,7 @@ public void testDomainTemplate() throws Exception assertNotNull(templateGroup); assertFalse("Errors in template: " + StringUtils.join(templateGroup.getErrors(), ", "), templateGroup.hasErrors()); - List created = templateGroup.createAndImport(sub, _user, true, true); + templateGroup.createAndImport(sub, _user, true, true); // verify the "Priority" list was created and data was imported UserSchema listSchema = QueryService.get().getUserSchema(_user, sub, "lists"); @@ -646,6 +619,13 @@ public void testDomainTemplate() throws Exception Collection aliases = data.getAliases(); assertTrue("Expected aliases to contain 'xsd' and 'domain templates', got: " + aliases, aliases.containsAll(List.of("xsd", "domain templates"))); + + // Verify reserved column names on lists + TableInfo categoryTable = listSchema.getTable("Category"); + Domain categoryDomain = categoryTable.getDomain(); + assertNotNull(categoryDomain); + + helper.verifyReservedColumnNames(c, _user, categoryTable.getDomain()); } // Issue 25224: NPE trying to delete a folder with a DataClass with at least one result row in it diff --git a/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java b/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java index 823ca36e40c..111cc7b21ab 100644 --- a/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java +++ b/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java @@ -1,5 +1,6 @@ package org.labkey.experiment.api; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Assert; import org.junit.Assume; @@ -7,6 +8,7 @@ import org.labkey.api.data.Container; import org.labkey.api.data.TableInfo; import org.labkey.api.exp.property.Domain; +import org.labkey.api.exp.property.DomainKind; import org.labkey.api.exp.property.DomainUtil; import org.labkey.api.exp.query.ExpSchema; import org.labkey.api.gwt.client.model.GWTDomain; @@ -165,4 +167,36 @@ static void assertMultiValue(Object value, String... expected) throws Exception for (String e : expected) Assert.assertTrue("Failed to find '" + e + "' in multivalue '" + s + "'", s.contains(e)); } + + public void verifyReservedColumnNames(Container c, User user, @NotNull Domain domain) + { + DomainKind kind = domain.getDomainKind(); + Assert.assertNotNull(kind); + + // Verify from the template are honored by the DomainKind + Set reservedNames = kind.getReservedPropertyNames(domain, user); + Assert.assertTrue("Expected template reserved name 'reservedOne' in: " + reservedNames, + reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("reservedOne"))); + Assert.assertTrue("Expected template reserved name 'ReservedTwo' in: " + reservedNames, + reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("ReservedTwo"))); + + // Attempt to add a field whose name collides with a template-reserved name (mixed case) + GWTDomain origGwt = DomainUtil.getDomainDescriptor(user, domain); + GWTDomain updateGwt = new GWTDomain<>(origGwt); + List updatedFields = new ArrayList<>(updateGwt.getFields()); + updatedFields.add(new GWTPropertyDescriptor("RESERVEDONE", "http://www.w3.org/2001/XMLSchema#string")); + updateGwt.setFields(updatedFields); + ValidationException ve = DomainUtil.updateDomainDescriptor(origGwt, updateGwt, c, user); + Assert.assertTrue("Expected a validation error when adding a reserved-name field", ve.hasErrors()); + Assert.assertTrue("Expected error message to flag the reserved name: " + ve.getMessage(), + ve.getMessage().toLowerCase().contains("reserved")); + + // A non-reserved field name should validate cleanly + GWTDomain okUpdate = new GWTDomain<>(origGwt); + List okFields = new ArrayList<>(okUpdate.getFields()); + okFields.add(new GWTPropertyDescriptor("nonReservedField", "http://www.w3.org/2001/XMLSchema#string")); + okUpdate.setFields(okFields); + ValidationException okVe = DomainUtil.validateProperties(domain, okUpdate, kind, origGwt, user); + Assert.assertFalse("Did not expect validation errors for a non-reserved field: " + okVe.getMessage(), okVe.hasErrors()); + } } diff --git a/experiment/src/org/labkey/experiment/api/ExpSampleTypeTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpSampleTypeTestCase.jsp index c4b6970e3d8..892a1295e10 100644 --- a/experiment/src/org/labkey/experiment/api/ExpSampleTypeTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpSampleTypeTestCase.jsp @@ -45,12 +45,8 @@ <%@ page import="org.labkey.api.exp.api.ExperimentService" %> <%@ page import="org.labkey.api.exp.api.SampleTypeService" %> <%@ page import="org.labkey.api.exp.property.Domain" %> -<%@ page import="org.labkey.api.exp.property.DomainKind" %> <%@ page import="org.labkey.api.exp.property.DomainTemplate" %> <%@ page import="org.labkey.api.exp.property.DomainTemplateGroup" %> -<%@ page import="org.labkey.api.exp.property.DomainUtil" %> -<%@ page import="org.labkey.api.gwt.client.model.GWTDomain" %> -<%@ page import="org.labkey.api.query.ValidationException" %> <%@ page import="org.labkey.api.exp.query.ExpSchema" %> <%@ page import="org.labkey.api.exp.query.SamplesSchema" %> <%@ page import="org.labkey.api.gwt.client.AuditBehaviorType" %> @@ -1393,33 +1389,7 @@ public void testSampleTypeFromTemplateReservedColumnNames() throws Exception final Domain domain = template.createAndImport(c, _user, domainName, true, false); assertNotNull(domain); - DomainKind kind = domain.getDomainKind(); - - // Verify from the template are honored by the DomainKind - Set reservedNames = kind.getReservedPropertyNames(domain, _user); - assertTrue("Expected template reserved name 'reservedOne' in: " + reservedNames, - reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("reservedOne"))); - assertTrue("Expected template reserved name 'ReservedTwo' in: " + reservedNames, - reservedNames.stream().anyMatch(n -> n.equalsIgnoreCase("ReservedTwo"))); - - // Attempt to add a field whose name collides with a template-reserved name (mixed case to exercise case-insensitivity) - GWTDomain origGwt = DomainUtil.getDomainDescriptor(_user, domain.getTypeURI(), c); - GWTDomain updateGwt = new GWTDomain<>(origGwt); - List updatedFields = new ArrayList<>(updateGwt.getFields()); - updatedFields.add(new GWTPropertyDescriptor("RESERVEDONE", "http://www.w3.org/2001/XMLSchema#string")); - updateGwt.setFields(updatedFields); - ValidationException ve = DomainUtil.updateDomainDescriptor(origGwt, updateGwt, c, _user); - assertTrue("Expected a validation error when adding a reserved-name field", ve.hasErrors()); - assertTrue("Expected error message to flag the reserved name: " + ve.getMessage(), - ve.getMessage().toLowerCase().contains("reserved")); - - // Sanity check: a non-reserved field name should validate cleanly - GWTDomain okUpdate = new GWTDomain<>(origGwt); - List okFields = new ArrayList<>(okUpdate.getFields()); - okFields.add(new GWTPropertyDescriptor("nonReservedField", "http://www.w3.org/2001/XMLSchema#string")); - okUpdate.setFields(okFields); - ValidationException okVe = DomainUtil.validateProperties(domain, okUpdate, kind, origGwt, _user); - assertFalse("Did not expect validation errors for a non-reserved field: " + okVe.getMessage(), okVe.hasErrors()); + helper.verifyReservedColumnNames(c, _user, domain); } private void assertExpectedName(ExpSampleType st, String expectedName) From 3f3e543688e2af7e4691da24962ef71feb13b485 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Wed, 20 May 2026 11:37:40 -0700 Subject: [PATCH 5/6] DomainKind.getKindReservedPropertyNames --- .../audit/query/AbstractAuditDomainKind.java | 2 +- .../api/exp/api/SampleTypeDomainKind.java | 9 +---- .../labkey/api/exp/property/DomainKind.java | 36 ++++++++++++++----- .../api/exp/property/TestDomainKind.java | 2 +- .../api/query/SimpleTableDomainKind.java | 2 +- .../api/assay/AssayBatchDomainKind.java | 6 +--- .../api/assay/AssayResultDomainKind.java | 2 +- .../labkey/api/assay/AssayRunDomainKind.java | 2 +- .../labkey/assay/DefaultAssayDomainKind.java | 2 +- .../PlateBasedAssaySampleTypeDomainKind.java | 6 ---- .../assay/plate/PlateMetadataDomainKind.java | 2 +- .../plate/PlateReplicateStatsDomainKind.java | 2 +- .../labkey/core/query/UsersDomainKind.java | 2 +- .../experiment/api/DataClassDomainKind.java | 6 ++-- .../experiment/api/VocabularyDomainKind.java | 2 +- .../api/property/StorageProvisionerImpl.java | 6 ---- .../filecontent/FilePropertiesDomainKind.java | 2 +- .../issue/query/IssueDefDomainKind.java | 2 +- .../org/labkey/list/model/ListDomainKind.java | 6 ++-- .../model/AbstractSpecimenDomainKind.java | 6 ---- .../specimen/model/SpecimenDomainKind.java | 2 +- .../model/SpecimenEventDomainKind.java | 2 +- .../api/specimen/model/VialDomainKind.java | 2 +- .../query/AbstractStudyDesignDomainKind.java | 2 +- .../study/model/BaseStudyDomainKind.java | 2 +- .../model/ContinuousDatasetDomainKind.java | 2 +- .../labkey/study/model/DatasetDomainKind.java | 3 -- .../study/model/DateDatasetDomainKind.java | 2 +- .../study/model/TestDatasetDomainKind.java | 7 ---- .../study/model/VisitDatasetDomainKind.java | 2 +- 30 files changed, 53 insertions(+), 78 deletions(-) diff --git a/api/src/org/labkey/api/audit/query/AbstractAuditDomainKind.java b/api/src/org/labkey/api/audit/query/AbstractAuditDomainKind.java index 5068f6e3218..d2f3df362f1 100644 --- a/api/src/org/labkey/api/audit/query/AbstractAuditDomainKind.java +++ b/api/src/org/labkey/api/audit/query/AbstractAuditDomainKind.java @@ -298,7 +298,7 @@ public boolean hasNullValues(Domain domain, DomainProperty prop) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { Set names = new HashSet<>(); diff --git a/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java b/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java index 614ee2d1ff5..00bea3e08b9 100644 --- a/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java +++ b/api/src/org/labkey/api/exp/api/SampleTypeDomainKind.java @@ -261,16 +261,9 @@ public Set getBaseProperties(Domain domain) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) - { - return getReservedPropertyNames(domain, user, false); - } - - @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user, boolean forCreate) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { Set reserved = new CaseInsensitiveHashSet(RESERVED_NAMES); - reserved.addAll(getTemplateReservedPropertyNames(domain)); if (domain == null) { diff --git a/api/src/org/labkey/api/exp/property/DomainKind.java b/api/src/org/labkey/api/exp/property/DomainKind.java index 860db419713..e64849c9ddd 100644 --- a/api/src/org/labkey/api/exp/property/DomainKind.java +++ b/api/src/org/labkey/api/exp/property/DomainKind.java @@ -109,23 +109,41 @@ public Map processArguments(Container container, User user, Map< /** * Return the set of names that should not be allowed for properties. E.g., the names of columns - * from the hard table underlying this type. + * from the hard table underlying this type, unioned with any names declared in the + * {@link DomainTemplate}'s {@code } element that this domain was created from. *

- * Subclasses should typically override this method and union their kind-specific reserved set with - * {@link #getTemplateReservedPropertyNames(Domain)} (or with {@code super.getReservedPropertyNames(...)} - * when the override does not also override the {@code forCreate} variant). Doing so ensures that - * names declared in a {@code DomainTemplate}'s {@code } element are honored. + * This method is {@code final}; subclasses contribute their kind-specific reserved set by overriding + * {@link #getKindReservedPropertyNames(Domain, User, boolean)}. The base class always unions that + * set with the template-declared set. * * @return set of strings containing the names. This will be compared ignoring case */ - public Set getReservedPropertyNames(Domain domain, User user) + public final Set getReservedPropertyNames(Domain domain, User user) { - return getTemplateReservedPropertyNames(domain); + return getReservedPropertyNames(domain, user, false); } - public Set getReservedPropertyNames(Domain domain, User user, boolean forCreate) + public final Set getReservedPropertyNames(Domain domain, User user, boolean forCreate) { - return getReservedPropertyNames(domain, user); + Set reserved = new CaseInsensitiveHashSet(getKindReservedPropertyNames(domain, user, forCreate)); + reserved.addAll(getTemplateReservedPropertyNames(domain)); + return reserved; + } + + /** + * Return the kind-specific set of names that should not be allowed for properties. Subclasses override + * this to contribute their static/hard-coded reserved names. The base class will automatically union + * the result with any names declared in the {@link DomainTemplate}'s {@code } + * element via {@link #getReservedPropertyNames(Domain, User, boolean)}. + * + * @param forCreate true when validating names during domain creation; some kinds reserve additional + * names only at creation time. + * @return set of strings containing the names. + */ + @NotNull + protected Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) + { + return Collections.emptySet(); } /** diff --git a/api/src/org/labkey/api/exp/property/TestDomainKind.java b/api/src/org/labkey/api/exp/property/TestDomainKind.java index 99aabb991f7..eff13d44b8c 100644 --- a/api/src/org/labkey/api/exp/property/TestDomainKind.java +++ b/api/src/org/labkey/api/exp/property/TestDomainKind.java @@ -148,7 +148,7 @@ public void deletePropertyDescriptor(Domain domain, User user, PropertyDescripto } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { throw new UnsupportedOperationException(); } diff --git a/api/src/org/labkey/api/query/SimpleTableDomainKind.java b/api/src/org/labkey/api/query/SimpleTableDomainKind.java index b857ae91139..545985ebed2 100644 --- a/api/src/org/labkey/api/query/SimpleTableDomainKind.java +++ b/api/src/org/labkey/api/query/SimpleTableDomainKind.java @@ -236,7 +236,7 @@ public boolean canCreateDefinition(User user, Container container) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { SimpleUserSchema.SimpleTable table = domain != null ? getTable(domain, user) : null; if (table != null) diff --git a/assay/api-src/org/labkey/api/assay/AssayBatchDomainKind.java b/assay/api-src/org/labkey/api/assay/AssayBatchDomainKind.java index 890cfec7691..9ff76997f1c 100644 --- a/assay/api-src/org/labkey/api/assay/AssayBatchDomainKind.java +++ b/assay/api-src/org/labkey/api/assay/AssayBatchDomainKind.java @@ -25,10 +25,6 @@ import java.util.Arrays; import java.util.Set; -/** - * User: jeckels - * Date: Jan 27, 2012 - */ public class AssayBatchDomainKind extends AssayDomainKind { private static final Set RESERVED_NAMES; @@ -50,7 +46,7 @@ public String getKindName() } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_NAMES; } diff --git a/assay/api-src/org/labkey/api/assay/AssayResultDomainKind.java b/assay/api-src/org/labkey/api/assay/AssayResultDomainKind.java index c6de4802ecb..6ac6c91682b 100644 --- a/assay/api-src/org/labkey/api/assay/AssayResultDomainKind.java +++ b/assay/api-src/org/labkey/api/assay/AssayResultDomainKind.java @@ -127,7 +127,7 @@ public DbSchema getSchema() } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_NAMES; } diff --git a/assay/api-src/org/labkey/api/assay/AssayRunDomainKind.java b/assay/api-src/org/labkey/api/assay/AssayRunDomainKind.java index 2915b7a10d6..9d7a0ab3bf4 100644 --- a/assay/api-src/org/labkey/api/assay/AssayRunDomainKind.java +++ b/assay/api-src/org/labkey/api/assay/AssayRunDomainKind.java @@ -53,7 +53,7 @@ public String getKindName() } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_NAMES; } diff --git a/assay/src/org/labkey/assay/DefaultAssayDomainKind.java b/assay/src/org/labkey/assay/DefaultAssayDomainKind.java index 56fef31c8f8..b8bdd764277 100644 --- a/assay/src/org/labkey/assay/DefaultAssayDomainKind.java +++ b/assay/src/org/labkey/assay/DefaultAssayDomainKind.java @@ -43,7 +43,7 @@ public String getKindName() } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return getAssayReservedPropertyNames(); } diff --git a/assay/src/org/labkey/assay/PlateBasedAssaySampleTypeDomainKind.java b/assay/src/org/labkey/assay/PlateBasedAssaySampleTypeDomainKind.java index 9ab3ad3a777..772e1d30907 100644 --- a/assay/src/org/labkey/assay/PlateBasedAssaySampleTypeDomainKind.java +++ b/assay/src/org/labkey/assay/PlateBasedAssaySampleTypeDomainKind.java @@ -55,12 +55,6 @@ public String getKindName() { return null; } - - @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) - { - return Collections.emptySet(); - } }; } diff --git a/assay/src/org/labkey/assay/plate/PlateMetadataDomainKind.java b/assay/src/org/labkey/assay/plate/PlateMetadataDomainKind.java index 88d82a3a52e..e160a02edb8 100644 --- a/assay/src/org/labkey/assay/plate/PlateMetadataDomainKind.java +++ b/assay/src/org/labkey/assay/plate/PlateMetadataDomainKind.java @@ -217,7 +217,7 @@ public SQLFragment sqlObjectIdsInDomain(Domain domain) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_NAMES; } diff --git a/assay/src/org/labkey/assay/plate/PlateReplicateStatsDomainKind.java b/assay/src/org/labkey/assay/plate/PlateReplicateStatsDomainKind.java index a25e0911006..60cfa796b1e 100644 --- a/assay/src/org/labkey/assay/plate/PlateReplicateStatsDomainKind.java +++ b/assay/src/org/labkey/assay/plate/PlateReplicateStatsDomainKind.java @@ -51,7 +51,7 @@ public String getKindName() } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return getAssayReservedPropertyNames(); } diff --git a/core/src/org/labkey/core/query/UsersDomainKind.java b/core/src/org/labkey/core/query/UsersDomainKind.java index 34f17f07dbe..db44d254cdf 100644 --- a/core/src/org/labkey/core/query/UsersDomainKind.java +++ b/core/src/org/labkey/core/query/UsersDomainKind.java @@ -159,7 +159,7 @@ public Domain createDomain(GWTDomain domain, JSONObject arguments, Container con } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return _reservedNames; } diff --git a/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java b/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java index 097d4ea4df7..d10b8b7700f 100644 --- a/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java +++ b/experiment/src/org/labkey/experiment/api/DataClassDomainKind.java @@ -232,11 +232,9 @@ public Set getBaseProperties(Domain domain) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { - Set reserved = new CaseInsensitiveHashSet(RESERVED_NAMES); - reserved.addAll(getTemplateReservedPropertyNames(domain)); - return reserved; + return RESERVED_NAMES; } @Override diff --git a/experiment/src/org/labkey/experiment/api/VocabularyDomainKind.java b/experiment/src/org/labkey/experiment/api/VocabularyDomainKind.java index 2ffec105742..503f8e5e2c7 100644 --- a/experiment/src/org/labkey/experiment/api/VocabularyDomainKind.java +++ b/experiment/src/org/labkey/experiment/api/VocabularyDomainKind.java @@ -79,7 +79,7 @@ public ActionURL urlShowData(Domain domain, ContainerUser containerUser) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_PROPERTY_NAMES; } diff --git a/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java b/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java index 4148bb6de9c..91418afe2c6 100644 --- a/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java +++ b/experiment/src/org/labkey/experiment/api/property/StorageProvisionerImpl.java @@ -1768,12 +1768,6 @@ public ActionURL urlShowData(Domain domain, ContainerUser containerUser) return null; } - @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) - { - return Collections.emptySet(); - } - @Override public @Nullable Priority getPriority(String object) { diff --git a/filecontent/src/org/labkey/filecontent/FilePropertiesDomainKind.java b/filecontent/src/org/labkey/filecontent/FilePropertiesDomainKind.java index 3c61bf8678d..8778f92b83b 100644 --- a/filecontent/src/org/labkey/filecontent/FilePropertiesDomainKind.java +++ b/filecontent/src/org/labkey/filecontent/FilePropertiesDomainKind.java @@ -103,7 +103,7 @@ public ActionURL urlEditDefinition(Domain domain, ContainerUser containerUser) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return _reservedFieldSet; } diff --git a/issues/src/org/labkey/issue/query/IssueDefDomainKind.java b/issues/src/org/labkey/issue/query/IssueDefDomainKind.java index 423b63a5e97..dcfed8c8236 100644 --- a/issues/src/org/labkey/issue/query/IssueDefDomainKind.java +++ b/issues/src/org/labkey/issue/query/IssueDefDomainKind.java @@ -114,7 +114,7 @@ public String getKindName() } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_NAMES; } diff --git a/list/src/org/labkey/list/model/ListDomainKind.java b/list/src/org/labkey/list/model/ListDomainKind.java index a5e5a048b66..e52703a2c43 100644 --- a/list/src/org/labkey/list/model/ListDomainKind.java +++ b/list/src/org/labkey/list/model/ListDomainKind.java @@ -247,11 +247,9 @@ public PropertyStorageSpec getPropertySpec(PropertyDescriptor pd, Domain domain) abstract Collection getSupportedKeyTypes(); @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { - Set reserved = new CaseInsensitiveHashSet(RESERVED_NAMES); - reserved.addAll(getTemplateReservedPropertyNames(domain)); - return reserved; + return RESERVED_NAMES; } @Override diff --git a/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java b/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java index bb600684f34..cac1a1e5236 100644 --- a/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/AbstractSpecimenDomainKind.java @@ -141,12 +141,6 @@ public Priority getPriority(String domainURI) return lsid.getNamespacePrefix() != null && getNamespacePrefix().equals(lsid.getNamespacePrefix()) ? Priority.MEDIUM : null; } - @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) - { - return Collections.emptySet(); - } - @Override public DbScope getScope() { diff --git a/study/api-src/org/labkey/api/specimen/model/SpecimenDomainKind.java b/study/api-src/org/labkey/api/specimen/model/SpecimenDomainKind.java index 03d0d8f652e..9dd5da4713a 100644 --- a/study/api-src/org/labkey/api/specimen/model/SpecimenDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/SpecimenDomainKind.java @@ -227,7 +227,7 @@ public ActionURL urlEditDefinition(Domain domain, ContainerUser containerUser) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_FIELD_NAMES; } diff --git a/study/api-src/org/labkey/api/specimen/model/SpecimenEventDomainKind.java b/study/api-src/org/labkey/api/specimen/model/SpecimenEventDomainKind.java index f66ebf80483..7a20501a647 100644 --- a/study/api-src/org/labkey/api/specimen/model/SpecimenEventDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/SpecimenEventDomainKind.java @@ -268,7 +268,7 @@ public ActionURL urlEditDefinition(Domain domain, ContainerUser containerUser) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_FIELD_NAMES; } diff --git a/study/api-src/org/labkey/api/specimen/model/VialDomainKind.java b/study/api-src/org/labkey/api/specimen/model/VialDomainKind.java index b2cbf38da37..af5073e2155 100644 --- a/study/api-src/org/labkey/api/specimen/model/VialDomainKind.java +++ b/study/api-src/org/labkey/api/specimen/model/VialDomainKind.java @@ -231,7 +231,7 @@ public ActionURL urlEditDefinition(Domain domain, ContainerUser containerUser) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_FIELD_NAMES; } diff --git a/study/api-src/org/labkey/api/studydesign/query/AbstractStudyDesignDomainKind.java b/study/api-src/org/labkey/api/studydesign/query/AbstractStudyDesignDomainKind.java index 715af4274b6..d0663c007ae 100644 --- a/study/api-src/org/labkey/api/studydesign/query/AbstractStudyDesignDomainKind.java +++ b/study/api-src/org/labkey/api/studydesign/query/AbstractStudyDesignDomainKind.java @@ -163,7 +163,7 @@ public String getStorageSchemaName() } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { return RESERVED_PROPERTY_NAMES; } diff --git a/study/src/org/labkey/study/model/BaseStudyDomainKind.java b/study/src/org/labkey/study/model/BaseStudyDomainKind.java index c1f7f08728c..4bf945578c4 100644 --- a/study/src/org/labkey/study/model/BaseStudyDomainKind.java +++ b/study/src/org/labkey/study/model/BaseStudyDomainKind.java @@ -73,7 +73,7 @@ public SQLFragment sqlObjectIdsInDomain(Domain domain) protected abstract TableInfo getTableInfo(); @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { TableInfo table = getTableInfo(); return table.getColumnNameSet(); diff --git a/study/src/org/labkey/study/model/ContinuousDatasetDomainKind.java b/study/src/org/labkey/study/model/ContinuousDatasetDomainKind.java index 24029c4e5ee..7f025274051 100644 --- a/study/src/org/labkey/study/model/ContinuousDatasetDomainKind.java +++ b/study/src/org/labkey/study/model/ContinuousDatasetDomainKind.java @@ -56,7 +56,7 @@ public Set getMandatoryPropertyNames(Domain domain) @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { HashSet fields = new HashSet<>(getStudySubjectReservedName(domain)); fields.addAll(DatasetDefinition.DEFAULT_ABSOLUTE_DATE_FIELDS); diff --git a/study/src/org/labkey/study/model/DatasetDomainKind.java b/study/src/org/labkey/study/model/DatasetDomainKind.java index 657d8a15a70..5536501e101 100644 --- a/study/src/org/labkey/study/model/DatasetDomainKind.java +++ b/study/src/org/labkey/study/model/DatasetDomainKind.java @@ -303,9 +303,6 @@ protected Set getStudySubjectReservedName(Domain domain) return Collections.unmodifiableSet(fields); } - @Override - public abstract @NotNull Set getReservedPropertyNames(Domain domain, User user); - @Override public Set getBaseProperties(Domain domain) { diff --git a/study/src/org/labkey/study/model/DateDatasetDomainKind.java b/study/src/org/labkey/study/model/DateDatasetDomainKind.java index 3a0f22f52a3..a1cad2862a3 100644 --- a/study/src/org/labkey/study/model/DateDatasetDomainKind.java +++ b/study/src/org/labkey/study/model/DateDatasetDomainKind.java @@ -58,7 +58,7 @@ public Set getMandatoryPropertyNames(Domain domain) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { HashSet fields = new HashSet<>(getStudySubjectReservedName(domain)); fields.addAll(DatasetDefinition.DEFAULT_RELATIVE_DATE_FIELDS); diff --git a/study/src/org/labkey/study/model/TestDatasetDomainKind.java b/study/src/org/labkey/study/model/TestDatasetDomainKind.java index 6fe00579cc8..ba61eeca166 100644 --- a/study/src/org/labkey/study/model/TestDatasetDomainKind.java +++ b/study/src/org/labkey/study/model/TestDatasetDomainKind.java @@ -22,7 +22,6 @@ import org.labkey.api.study.Study; import org.labkey.api.study.StudyService; -import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -48,12 +47,6 @@ public Priority getPriority(String domainURI) return domainURI.contains(KIND_NAME) ? Priority.MEDIUM : null; } - @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) - { - return Collections.emptySet(); - } - @Override public Set getPropertyIndices(Domain domain) { diff --git a/study/src/org/labkey/study/model/VisitDatasetDomainKind.java b/study/src/org/labkey/study/model/VisitDatasetDomainKind.java index aab7b23f71c..cce1ba38073 100644 --- a/study/src/org/labkey/study/model/VisitDatasetDomainKind.java +++ b/study/src/org/labkey/study/model/VisitDatasetDomainKind.java @@ -60,7 +60,7 @@ public Set getMandatoryPropertyNames(Domain domain) } @Override - public @NotNull Set getReservedPropertyNames(Domain domain, User user) + protected @NotNull Set getKindReservedPropertyNames(Domain domain, User user, boolean forCreate) { Set fields = DomainUtil.getNamesAndLabels(DatasetDefinition.DEFAULT_VISIT_FIELDS); fields.addAll(getStudySubjectReservedName(domain)); From bd20350295ba91a978dd62f168d454eeebc8d15e Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Wed, 20 May 2026 12:14:35 -0700 Subject: [PATCH 6/6] Review feedback --- api/src/org/labkey/api/exp/property/DomainKind.java | 2 ++ .../org/labkey/experiment/api/ExpDataClassDataTestCase.jsp | 4 ++-- .../labkey/experiment/api/ExpProvisionedTableTestHelper.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/api/src/org/labkey/api/exp/property/DomainKind.java b/api/src/org/labkey/api/exp/property/DomainKind.java index e64849c9ddd..0a0e70c4d50 100644 --- a/api/src/org/labkey/api/exp/property/DomainKind.java +++ b/api/src/org/labkey/api/exp/property/DomainKind.java @@ -118,11 +118,13 @@ public Map processArguments(Container container, User user, Map< * * @return set of strings containing the names. This will be compared ignoring case */ + @NotNull public final Set getReservedPropertyNames(Domain domain, User user) { return getReservedPropertyNames(domain, user, false); } + @NotNull public final Set getReservedPropertyNames(Domain domain, User user, boolean forCreate) { Set reserved = new CaseInsensitiveHashSet(getKindReservedPropertyNames(domain, user, forCreate)); diff --git a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp index 6f01330218d..888f2213c99 100644 --- a/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp +++ b/experiment/src/org/labkey/experiment/api/ExpDataClassDataTestCase.jsp @@ -223,7 +223,7 @@ public void nameExpressionScale() throws Exception @Test public void testDataClass() throws Exception { - final Container sub = ContainerManager.createContainer(c, "sub", _user); + final Container sub = ContainerManager.createContainer(c, "subTestDataClass", _user); final String dataClassName = "testing"; List props = List.of( @@ -632,7 +632,7 @@ public void testDomainTemplate() throws Exception @Test public void testContainerDelete() throws Exception { - final Container sub = ContainerManager.createContainer(c, "sub", _user); + final Container sub = ContainerManager.createContainer(c, "subTestContainerDelete", _user); final String dataClassName = "testing"; List props = new ArrayList<>(); diff --git a/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java b/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java index 111cc7b21ab..bd60d1c25e7 100644 --- a/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java +++ b/experiment/src/org/labkey/experiment/api/ExpProvisionedTableTestHelper.java @@ -63,7 +63,7 @@ public Domain createVocabularyTestDomain(User user, Container c) throws Validati prop3.setRangeURI("string"); prop3.setName(colorPropertyName); - GWTDomain domain = new GWTDomain(); + GWTDomain domain = new GWTDomain<>(); domain.setName(domainName); domain.setDescription(domainDescription); domain.setFields(List.of(prop1, prop2, prop3));