View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit;
7   
8   import static org.junit.jupiter.api.Assertions.assertEquals;
9   import static org.junit.jupiter.api.Assertions.assertFalse;
10  import static org.junit.jupiter.api.Assertions.assertNotNull;
11  import static org.junit.jupiter.api.Assertions.assertNotSame;
12  import static org.junit.jupiter.api.Assertions.assertNull;
13  import static org.junit.jupiter.api.Assertions.assertSame;
14  import static org.junit.jupiter.api.Assertions.assertTrue;
15  import static org.junit.jupiter.api.Assertions.fail;
16  
17  import jakarta.annotation.PostConstruct;
18  import jakarta.annotation.PreDestroy;
19  import jakarta.annotation.Resource;
20  import jakarta.ejb.EJB;
21  import jakarta.inject.Inject;
22  import jakarta.persistence.Cache;
23  import jakarta.persistence.CacheRetrieveMode;
24  import jakarta.persistence.CacheStoreMode;
25  import jakarta.persistence.ConnectionConsumer;
26  import jakarta.persistence.ConnectionFunction;
27  import jakarta.persistence.EntityGraph;
28  import jakarta.persistence.EntityManager;
29  import jakarta.persistence.EntityManagerFactory;
30  import jakarta.persistence.EntityTransaction;
31  import jakarta.persistence.FindOption;
32  import jakarta.persistence.FlushModeType;
33  import jakarta.persistence.LockModeType;
34  import jakarta.persistence.LockOption;
35  import jakarta.persistence.Persistence;
36  import jakarta.persistence.PersistenceContext;
37  import jakarta.persistence.PersistenceUnit;
38  import jakarta.persistence.PersistenceUnitTransactionType;
39  import jakarta.persistence.PersistenceUnitUtil;
40  import jakarta.persistence.Query;
41  import jakarta.persistence.RefreshOption;
42  import jakarta.persistence.SchemaManager;
43  import jakarta.persistence.StoredProcedureQuery;
44  import jakarta.persistence.SynchronizationType;
45  import jakarta.persistence.TypedQuery;
46  import jakarta.persistence.TypedQueryReference;
47  import jakarta.persistence.criteria.CriteriaBuilder;
48  import jakarta.persistence.criteria.CriteriaDelete;
49  import jakarta.persistence.criteria.CriteriaQuery;
50  import jakarta.persistence.criteria.CriteriaSelect;
51  import jakarta.persistence.criteria.CriteriaUpdate;
52  import jakarta.persistence.metamodel.Metamodel;
53  import jakarta.servlet.ServletContext;
54  import jakarta.servlet.http.HttpSession;
55  
56  import java.io.File;
57  import java.io.IOException;
58  import java.io.Writer;
59  import java.net.URI;
60  import java.net.URISyntaxException;
61  import java.nio.charset.StandardCharsets;
62  import java.nio.file.Files;
63  import java.nio.file.Path;
64  import java.util.List;
65  import java.util.Map;
66  import java.util.function.Consumer;
67  import java.util.function.Function;
68  
69  import mockit.integration.junit5.JMockitExtension;
70  
71  import org.junit.jupiter.api.AfterAll;
72  import org.junit.jupiter.api.AfterEach;
73  import org.junit.jupiter.api.BeforeAll;
74  import org.junit.jupiter.api.MethodOrderer.MethodName;
75  import org.junit.jupiter.api.Test;
76  import org.junit.jupiter.api.TestMethodOrder;
77  import org.junit.jupiter.api.extension.ExtendWith;
78  
79  /**
80   * The Class TestedClassWithFullStandardDITest.
81   */
82  @ExtendWith(JMockitExtension.class)
83  @TestMethodOrder(MethodName.class)
84  class TestedClassWithFullStandardDITest {
85  
86      /**
87       * The Class TestedClass.
88       */
89      public static class TestedClass {
90  
91          /** The dependency to be mocked. */
92          @Inject
93          private Runnable dependencyToBeMocked;
94  
95          /** The dependency 2. */
96          @Inject
97          private FirstLevelDependency dependency2;
98  
99          /** The dependency 3. */
100         @Resource
101         private FirstLevelDependency dependency3;
102 
103         /** The common dependency. */
104         @Inject
105         private CommonDependency commonDependency;
106 
107         /** The text. */
108         String text;
109 
110         /** The initialized. */
111         boolean initialized;
112 
113         /** The destroyed. */
114         static boolean destroyed;
115 
116         /**
117          * Initialize.
118          */
119         @PostConstruct
120         void initialize() {
121             assertNotNull(dependency3);
122             initialized = true;
123         }
124 
125         /**
126          * Destroy.
127          */
128         @PreDestroy
129         void destroy() {
130             assertTrue(initialized, "TestedClass not initialized");
131             destroyed = true;
132         }
133     }
134 
135     /**
136      * The Class AnotherTestedClass.
137      */
138     static final class AnotherTestedClass {
139 
140         /** The em. */
141         @PersistenceContext
142         EntityManager em;
143 
144         /** The session. */
145         @Inject
146         HttpSession session;
147 
148         /** The application context. */
149         @Inject
150         ServletContext applicationContext;
151     }
152 
153     /**
154      * The Class FirstLevelDependency.
155      */
156     public static class FirstLevelDependency {
157 
158         /** The dependency. */
159         @EJB
160         private SecondLevelDependency dependency;
161 
162         /** The static dependency. */
163         @Inject
164         private static SecondLevelDependency staticDependency;
165 
166         /** The common dependency. */
167         @Inject
168         private CommonDependency commonDependency;
169 
170         /** The dependency to be mocked. */
171         @Resource
172         private static Runnable dependencyToBeMocked;
173 
174         /** The em. */
175         @PersistenceContext
176         private EntityManager em;
177     }
178 
179     /**
180      * The Class SecondLevelDependency.
181      */
182     public static class SecondLevelDependency {
183 
184         /** The common dependency. */
185         @Inject
186         CommonDependency commonDependency;
187 
188         /** The em. */
189         @PersistenceContext
190         private EntityManager em;
191 
192         /** The servlet context. */
193         @Inject
194         ServletContext servletContext;
195 
196         /** The http session. */
197         @Inject
198         HttpSession httpSession;
199 
200         /** The initialized. */
201         boolean initialized;
202 
203         /** The terminated. */
204         static boolean terminated;
205 
206         /**
207          * Initialize.
208          */
209         @PostConstruct
210         void initialize() {
211             initialized = true;
212         }
213 
214         /**
215          * Terminate.
216          */
217         @PreDestroy
218         void terminate() {
219             terminated = true;
220         }
221     }
222 
223     /**
224      * The Class CommonDependency.
225      */
226     public static class CommonDependency {
227 
228         /** The em factory. */
229         @PersistenceUnit(unitName = "test")
230         private EntityManagerFactory emFactory;
231 
232         /** The em. */
233         @PersistenceContext(unitName = "test")
234         private EntityManager em;
235     }
236 
237     /** The tested. */
238     @Tested(fullyInitialized = true)
239     TestedClass tested;
240 
241     /** The tested 2. */
242     @Tested(fullyInitialized = true)
243     AnotherTestedClass tested2;
244 
245     /** The mocked dependency. */
246     @Injectable
247     Runnable mockedDependency;
248 
249     /** The persistence xml file. */
250     static File persistenceXmlFile;
251 
252     /** The named EM factory. */
253     static EntityManagerFactory namedEMFactory;
254 
255     /** The named EM. */
256     static EntityManager namedEM;
257 
258     /** The default EM factory. */
259     static EntityManagerFactory defaultEMFactory;
260 
261     /** The default EM. */
262     static EntityManager defaultEM;
263 
264     /**
265      * Sets the up persistence.
266      *
267      * @throws Exception
268      *             the exception
269      */
270     @BeforeAll
271     @SuppressWarnings("rawtypes")
272     static void setUpPersistence() throws Exception {
273         final class FakeEntityManager implements EntityManager {
274             @Override
275             public void persist(Object entity) {
276             }
277 
278             @Override
279             public <T> T merge(T entity) {
280                 return null;
281             }
282 
283             @Override
284             public void remove(Object entity) {
285             }
286 
287             @Override
288             public <T> T find(Class<T> entityClass, Object primaryKey) {
289                 return null;
290             }
291 
292             @Override
293             public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
294                 return null;
295             }
296 
297             @Override
298             public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
299                 return null;
300             }
301 
302             @Override
303             public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode,
304                     Map<String, Object> properties) {
305                 return null;
306             }
307 
308             @Override
309             public <T> T getReference(Class<T> entityClass, Object primaryKey) {
310                 return null;
311             }
312 
313             @Override
314             public void flush() {
315             }
316 
317             @Override
318             public void setFlushMode(FlushModeType flushMode) {
319             }
320 
321             @Override
322             public FlushModeType getFlushMode() {
323                 return null;
324             }
325 
326             @Override
327             public void lock(Object entity, LockModeType lockMode) {
328             }
329 
330             @Override
331             public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
332             }
333 
334             @Override
335             public void refresh(Object entity) {
336             }
337 
338             @Override
339             public void refresh(Object entity, Map<String, Object> properties) {
340             }
341 
342             @Override
343             public void refresh(Object entity, LockModeType lockMode) {
344             }
345 
346             @Override
347             public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
348             }
349 
350             @Override
351             public void clear() {
352             }
353 
354             @Override
355             public void detach(Object entity) {
356             }
357 
358             @Override
359             public boolean contains(Object entity) {
360                 return false;
361             }
362 
363             @Override
364             public LockModeType getLockMode(Object entity) {
365                 return null;
366             }
367 
368             @Override
369             public void setProperty(String propertyName, Object value) {
370             }
371 
372             @Override
373             public Map<String, Object> getProperties() {
374                 return null;
375             }
376 
377             @Override
378             public Query createQuery(String qlString) {
379                 return null;
380             }
381 
382             @Override
383             public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
384                 return null;
385             }
386 
387             @Override
388             public Query createQuery(CriteriaUpdate updateQuery) {
389                 return null;
390             }
391 
392             @Override
393             public Query createQuery(CriteriaDelete deleteQuery) {
394                 return null;
395             }
396 
397             @Override
398             public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
399                 return null;
400             }
401 
402             @Override
403             public Query createNamedQuery(String name) {
404                 return null;
405             }
406 
407             @Override
408             public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
409                 return null;
410             }
411 
412             @Override
413             public Query createNativeQuery(String sqlString) {
414                 return null;
415             }
416 
417             @Override
418             public Query createNativeQuery(String sqlString, Class resultClass) {
419                 return null;
420             }
421 
422             @Override
423             public Query createNativeQuery(String sqlString, String resultSetMapping) {
424                 return null;
425             }
426 
427             @Override
428             public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
429                 return null;
430             }
431 
432             @Override
433             public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
434                 return null;
435             }
436 
437             @Override
438             public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
439                 return null;
440             }
441 
442             @Override
443             public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
444                 return null;
445             }
446 
447             @Override
448             public void joinTransaction() {
449             }
450 
451             @Override
452             public boolean isJoinedToTransaction() {
453                 return false;
454             }
455 
456             @Override
457             public <T> T unwrap(Class<T> cls) {
458                 return null;
459             }
460 
461             @Override
462             public Object getDelegate() {
463                 return null;
464             }
465 
466             @Override
467             public void close() {
468             }
469 
470             @Override
471             public boolean isOpen() {
472                 return false;
473             }
474 
475             @Override
476             public EntityTransaction getTransaction() {
477                 return null;
478             }
479 
480             @Override
481             public EntityManagerFactory getEntityManagerFactory() {
482                 return null;
483             }
484 
485             @Override
486             public CriteriaBuilder getCriteriaBuilder() {
487                 return null;
488             }
489 
490             @Override
491             public Metamodel getMetamodel() {
492                 return null;
493             }
494 
495             @Override
496             public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
497                 return null;
498             }
499 
500             @Override
501             public EntityGraph<?> createEntityGraph(String graphName) {
502                 return null;
503             }
504 
505             @Override
506             public EntityGraph<?> getEntityGraph(String graphName) {
507                 return null;
508             }
509 
510             @Override
511             public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
512                 return null;
513             }
514 
515             @Override
516             public <T> T find(Class<T> entityClass, Object primaryKey, FindOption... options) {
517                 return null;
518             }
519 
520             @Override
521             public <T> T find(EntityGraph<T> entityGraph, Object primaryKey, FindOption... options) {
522                 return null;
523             }
524 
525             @Override
526             public <T> T getReference(T entity) {
527                 return null;
528             }
529 
530             @Override
531             public void lock(Object entity, LockModeType lockMode, LockOption... options) {
532             }
533 
534             @Override
535             public void refresh(Object entity, RefreshOption... options) {
536             }
537 
538             @Override
539             public void setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) {
540             }
541 
542             @Override
543             public void setCacheStoreMode(CacheStoreMode cacheStoreMode) {
544             }
545 
546             @Override
547             public CacheRetrieveMode getCacheRetrieveMode() {
548                 return null;
549             }
550 
551             @Override
552             public CacheStoreMode getCacheStoreMode() {
553                 return null;
554             }
555 
556             @Override
557             public <T> TypedQuery<T> createQuery(CriteriaSelect<T> selectQuery) {
558                 return null;
559             }
560 
561             @Override
562             public <T> TypedQuery<T> createQuery(TypedQueryReference<T> reference) {
563                 return null;
564             }
565 
566             @Override
567             public <C> void runWithConnection(ConnectionConsumer<C> action) {
568             }
569 
570             @Override
571             public <C, T> T callWithConnection(ConnectionFunction<C, T> function) {
572                 return null;
573             }
574         }
575         namedEM = new FakeEntityManager();
576         defaultEM = new FakeEntityManager();
577 
578         final class FakeEntityManagerFactory implements EntityManagerFactory {
579             final EntityManager em;
580 
581             FakeEntityManagerFactory(EntityManager em) {
582                 this.em = em;
583             }
584 
585             @Override
586             public EntityManager createEntityManager() {
587                 return em;
588             }
589 
590             @Override
591             public EntityManager createEntityManager(Map map) {
592                 return null;
593             }
594 
595             @Override
596             public EntityManager createEntityManager(SynchronizationType synchronizationType) {
597                 return null;
598             }
599 
600             @Override
601             public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map) {
602                 return null;
603             }
604 
605             @Override
606             public CriteriaBuilder getCriteriaBuilder() {
607                 return null;
608             }
609 
610             @Override
611             public Metamodel getMetamodel() {
612                 return null;
613             }
614 
615             @Override
616             public boolean isOpen() {
617                 return false;
618             }
619 
620             @Override
621             public void close() {
622             }
623 
624             @Override
625             public Map<String, Object> getProperties() {
626                 return null;
627             }
628 
629             @Override
630             public Cache getCache() {
631                 return null;
632             }
633 
634             @Override
635             public PersistenceUnitUtil getPersistenceUnitUtil() {
636                 return null;
637             }
638 
639             @Override
640             public void addNamedQuery(String name, Query query) {
641             }
642 
643             @Override
644             public <T> T unwrap(Class<T> cls) {
645                 return null;
646             }
647 
648             @Override
649             public <T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph) {
650             }
651 
652             @Override
653             public String getName() {
654                 return null;
655             }
656 
657             @Override
658             public PersistenceUnitTransactionType getTransactionType() {
659                 return null;
660             }
661 
662             @Override
663             public SchemaManager getSchemaManager() {
664                 return null;
665             }
666 
667             @Override
668             public <R> Map<String, TypedQueryReference<R>> getNamedQueries(Class<R> resultType) {
669                 return null;
670             }
671 
672             @Override
673             public <E> Map<String, EntityGraph<? extends E>> getNamedEntityGraphs(Class<E> entityType) {
674                 return null;
675             }
676 
677             @Override
678             public void runInTransaction(Consumer<EntityManager> work) {
679             }
680 
681             @Override
682             public <R> R callInTransaction(Function<EntityManager, R> work) {
683                 return null;
684             }
685         }
686         namedEMFactory = new FakeEntityManagerFactory(namedEM);
687         defaultEMFactory = new FakeEntityManagerFactory(defaultEM);
688 
689         new MockUp<Persistence>() {
690             @Mock
691             EntityManagerFactory createEntityManagerFactory(String persistenceUnitName) {
692                 if ("test".equals(persistenceUnitName)) {
693                     return namedEMFactory;
694                 }
695 
696                 if ("default".equals(persistenceUnitName)) {
697                     return defaultEMFactory;
698                 }
699 
700                 fail("Unexpected persistence unit");
701                 return null;
702             }
703         };
704 
705         createTemporaryPersistenceXmlFileWithDefaultPersistenceUnit();
706     }
707 
708     /**
709      * Creates the temporary persistence xml file with default persistence unit.
710      *
711      * @throws IOException
712      *             Signals that an I/O exception has occurred.
713      * @throws URISyntaxException
714      *             the URI syntax exception
715      */
716     static void createTemporaryPersistenceXmlFileWithDefaultPersistenceUnit() throws IOException, URISyntaxException {
717         URI rootOfClasspath = TestedClass.class.getProtectionDomain().getCodeSource().getLocation().toURI();
718         File tempFolder = Path.of(rootOfClasspath).resolve("META-INF").toFile();
719         if (tempFolder.mkdir()) {
720             tempFolder.deleteOnExit();
721         }
722 
723         persistenceXmlFile = tempFolder.toPath().resolve("persistence.xml").toFile();
724 
725         Writer xmlWriter = Files.newBufferedWriter(persistenceXmlFile.toPath(), StandardCharsets.UTF_8);
726         xmlWriter.write("<persistence><persistence-unit name='default'/></persistence>");
727         xmlWriter.close();
728     }
729 
730     /**
731      * Delete default persistence xml file.
732      */
733     @AfterAll
734     static void deleteDefaultPersistenceXmlFile() {
735         persistenceXmlFile.delete();
736         persistenceXmlFile.getParentFile().delete();
737     }
738 
739     /**
740      * Use fully initialized tested object.
741      */
742     @Test
743     void useFullyInitializedTestedObject() {
744         // First level dependencies:
745         assertSame(mockedDependency, tested.dependencyToBeMocked);
746         assertNotNull(tested.dependency2);
747         assertSame(tested.dependency2, tested.dependency3);
748         assertNotNull(tested.commonDependency);
749         assertNull(tested.text);
750 
751         // Second level dependencies:
752         assertNotNull(tested.dependency2.dependency);
753         assertSame(FirstLevelDependency.staticDependency, tested.dependency2.dependency);
754         assertSame(tested.dependency3.dependency, tested.dependency2.dependency);
755         assertSame(tested.commonDependency, tested.dependency2.commonDependency);
756         assertSame(tested.commonDependency, tested.dependency3.commonDependency);
757         assertSame(mockedDependency, FirstLevelDependency.dependencyToBeMocked);
758         assertSame(mockedDependency, FirstLevelDependency.dependencyToBeMocked);
759         assertSame(defaultEM, tested.dependency2.em);
760         assertSame(tested.dependency2.em, tested.dependency3.em);
761         assertSame(namedEMFactory, tested.commonDependency.emFactory);
762         assertSame(namedEM, tested.commonDependency.em);
763         assertNotSame(tested.dependency2.em, tested.commonDependency.em);
764         assertSame(tested2.em, tested.dependency2.em);
765 
766         // Third level dependencies:
767         assertSame(tested.commonDependency, tested.dependency2.dependency.commonDependency);
768         assertSame(tested.dependency2.em, tested.dependency2.dependency.em);
769 
770         // Lifecycle methods:
771         assertTrue(tested.initialized);
772         assertTrue(tested.dependency2.dependency.initialized);
773     }
774 
775     /**
776      * Use fully initialized tested object again.
777      */
778     @Test
779     void useFullyInitializedTestedObjectAgain() {
780         assertNull(tested.text);
781     }
782 
783     /**
784      * Verify emulated http session.
785      */
786     @Test
787     void verifyEmulatedHttpSession() {
788         HttpSession session = tested2.session;
789         assertFalse(session.isNew());
790         assertFalse(session.getId().isEmpty());
791         assertTrue(session.getCreationTime() > 0);
792         assertTrue(session.getLastAccessedTime() > 0);
793         assertFalse(session.getAttributeNames().hasMoreElements());
794 
795         session.setMaxInactiveInterval(600);
796         assertEquals(600, session.getMaxInactiveInterval());
797 
798         session.setAttribute("test", 123);
799         assertEquals(123, session.getAttribute("test"));
800         assertEquals("test", session.getAttributeNames().nextElement());
801 
802         session.removeAttribute("test");
803         assertNull(session.getAttribute("test"));
804 
805         session.setAttribute("test2", "abc");
806         session.invalidate();
807 
808         try {
809             session.isNew();
810             fail();
811         } catch (IllegalStateException invalidatedSession) {
812             /* ok */ }
813         try {
814             session.getCreationTime();
815             fail();
816         } catch (IllegalStateException invalidatedSession) {
817             /* ok */ }
818         try {
819             session.getLastAccessedTime();
820             fail();
821         } catch (IllegalStateException invalidatedSession) {
822             /* ok */ }
823         try {
824             session.getAttributeNames();
825             fail();
826         } catch (IllegalStateException invalidatedSession) {
827             /* ok */ }
828         try {
829             session.getAttribute("test2");
830             fail();
831         } catch (IllegalStateException invalidatedSession) {
832             /* ok */ }
833         try {
834             session.setAttribute("x", "");
835             fail();
836         } catch (IllegalStateException invalidatedSession) {
837             /* ok */ }
838         try {
839             session.removeAttribute("x");
840             fail();
841         } catch (IllegalStateException invalidatedSession) {
842             /* ok */ }
843         try {
844             session.invalidate();
845             fail();
846         } catch (IllegalStateException invalidatedSession) {
847             /* ok */ }
848 
849         assertSame(tested2.applicationContext, session.getServletContext());
850         assertSame(session, tested.dependency3.dependency.httpSession);
851     }
852 
853     /**
854      * Verify emulated servlet context.
855      */
856     @Test
857     void verifyEmulatedServletContext() {
858         ServletContext ctx = tested2.applicationContext;
859 
860         assertFalse(ctx.getAttributeNames().hasMoreElements());
861 
862         ctx.setInitParameter("test", "abc");
863         assertEquals("abc", ctx.getInitParameter("test"));
864         assertEquals("test", ctx.getInitParameterNames().nextElement());
865 
866         ctx.setAttribute("test", 123);
867         assertEquals(123, ctx.getAttribute("test"));
868         assertEquals("test", ctx.getAttributeNames().nextElement());
869 
870         ctx.removeAttribute("test");
871         assertNull(ctx.getAttribute("test"));
872 
873         assertSame(ctx, tested.dependency2.dependency.servletContext);
874     }
875 
876     /**
877      * Verify that tested fields were cleared and pre destroy methods were executed.
878      */
879     @AfterEach
880     void verifyThatTestedFieldsWereClearedAndPreDestroyMethodsWereExecuted() {
881         assertNull(tested);
882         assertNull(tested2);
883         assertTrue(TestedClass.destroyed);
884         assertTrue(SecondLevelDependency.terminated);
885     }
886 
887     /**
888      * Clear entity managers.
889      */
890     @AfterEach
891     void clearEntityManagers() {
892         namedEM = null;
893         defaultEM = null;
894     }
895 }