1212import org .labkey .remoteapi .issues .IssueResponseModel ;
1313import org .labkey .remoteapi .issues .IssuesCommand ;
1414import org .labkey .test .BaseWebDriverTest ;
15+ import org .labkey .test .Locator ;
1516import org .labkey .test .TestFileUtils ;
1617import org .labkey .test .categories .Daily ;
1718import org .labkey .test .categories .Issues ;
19+ import org .labkey .test .pages .issues .IssuesAdminPage ;
20+ import org .labkey .test .params .FieldDefinition ;
1821import org .labkey .test .util .APIUserHelper ;
1922import org .labkey .test .util .ApiPermissionsHelper ;
2023import org .labkey .test .util .IssuesHelper ;
2427import java .util .ArrayList ;
2528import java .util .Arrays ;
2629import java .util .List ;
27- import java .util .stream .Collectors ;
2830
2931import static org .hamcrest .CoreMatchers .containsString ;
3032import static org .hamcrest .MatcherAssert .assertThat ;
3638@ Category ({Issues .class , Daily .class })
3739public 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