2121import static org .junit .jupiter .api .Assertions .assertNotNull ;
2222import static org .junit .jupiter .api .Assertions .assertNull ;
2323import static org .junit .jupiter .api .Assertions .assertThrows ;
24+ import static org .mockito .ArgumentMatchers .any ;
25+ import static org .mockito .ArgumentMatchers .anyInt ;
26+ import static org .mockito .Mockito .doNothing ;
27+ import static org .mockito .Mockito .doReturn ;
28+ import static org .mockito .Mockito .spy ;
2429
2530import java .sql .SQLException ;
2631import java .util .Collections ;
2732import java .util .HashSet ;
2833import java .util .Properties ;
2934import java .util .concurrent .TimeUnit ;
3035import org .junit .jupiter .api .AfterEach ;
36+ import org .junit .jupiter .api .Assertions ;
3137import org .junit .jupiter .api .BeforeEach ;
3238import org .junit .jupiter .api .Test ;
3339import org .mockito .Mock ;
3440import org .mockito .MockitoAnnotations ;
3541import software .amazon .jdbc .dialect .Dialect ;
3642import software .amazon .jdbc .plugin .customendpoint .CustomEndpointMonitorImpl ;
3743import software .amazon .jdbc .targetdriverdialect .TargetDriverDialect ;
44+ import software .amazon .jdbc .util .connection .ConnectionService ;
3845import software .amazon .jdbc .util .events .EventPublisher ;
3946import software .amazon .jdbc .util .storage .StorageService ;
4047import software .amazon .jdbc .util .telemetry .TelemetryFactory ;
4148
4249class MonitorServiceImplTest {
43- @ Mock StorageService storageService ;
44- @ Mock TelemetryFactory telemetryFactory ;
45- @ Mock TargetDriverDialect targetDriverDialect ;
46- @ Mock Dialect dbDialect ;
47- @ Mock EventPublisher publisher ;
48- MonitorServiceImpl monitorService ;
50+ @ Mock StorageService mockStorageService ;
51+ @ Mock ConnectionService mockConnectionService ;
52+ @ Mock TelemetryFactory mockTelemetryFactory ;
53+ @ Mock TargetDriverDialect mockTargetDriverDialect ;
54+ @ Mock Dialect mockDbDialect ;
55+ @ Mock EventPublisher mockPublisher ;
56+ MonitorServiceImpl spyMonitorService ;
4957 private AutoCloseable closeable ;
5058
5159 @ BeforeEach
5260 void setUp () {
5361 closeable = MockitoAnnotations .openMocks (this );
54- monitorService = new MonitorServiceImpl (publisher ) {
55- @ Override
56- protected void initCleanupThread (long cleanupIntervalNanos ) {
57- // Do nothing
58- }
59- };
62+ spyMonitorService = spy (new MonitorServiceImpl (mockPublisher ));
63+ doNothing ().when (spyMonitorService ).initCleanupThread (anyInt ());
64+
65+ try {
66+ doReturn (mockConnectionService ).when (spyMonitorService )
67+ .getConnectionService (any (), any (), any (), any (), any (), any (), any ());
68+ } catch (SQLException e ) {
69+ Assertions .fail (
70+ "Encountered exception while stubbing MonitorServiceImpl#getConnectionService: " + e .getMessage ());
71+ }
6072 }
6173
6274 @ AfterEach
6375 void tearDown () throws Exception {
6476 closeable .close ();
65- monitorService .releaseResources ();
77+ spyMonitorService .releaseResources ();
6678 }
6779
6880 @ Test
6981 public void testMonitorError_monitorReCreated () throws SQLException , InterruptedException {
70- monitorService .registerMonitorTypeIfAbsent (
82+ spyMonitorService .registerMonitorTypeIfAbsent (
7183 NoOpMonitor .class ,
7284 TimeUnit .MINUTES .toNanos (1 ),
7385 TimeUnit .MINUTES .toNanos (1 ),
7486 new HashSet <>(Collections .singletonList (MonitorErrorResponse .RECREATE )),
7587 null
7688 );
7789 String key = "testMonitor" ;
78- NoOpMonitor monitor = monitorService .runIfAbsent (
90+ NoOpMonitor monitor = spyMonitorService .runIfAbsent (
7991 NoOpMonitor .class ,
8092 key ,
81- storageService ,
82- telemetryFactory ,
93+ mockStorageService ,
94+ mockTelemetryFactory ,
8395 "jdbc:postgresql://somehost/somedb" ,
8496 "someProtocol" ,
85- targetDriverDialect ,
86- dbDialect ,
97+ mockTargetDriverDialect ,
98+ mockDbDialect ,
8799 new Properties (),
88- (connectionService , pluginService ) -> new NoOpMonitor (monitorService , 30 )
100+ (connectionService , pluginService ) -> new NoOpMonitor (spyMonitorService , 30 )
89101 );
90102
91- Monitor storedMonitor = monitorService .get (NoOpMonitor .class , key );
103+ Monitor storedMonitor = spyMonitorService .get (NoOpMonitor .class , key );
92104 assertNotNull (storedMonitor );
93105 assertEquals (monitor , storedMonitor );
94106 // need to wait to give time for the monitor executor to start the monitor thread.
95107 TimeUnit .MILLISECONDS .sleep (250 );
96108 assertEquals (MonitorState .RUNNING , monitor .getState ());
97109
98110 monitor .state .set (MonitorState .ERROR );
99- monitorService .checkMonitors ();
111+ spyMonitorService .checkMonitors ();
100112
101113 assertEquals (MonitorState .STOPPED , monitor .getState ());
102114
103- Monitor newMonitor = monitorService .get (NoOpMonitor .class , key );
115+ Monitor newMonitor = spyMonitorService .get (NoOpMonitor .class , key );
104116 assertNotNull (newMonitor );
105117 assertNotEquals (monitor , newMonitor );
106118 // need to wait to give time for the monitor executor to start the monitor thread.
@@ -110,40 +122,40 @@ public void testMonitorError_monitorReCreated() throws SQLException, Interrupted
110122
111123 @ Test
112124 public void testMonitorStuck_monitorReCreated () throws SQLException , InterruptedException {
113- monitorService .registerMonitorTypeIfAbsent (
125+ spyMonitorService .registerMonitorTypeIfAbsent (
114126 NoOpMonitor .class ,
115127 TimeUnit .MINUTES .toNanos (1 ),
116128 1 , // heartbeat times out immediately
117129 new HashSet <>(Collections .singletonList (MonitorErrorResponse .RECREATE )),
118130 null
119131 );
120132 String key = "testMonitor" ;
121- NoOpMonitor monitor = monitorService .runIfAbsent (
133+ NoOpMonitor monitor = spyMonitorService .runIfAbsent (
122134 NoOpMonitor .class ,
123135 key ,
124- storageService ,
125- telemetryFactory ,
136+ mockStorageService ,
137+ mockTelemetryFactory ,
126138 "jdbc:postgresql://somehost/somedb" ,
127139 "someProtocol" ,
128- targetDriverDialect ,
129- dbDialect ,
140+ mockTargetDriverDialect ,
141+ mockDbDialect ,
130142 new Properties (),
131- (connectionService , pluginService ) -> new NoOpMonitor (monitorService , 30 )
143+ (connectionService , pluginService ) -> new NoOpMonitor (spyMonitorService , 30 )
132144 );
133145
134- Monitor storedMonitor = monitorService .get (NoOpMonitor .class , key );
146+ Monitor storedMonitor = spyMonitorService .get (NoOpMonitor .class , key );
135147 assertNotNull (storedMonitor );
136148 assertEquals (monitor , storedMonitor );
137149 // need to wait to give time for the monitor executor to start the monitor thread.
138150 TimeUnit .MILLISECONDS .sleep (250 );
139151 assertEquals (MonitorState .RUNNING , monitor .getState ());
140152
141153 // checkMonitors() should detect the heartbeat/inactivity timeout, stop the monitor, and re-create a new one.
142- monitorService .checkMonitors ();
154+ spyMonitorService .checkMonitors ();
143155
144156 assertEquals (MonitorState .STOPPED , monitor .getState ());
145157
146- Monitor newMonitor = monitorService .get (NoOpMonitor .class , key );
158+ Monitor newMonitor = spyMonitorService .get (NoOpMonitor .class , key );
147159 assertNotNull (newMonitor );
148160 assertNotEquals (monitor , newMonitor );
149161 // need to wait to give time for the monitor executor to start the monitor thread.
@@ -153,7 +165,7 @@ public void testMonitorStuck_monitorReCreated() throws SQLException, Interrupted
153165
154166 @ Test
155167 public void testMonitorExpired () throws SQLException , InterruptedException {
156- monitorService .registerMonitorTypeIfAbsent (
168+ spyMonitorService .registerMonitorTypeIfAbsent (
157169 NoOpMonitor .class ,
158170 TimeUnit .MILLISECONDS .toNanos (200 ), // monitor expires after 200ms
159171 TimeUnit .MINUTES .toNanos (1 ),
@@ -163,57 +175,57 @@ public void testMonitorExpired() throws SQLException, InterruptedException {
163175 null
164176 );
165177 String key = "testMonitor" ;
166- NoOpMonitor monitor = monitorService .runIfAbsent (
178+ NoOpMonitor monitor = spyMonitorService .runIfAbsent (
167179 NoOpMonitor .class ,
168180 key ,
169- storageService ,
170- telemetryFactory ,
181+ mockStorageService ,
182+ mockTelemetryFactory ,
171183 "jdbc:postgresql://somehost/somedb" ,
172184 "someProtocol" ,
173- targetDriverDialect ,
174- dbDialect ,
185+ mockTargetDriverDialect ,
186+ mockDbDialect ,
175187 new Properties (),
176- (connectionService , pluginService ) -> new NoOpMonitor (monitorService , 30 )
188+ (connectionService , pluginService ) -> new NoOpMonitor (spyMonitorService , 30 )
177189 );
178190
179- Monitor storedMonitor = monitorService .get (NoOpMonitor .class , key );
191+ Monitor storedMonitor = spyMonitorService .get (NoOpMonitor .class , key );
180192 assertNotNull (storedMonitor );
181193 assertEquals (monitor , storedMonitor );
182194 // need to wait to give time for the monitor executor to start the monitor thread.
183195 TimeUnit .MILLISECONDS .sleep (250 );
184196 assertEquals (MonitorState .RUNNING , monitor .getState ());
185197
186198 // checkMonitors() should detect the expiration timeout and stop/remove the monitor.
187- monitorService .checkMonitors ();
199+ spyMonitorService .checkMonitors ();
188200
189201 assertEquals (MonitorState .STOPPED , monitor .getState ());
190202
191- Monitor newMonitor = monitorService .get (NoOpMonitor .class , key );
203+ Monitor newMonitor = spyMonitorService .get (NoOpMonitor .class , key );
192204 // monitor should have been removed when checkMonitors() was called.
193205 assertNull (newMonitor );
194206 }
195207
196208 @ Test
197209 public void testMonitorMismatch () {
198- assertThrows (IllegalStateException .class , () -> monitorService .runIfAbsent (
210+ assertThrows (IllegalStateException .class , () -> spyMonitorService .runIfAbsent (
199211 CustomEndpointMonitorImpl .class ,
200212 "testMonitor" ,
201- storageService ,
202- telemetryFactory ,
213+ mockStorageService ,
214+ mockTelemetryFactory ,
203215 "jdbc:postgresql://somehost/somedb" ,
204216 "someProtocol" ,
205- targetDriverDialect ,
206- dbDialect ,
217+ mockTargetDriverDialect ,
218+ mockDbDialect ,
207219 new Properties (),
208220 // indicated monitor class is CustomEndpointMonitorImpl, but actual monitor is NoOpMonitor. The monitor
209221 // service should detect this and throw an exception.
210- (connectionService , pluginService ) -> new NoOpMonitor (monitorService , 30 )
222+ (connectionService , pluginService ) -> new NoOpMonitor (spyMonitorService , 30 )
211223 ));
212224 }
213225
214226 @ Test
215227 public void testRemove () throws SQLException , InterruptedException {
216- monitorService .registerMonitorTypeIfAbsent (
228+ spyMonitorService .registerMonitorTypeIfAbsent (
217229 NoOpMonitor .class ,
218230 TimeUnit .MINUTES .toNanos (1 ),
219231 TimeUnit .MINUTES .toNanos (1 ),
@@ -224,30 +236,30 @@ public void testRemove() throws SQLException, InterruptedException {
224236 );
225237
226238 String key = "testMonitor" ;
227- NoOpMonitor monitor = monitorService .runIfAbsent (
239+ NoOpMonitor monitor = spyMonitorService .runIfAbsent (
228240 NoOpMonitor .class ,
229241 key ,
230- storageService ,
231- telemetryFactory ,
242+ mockStorageService ,
243+ mockTelemetryFactory ,
232244 "jdbc:postgresql://somehost/somedb" ,
233245 "someProtocol" ,
234- targetDriverDialect ,
235- dbDialect ,
246+ mockTargetDriverDialect ,
247+ mockDbDialect ,
236248 new Properties (),
237- (connectionService , pluginService ) -> new NoOpMonitor (monitorService , 30 )
249+ (connectionService , pluginService ) -> new NoOpMonitor (spyMonitorService , 30 )
238250 );
239251 assertNotNull (monitor );
240252
241253 // need to wait to give time for the monitor executor to start the monitor thread.
242254 TimeUnit .MILLISECONDS .sleep (250 );
243- Monitor removedMonitor = monitorService .remove (NoOpMonitor .class , key );
255+ Monitor removedMonitor = spyMonitorService .remove (NoOpMonitor .class , key );
244256 assertEquals (monitor , removedMonitor );
245257 assertEquals (MonitorState .RUNNING , monitor .getState ());
246258 }
247259
248260 @ Test
249261 public void testStopAndRemove () throws SQLException , InterruptedException {
250- monitorService .registerMonitorTypeIfAbsent (
262+ spyMonitorService .registerMonitorTypeIfAbsent (
251263 NoOpMonitor .class ,
252264 TimeUnit .MINUTES .toNanos (1 ),
253265 TimeUnit .MINUTES .toNanos (1 ),
@@ -258,24 +270,24 @@ public void testStopAndRemove() throws SQLException, InterruptedException {
258270 );
259271
260272 String key = "testMonitor" ;
261- NoOpMonitor monitor = monitorService .runIfAbsent (
273+ NoOpMonitor monitor = spyMonitorService .runIfAbsent (
262274 NoOpMonitor .class ,
263275 key ,
264- storageService ,
265- telemetryFactory ,
276+ mockStorageService ,
277+ mockTelemetryFactory ,
266278 "jdbc:postgresql://somehost/somedb" ,
267279 "someProtocol" ,
268- targetDriverDialect ,
269- dbDialect ,
280+ mockTargetDriverDialect ,
281+ mockDbDialect ,
270282 new Properties (),
271- (connectionService , pluginService ) -> new NoOpMonitor (monitorService , 30 )
283+ (connectionService , pluginService ) -> new NoOpMonitor (spyMonitorService , 30 )
272284 );
273285 assertNotNull (monitor );
274286
275287 // need to wait to give time for the monitor executor to start the monitor thread.
276288 TimeUnit .MILLISECONDS .sleep (250 );
277- monitorService .stopAndRemove (NoOpMonitor .class , key );
278- assertNull (monitorService .get (NoOpMonitor .class , key ));
289+ spyMonitorService .stopAndRemove (NoOpMonitor .class , key );
290+ assertNull (spyMonitorService .get (NoOpMonitor .class , key ));
279291 assertEquals (MonitorState .STOPPED , monitor .getState ());
280292 }
281293
0 commit comments