Skip to content

Commit f8f44b7

Browse files
Merge 25.9 to develop
2 parents 0c6e100 + 9eff583 commit f8f44b7

2 files changed

Lines changed: 102 additions & 12 deletions

File tree

src/org/labkey/remoteapi/issues/IssueModel.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.labkey.remoteapi.issues;
22

33
import org.json.JSONObject;
4+
import org.json.JSONParserConfiguration;
45
import org.labkey.api.collections.CaseInsensitiveHashMap;
56

67
import java.io.File;
@@ -27,7 +28,8 @@ public IssueModel setProperties(Map<String, String> properties)
2728

2829
public JSONObject toJSON()
2930
{
30-
var json = new JSONObject(_properties);
31+
// Ensure that null values are sent instead of omitted
32+
var json = new JSONObject(_properties, new JSONParserConfiguration().withUseNativeNulls(true));
3133

3234
// handle attachments
3335
if (!_attachments.isEmpty())

src/org/labkey/test/tests/issues/IssueAPITest.java

Lines changed: 99 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
import org.labkey.remoteapi.issues.IssueResponseModel;
1313
import org.labkey.remoteapi.issues.IssuesCommand;
1414
import org.labkey.test.BaseWebDriverTest;
15+
import org.labkey.test.Locator;
1516
import org.labkey.test.TestFileUtils;
1617
import org.labkey.test.categories.Daily;
1718
import org.labkey.test.categories.Issues;
19+
import org.labkey.test.pages.issues.IssuesAdminPage;
20+
import org.labkey.test.params.FieldDefinition;
1821
import org.labkey.test.util.APIUserHelper;
1922
import org.labkey.test.util.ApiPermissionsHelper;
2023
import org.labkey.test.util.IssuesHelper;
@@ -24,7 +27,6 @@
2427
import java.util.ArrayList;
2528
import java.util.Arrays;
2629
import java.util.List;
27-
import java.util.stream.Collectors;
2830

2931
import static org.hamcrest.CoreMatchers.containsString;
3032
import static org.hamcrest.MatcherAssert.assertThat;
@@ -36,9 +38,11 @@
3638
@Category({Issues.class, Daily.class})
3739
public class IssueAPITest extends BaseWebDriverTest
3840
{
41+
public static final String CUSTOM_REQUIRED_FIELD = "CustomField";
3942
IssuesHelper _issuesHelper = new IssuesHelper(this);
4043
APIUserHelper _userHelper = new APIUserHelper(this);
4144
static String ISSUES = "issues";
45+
static String ISSUES_WITH_REQUIRED = "required";
4246
static Integer TEST_USER_ID;
4347
static String TEST_USER_NAME;
4448
static String TEST_USER_DISPLAY_NAME;
@@ -60,6 +64,12 @@ private void doSetup()
6064
_containerHelper.createProject(getProjectName(), null);
6165
_issuesHelper.createNewIssuesList(ISSUES, getContainerHelper());
6266

67+
_issuesHelper.createNewIssuesList(ISSUES_WITH_REQUIRED, getContainerHelper());
68+
clickAndWait(Locator.linkWithText(ISSUES_WITH_REQUIRED));
69+
IssuesAdminPage adminPage = _issuesHelper.goToAdmin();
70+
adminPage.getFieldsPanel().addField(new FieldDefinition(CUSTOM_REQUIRED_FIELD, FieldDefinition.ColumnType.String).setRequired(true));
71+
adminPage.clickSave();
72+
6373
TEST_USER_NAME = getUsername();
6474
TEST_USER_ID = _userHelper.getUserId(TEST_USER_NAME);
6575
TEST_USER_DISPLAY_NAME = _userHelper.getDisplayNameForEmail(TEST_USER_NAME);
@@ -98,6 +108,76 @@ public void testInsertAnIssue() throws Exception
98108
assertEquals("expect a single attachment", List.of(testFile.getName()), attachments);
99109
}
100110

111+
@Test
112+
public void testUpdateAnIssueWithRequiredField() throws Exception
113+
{
114+
// First try inserting without a required custom field
115+
IssueModel testIssue = basicIssueModel("Custom field test issue", "Let's see if we can update this");
116+
testIssue.setIssueDefName(ISSUES_WITH_REQUIRED);
117+
IssuesCommand cmd = new IssuesCommand();
118+
cmd.setIssues(List.of(testIssue));
119+
final String expectedError = "Missing value for required property: CustomField";
120+
try
121+
{
122+
cmd.execute(createDefaultConnection(), getProjectName());
123+
fail("Should have thrown an exception because the required field was not set");
124+
}
125+
catch (CommandException expectedFailure)
126+
{
127+
assertEquals(expectedError, expectedFailure.getMessage());
128+
}
129+
130+
// Retry, supplying a value
131+
String customFieldValue = "test value";
132+
testIssue.setProp(CUSTOM_REQUIRED_FIELD, customFieldValue);
133+
IssueResponse response = cmd.execute(createDefaultConnection(), getProjectName());
134+
assertEquals(1, response.getIssueIds().size());
135+
136+
// Update without including the custom field, ensuring that the old value is retained
137+
IssueModel toUpdate = new IssueModel();
138+
toUpdate.setIssueId(response.getIssueIds().get(0));
139+
final String updatedTitle = "Updated custom field test issue";
140+
toUpdate.setTitle(updatedTitle);
141+
toUpdate.setIssueDefName(ISSUES_WITH_REQUIRED);
142+
toUpdate.setAction(IssueModel.IssueAction.update);
143+
IssueResponse updateResponse = new IssuesCommand(List.of(toUpdate)).execute(createDefaultConnection(), getProjectName());
144+
assertEquals(1, updateResponse.getIssueIds().size());
145+
146+
IssueResponseModel updatedIssue = getIssueResponse(updateResponse.getIssueIds().get(0));
147+
assertEquals(updatedTitle, updatedIssue.getTitle());
148+
assertEquals(customFieldValue, updatedIssue.getProperties(CUSTOM_REQUIRED_FIELD));
149+
150+
// Update with a new value for the custom field
151+
toUpdate = new IssueModel();
152+
toUpdate.setIssueId(response.getIssueIds().get(0));
153+
toUpdate.setIssueDefName(ISSUES_WITH_REQUIRED);
154+
toUpdate.setAction(IssueModel.IssueAction.update);
155+
final String newCustomFieldValue = "new value";
156+
toUpdate.setProp(CUSTOM_REQUIRED_FIELD, newCustomFieldValue);
157+
updateResponse = new IssuesCommand(List.of(toUpdate)).execute(createDefaultConnection(), getProjectName());
158+
assertEquals(1, updateResponse.getIssueIds().size());
159+
160+
updatedIssue = getIssueResponse(updateResponse.getIssueIds().get(0));
161+
assertEquals(updatedTitle, updatedIssue.getTitle());
162+
assertEquals(newCustomFieldValue, updatedIssue.getProperties(CUSTOM_REQUIRED_FIELD));
163+
164+
// Attempt an update setting the value to null, which should fail
165+
toUpdate = new IssueModel();
166+
toUpdate.setIssueId(response.getIssueIds().get(0));
167+
toUpdate.setIssueDefName(ISSUES_WITH_REQUIRED);
168+
toUpdate.setAction(IssueModel.IssueAction.update);
169+
toUpdate.setProp(CUSTOM_REQUIRED_FIELD, null);
170+
try
171+
{
172+
new IssuesCommand(List.of(toUpdate)).execute(createDefaultConnection(), getProjectName());
173+
fail("Should have thrown an exception because the required field was set to null");
174+
}
175+
catch (CommandException expectedFailure)
176+
{
177+
assertEquals(expectedError, expectedFailure.getMessage());
178+
}
179+
}
180+
101181
@Test
102182
public void testUpdateAnIssue() throws Exception
103183
{
@@ -107,7 +187,9 @@ public void testUpdateAnIssue() throws Exception
107187
String title = "Updated issue test issue";
108188
Integer updatedPri = 4;
109189
IssueModel originalIssue = basicIssueModel(originalTitle, originalComment);
110-
IssueModel updateIssue = basicIssueModel(title, comment)
190+
IssueModel updateIssue = new IssueModel()
191+
.setTitle(title)
192+
.setComment(comment)
111193
.setAction(IssueModel.IssueAction.update)
112194
.setPriority(updatedPri);
113195

@@ -136,7 +218,9 @@ public void testResolveAnIssue() throws Exception
136218
Integer updatedPri = 4;
137219
IssueModel originalIssue = basicIssueModel(originalTitle, originalComment);
138220

139-
IssueModel resolveIssue = basicIssueModel(newTitle, newComment)
221+
IssueModel resolveIssue = new IssueModel()
222+
.setTitle(newTitle)
223+
.setComment(newComment)
140224
.setAction(IssueModel.IssueAction.resolve)
141225
.setResolution("Fixed")
142226
.setPriority(updatedPri);
@@ -165,7 +249,9 @@ public void testCloseAnIssue() throws Exception
165249
String newTitle = "Closed test issue";
166250
Integer updatedPri = 4;
167251
IssueModel originalIssue = basicIssueModel(originalTitle, originalComment);
168-
IssueModel closeIssue = basicIssueModel(newTitle, newComment)
252+
IssueModel closeIssue = new IssueModel()
253+
.setTitle(newTitle)
254+
.setComment(newComment)
169255
.setAction(IssueModel.IssueAction.close)
170256
.setPriority(updatedPri);
171257

@@ -187,7 +273,8 @@ public void testAssignAnIssue() throws Exception
187273
{
188274
String title = "Assign Test Issue";
189275
IssueModel originalIssue = basicIssueModel(title, "Gonna assign this");
190-
IssueModel updateIssue = basicIssueModel(null, "assigned now")
276+
IssueModel updateIssue = new IssueModel()
277+
.setComment("assigned now")
191278
.setAction(IssueModel.IssueAction.update)
192279
.setAssignedTo(TEST_BUDDY_ID);
193280

@@ -208,9 +295,9 @@ public void testAssignAnIssue() throws Exception
208295
public void testReopenAnIssue() throws Exception
209296
{
210297
IssueModel originalIssue = basicIssueModel("Reopen test issue", "Gonna close and reopen this");
211-
IssueModel closeIssue = basicIssueModel(null, null)
298+
IssueModel closeIssue = new IssueModel()
212299
.setAction(IssueModel.IssueAction.close);
213-
IssueModel reopenIssue = basicIssueModel(null, null)
300+
IssueModel reopenIssue = new IssueModel()
214301
.setAction(IssueModel.IssueAction.reopen);
215302

216303
// insert
@@ -267,10 +354,11 @@ public void testResolveAClosedIssue() throws Exception
267354

268355
var issueId = doIssueAction(issue);
269356

270-
IssueModel close = basicIssueModel(null, null).setAction(IssueModel.IssueAction.close)
271-
.setIssueId(issueId);
272-
IssueModel resolve = basicIssueModel(null, null).setAction(IssueModel.IssueAction.resolve)
357+
IssueModel close = new IssueModel().setAction(IssueModel.IssueAction.close)
273358
.setIssueId(issueId);
359+
IssueModel resolve = new IssueModel().setAction(IssueModel.IssueAction.resolve)
360+
.setIssueId(issueId).
361+
setAssignedTo(TEST_USER_ID);
274362

275363
doIssueAction(close);
276364
var closedResponse = getIssueResponse(issueId);
@@ -303,7 +391,7 @@ public void testUpdateMultipleIssues() throws Exception
303391
insertCmd.setIssues(issues);
304392
var insertResponse = insertCmd.execute(createDefaultConnection(), getProjectName());
305393
List<Long> issueIds = insertResponse.getIssueIds();
306-
var distinctIds = issueIds.stream().distinct().collect(Collectors.toList());
394+
var distinctIds = issueIds.stream().distinct().toList();
307395
// ensure we got as many issueIDs back as we sent issues in
308396
assertEquals("Expect to get as many issueIds as there are inputs", issues.size(), issueIds.size());
309397
// make sure we didn't get a list of IDs with duplicates

0 commit comments

Comments
 (0)