1+ /*
2+ * Copyright 2008-2025 the original author or authors.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * https://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+ package org .springframework .batch .core .repository .support ;
17+
18+ import org .junit .jupiter .api .Disabled ;
19+ import org .junit .jupiter .api .Test ;
20+ import org .springframework .batch .core .job .DefaultJobKeyGenerator ;
21+ import org .springframework .batch .core .job .JobExecution ;
22+ import org .springframework .batch .core .job .JobInstance ;
23+ import org .springframework .batch .core .job .JobKeyGenerator ;
24+ import org .springframework .batch .core .job .parameters .JobParameters ;
25+ import org .springframework .batch .core .job .parameters .JobParametersBuilder ;
26+ import org .springframework .batch .core .repository .dao .JobExecutionDao ;
27+ import org .springframework .batch .core .repository .dao .JobInstanceDao ;
28+ import org .springframework .beans .factory .annotation .Autowired ;
29+ import org .springframework .test .util .ReflectionTestUtils ;
30+
31+ import java .math .BigInteger ;
32+ import java .nio .charset .StandardCharsets ;
33+ import java .security .MessageDigest ;
34+ import java .util .Date ;
35+ import java .util .List ;
36+
37+ import static org .junit .jupiter .api .Assertions .*;
38+
39+ /**
40+ * @author Yanming Zhou
41+ */
42+ class MongoJobInstanceDaoIntegrationTests extends AbstractMongoDBDaoIntegrationTests {
43+
44+ @ Autowired
45+ private JobInstanceDao dao ;
46+
47+ private final JobParameters fooParams = new JobParametersBuilder ().addString ("stringKey" , "stringValue" )
48+ .addLong ("longKey" , Long .MAX_VALUE )
49+ .addDouble ("doubleKey" , Double .MAX_VALUE )
50+ .addDate ("dateKey" , new Date (DATE ))
51+ .toJobParameters ();
52+
53+ private static final long DATE = 777 ;
54+
55+ private final String fooJob = "foo" ;
56+
57+ @ Test
58+ void testFindJobInstanceByExecution (@ Autowired JobExecutionDao jobExecutionDao ) {
59+
60+ JobParameters jobParameters = new JobParameters ();
61+ JobInstance jobInstance = dao .createJobInstance ("testInstance" , jobParameters );
62+ JobExecution jobExecution = jobExecutionDao .createJobExecution (jobInstance , jobParameters );
63+
64+ JobInstance returnedInstance = dao .getJobInstance (jobExecution );
65+ assertEquals (jobInstance , returnedInstance );
66+ }
67+
68+ @ Test
69+ void testHexing () throws Exception {
70+ MessageDigest digest = MessageDigest .getInstance ("MD5" );
71+ byte [] bytes = digest .digest ("f78spx" .getBytes (StandardCharsets .UTF_8 ));
72+ StringBuilder output = new StringBuilder ();
73+ for (byte bite : bytes ) {
74+ output .append (String .format ("%02x" , bite ));
75+ }
76+ assertEquals (32 , output .length (), "Wrong hash: " + output );
77+ String value = String .format ("%032x" , new BigInteger (1 , bytes ));
78+ assertEquals (32 , value .length (), "Wrong hash: " + value );
79+ assertEquals (value , output .toString ());
80+ }
81+
82+ @ Disabled ("Not supported yet" )
83+ @ Test
84+ void testJobInstanceWildcard () {
85+ dao .createJobInstance ("anotherJob" , new JobParameters ());
86+ dao .createJobInstance ("someJob" , new JobParameters ());
87+
88+ List <JobInstance > jobInstances = dao .getJobInstances ("*Job" , 0 , 2 );
89+ assertEquals (2 , jobInstances .size ());
90+
91+ for (JobInstance instance : jobInstances ) {
92+ assertTrue (instance .getJobName ().contains ("Job" ));
93+ }
94+
95+ jobInstances = dao .getJobInstances ("Job*" , 0 , 2 );
96+ assertTrue (jobInstances .isEmpty ());
97+ }
98+
99+ @ Test
100+ void testDeleteJobInstance () {
101+ // given
102+ JobInstance jobInstance = dao .createJobInstance ("someTestInstance" , new JobParameters ());
103+
104+ // when
105+ dao .deleteJobInstance (jobInstance );
106+
107+ // then
108+ assertNull (dao .getJobInstance (jobInstance .getId ()));
109+ }
110+
111+ @ Test
112+ void testDefaultJobKeyGeneratorIsUsed () {
113+ JobKeyGenerator jobKeyGenerator = (JobKeyGenerator ) ReflectionTestUtils .getField (dao , "jobKeyGenerator" );
114+ assertNotNull (jobKeyGenerator );
115+ assertEquals (DefaultJobKeyGenerator .class , jobKeyGenerator .getClass ());
116+ }
117+
118+ /*
119+ * Create and retrieve a job instance.
120+ */
121+
122+ @ Test
123+ void testCreateAndRetrieve () {
124+
125+ JobInstance fooInstance = dao .createJobInstance (fooJob , fooParams );
126+ assertEquals (fooJob , fooInstance .getJobName ());
127+
128+ JobInstance retrievedInstance = dao .getJobInstance (fooJob , fooParams );
129+ assertNotNull (retrievedInstance );
130+ assertEquals (fooInstance , retrievedInstance );
131+ assertEquals (fooJob , retrievedInstance .getJobName ());
132+ }
133+
134+ /*
135+ * Create and retrieve a job instance.
136+ */
137+
138+ @ Test
139+ void testCreateAndGetById () {
140+
141+ JobInstance fooInstance = dao .createJobInstance (fooJob , fooParams );
142+ assertEquals (fooJob , fooInstance .getJobName ());
143+
144+ JobInstance retrievedInstance = dao .getJobInstance (fooInstance .getId ());
145+ assertNotNull (retrievedInstance );
146+ assertEquals (fooInstance , retrievedInstance );
147+ assertEquals (fooJob , retrievedInstance .getJobName ());
148+ }
149+
150+ /*
151+ * Create and retrieve a job instance.
152+ */
153+
154+ @ Test
155+ void testGetMissingById () {
156+
157+ JobInstance retrievedInstance = dao .getJobInstance (1111111L );
158+ assertNull (retrievedInstance );
159+
160+ }
161+
162+ /*
163+ * Create and retrieve a job instance.
164+ */
165+
166+ @ Test
167+ void testGetJobNames () {
168+
169+ testCreateAndRetrieve ();
170+ List <String > jobNames = dao .getJobNames ();
171+ assertFalse (jobNames .isEmpty ());
172+ assertTrue (jobNames .contains (fooJob ));
173+
174+ }
175+
176+ /**
177+ * Create and retrieve a job instance.
178+ */
179+
180+ @ Test
181+ void testGetLastInstances () {
182+
183+ testCreateAndRetrieve ();
184+
185+ // unrelated job instance that should be ignored by the query
186+ dao .createJobInstance ("anotherJob" , new JobParameters ());
187+
188+ // we need two instances of the same job to check ordering
189+ dao .createJobInstance (fooJob , new JobParameters ());
190+
191+ List <JobInstance > jobInstances = dao .getJobInstances (fooJob , 0 , 2 );
192+ assertEquals (2 , jobInstances .size ());
193+ assertEquals (fooJob , jobInstances .get (0 ).getJobName ());
194+ assertEquals (fooJob , jobInstances .get (1 ).getJobName ());
195+ // assertEquals(Integer.valueOf(0), jobInstances.get(0).getVersion());
196+ // assertEquals(Integer.valueOf(0), jobInstances.get(1).getVersion());
197+
198+ assertTrue (jobInstances .get (0 ).getId () > jobInstances .get (1 ).getId (),
199+ "Last instance should be first on the list" );
200+
201+ }
202+
203+ @ Test
204+ void testGetLastInstance () {
205+ testCreateAndRetrieve ();
206+
207+ // unrelated job instance that should be ignored by the query
208+ dao .createJobInstance ("anotherJob" , new JobParameters ());
209+
210+ // we need two instances of the same job to check ordering
211+ dao .createJobInstance (fooJob , new JobParameters ());
212+
213+ List <JobInstance > jobInstances = dao .getJobInstances (fooJob , 0 , 2 );
214+ assertEquals (2 , jobInstances .size ());
215+ JobInstance lastJobInstance = dao .getLastJobInstance (fooJob );
216+ assertNotNull (lastJobInstance );
217+ assertEquals (fooJob , lastJobInstance .getJobName ());
218+ assertEquals (jobInstances .get (0 ), lastJobInstance , "Last instance should be first on the list" );
219+ }
220+
221+ @ Test
222+ void testGetLastInstanceWhenNoInstance () {
223+ JobInstance lastJobInstance = dao .getLastJobInstance ("NonExistingJob" );
224+ assertNull (lastJobInstance );
225+ }
226+
227+ /**
228+ * Create and retrieve a job instance.
229+ */
230+
231+ @ Test
232+ void testGetLastInstancesPaged () {
233+
234+ testCreateAndRetrieve ();
235+
236+ // unrelated job instance that should be ignored by the query
237+ dao .createJobInstance ("anotherJob" , new JobParameters ());
238+
239+ // we need multiple instances of the same job to check ordering
240+ String multiInstanceJob = "multiInstanceJob" ;
241+ String paramKey = "myID" ;
242+ int instanceCount = 6 ;
243+ for (int i = 1 ; i <= instanceCount ; i ++) {
244+ JobParameters params = new JobParametersBuilder ().addLong (paramKey , (long ) i ).toJobParameters ();
245+ dao .createJobInstance (multiInstanceJob , params );
246+ }
247+
248+ int startIndex = 3 ;
249+ int queryCount = 2 ;
250+ List <JobInstance > jobInstances = dao .getJobInstances (multiInstanceJob , startIndex , queryCount );
251+
252+ assertEquals (queryCount , jobInstances .size ());
253+
254+ for (int i = 0 ; i < queryCount ; i ++) {
255+ JobInstance returnedInstance = jobInstances .get (i );
256+ assertEquals (multiInstanceJob , returnedInstance .getJobName ());
257+ // assertEquals(Integer.valueOf(0), returnedInstance.getVersion());
258+
259+ // checks the correct instances are returned and the order is descending
260+ // assertEquals(instanceCount - startIndex - i ,
261+ // returnedInstance.getJobParameters().getLong(paramKey));
262+ }
263+
264+ }
265+
266+ /**
267+ * Create and retrieve a job instance.
268+ */
269+
270+ @ Test
271+ void testGetLastInstancesPastEnd () {
272+
273+ testCreateAndRetrieve ();
274+
275+ // unrelated job instance that should be ignored by the query
276+ dao .createJobInstance ("anotherJob" , new JobParameters ());
277+
278+ // we need two instances of the same job to check ordering
279+ dao .createJobInstance (fooJob , new JobParameters ());
280+
281+ assertEquals (1 , dao .getJobInstances (fooJob , 0 , 1 ).size ());
282+ assertEquals (2 , dao .getJobInstances (fooJob , 0 , 2 ).size ());
283+ assertEquals (2 , dao .getJobInstances (fooJob , 0 , 3 ).size ());
284+ assertEquals (1 , dao .getJobInstances (fooJob , 1 , 3 ).size ());
285+ assertEquals (0 , dao .getJobInstances (fooJob , 0 , 0 ).size ());
286+ assertEquals (0 , dao .getJobInstances (fooJob , 4 , 2 ).size ());
287+
288+ }
289+
290+ /**
291+ * Trying to create instance twice for the same job+parameters causes error
292+ */
293+
294+ @ Test
295+ void testCreateDuplicateInstance () {
296+
297+ dao .createJobInstance (fooJob , fooParams );
298+
299+ assertThrows (IllegalStateException .class , () -> dao .createJobInstance (fooJob , fooParams ));
300+ }
301+
302+ @ Disabled ("Version is not persisted" )
303+ @ Test
304+ void testCreationAddsVersion () {
305+
306+ JobInstance jobInstance = new JobInstance (1L , "testVersionAndId" );
307+
308+ assertNull (jobInstance .getVersion ());
309+
310+ jobInstance = dao .createJobInstance ("testVersion" , new JobParameters ());
311+
312+ assertNotNull (jobInstance .getVersion ());
313+ }
314+
315+ }
0 commit comments