You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CeCleaningSchedulerImplTest.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2021 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.ce.cleaning;
  21. import java.util.Collection;
  22. import java.util.List;
  23. import java.util.concurrent.Callable;
  24. import java.util.concurrent.Future;
  25. import java.util.concurrent.ScheduledFuture;
  26. import java.util.concurrent.TimeUnit;
  27. import java.util.concurrent.locks.Lock;
  28. import org.junit.Test;
  29. import org.sonar.ce.CeDistributedInformation;
  30. import org.sonar.ce.configuration.CeConfiguration;
  31. import org.sonar.ce.queue.InternalCeQueue;
  32. import static org.assertj.core.api.Assertions.assertThat;
  33. import static org.assertj.core.api.Assertions.fail;
  34. import static org.mockito.ArgumentMatchers.any;
  35. import static org.mockito.Mockito.doThrow;
  36. import static org.mockito.Mockito.mock;
  37. import static org.mockito.Mockito.times;
  38. import static org.mockito.Mockito.verify;
  39. import static org.mockito.Mockito.when;
  40. public class CeCleaningSchedulerImplTest {
  41. private Lock jobLock = mock(Lock.class);
  42. @Test
  43. public void startScheduling_does_not_fail_if_cleaning_methods_send_even_an_Exception() {
  44. InternalCeQueue mockedInternalCeQueue = mock(InternalCeQueue.class);
  45. CeDistributedInformation mockedCeDistributedInformation = mockCeDistributedInformation(jobLock);
  46. CeCleaningSchedulerImpl underTest = mockCeCleaningSchedulerImpl(mockedInternalCeQueue, mockedCeDistributedInformation);
  47. Exception exception = new IllegalArgumentException("faking unchecked exception thrown by cancelWornOuts");
  48. doThrow(exception).when(mockedInternalCeQueue).resetTasksWithUnknownWorkerUUIDs(any());
  49. underTest.startScheduling();
  50. verify(mockedInternalCeQueue).resetTasksWithUnknownWorkerUUIDs(any());
  51. }
  52. @Test
  53. public void startScheduling_fails_if_resetTasksWithUnknownWorkerUUIDs_send_an_Error() {
  54. InternalCeQueue mockedInternalCeQueue = mock(InternalCeQueue.class);
  55. CeDistributedInformation mockedCeDistributedInformation = mockCeDistributedInformation(jobLock);
  56. CeCleaningSchedulerImpl underTest = mockCeCleaningSchedulerImpl(mockedInternalCeQueue, mockedCeDistributedInformation);
  57. Error expected = new Error("faking Error thrown by cancelWornOuts");
  58. doThrow(expected).when(mockedInternalCeQueue).resetTasksWithUnknownWorkerUUIDs(any());
  59. try {
  60. underTest.startScheduling();
  61. fail("the error should have been thrown");
  62. } catch (Error e) {
  63. assertThat(e).isSameAs(expected);
  64. }
  65. verify(mockedInternalCeQueue).resetTasksWithUnknownWorkerUUIDs(any());
  66. }
  67. @Test
  68. public void startScheduling_must_call_the_lock_methods() {
  69. InternalCeQueue mockedInternalCeQueue = mock(InternalCeQueue.class);
  70. CeDistributedInformation mockedCeDistributedInformation = mockCeDistributedInformation(jobLock);
  71. CeCleaningSchedulerImpl underTest = mockCeCleaningSchedulerImpl(mockedInternalCeQueue, mockedCeDistributedInformation);
  72. underTest.startScheduling();
  73. verify(mockedCeDistributedInformation, times(1)).acquireCleanJobLock();
  74. verify(jobLock, times(1)).tryLock();
  75. verify(jobLock, times(1)).unlock();
  76. }
  77. @Test
  78. public void startScheduling_must_not_execute_method_if_lock_is_already_acquired() {
  79. InternalCeQueue mockedInternalCeQueue = mock(InternalCeQueue.class);
  80. CeDistributedInformation mockedCeDistributedInformation = mockCeDistributedInformation(jobLock);
  81. when(jobLock.tryLock()).thenReturn(false);
  82. CeCleaningSchedulerImpl underTest = mockCeCleaningSchedulerImpl(mockedInternalCeQueue, mockedCeDistributedInformation);
  83. underTest.startScheduling();
  84. verify(mockedCeDistributedInformation, times(1)).acquireCleanJobLock();
  85. verify(jobLock, times(1)).tryLock();
  86. // since lock cannot be locked, unlock method is not been called
  87. verify(jobLock, times(0)).unlock();
  88. // since lock cannot be locked, cleaning job methods must not be called
  89. verify(mockedInternalCeQueue, times(0)).resetTasksWithUnknownWorkerUUIDs(any());
  90. }
  91. @Test
  92. public void startScheduling_calls_cleaning_methods_of_internalCeQueue_at_fixed_rate_with_value_from_CeConfiguration() {
  93. InternalCeQueue mockedInternalCeQueue = mock(InternalCeQueue.class);
  94. long wornOutInitialDelay = 10L;
  95. long wornOutDelay = 20L;
  96. long unknownWorkerInitialDelay = 11L;
  97. long unknownWorkerDelay = 21L;
  98. CeConfiguration mockedCeConfiguration = mockCeConfiguration(wornOutInitialDelay, wornOutDelay);
  99. CeCleaningAdapter executorService = new CeCleaningAdapter() {
  100. @Override
  101. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initDelay, long period, TimeUnit unit) {
  102. schedulerCounter++;
  103. switch(schedulerCounter) {
  104. case 1:
  105. assertThat(initDelay).isEqualTo(wornOutInitialDelay);
  106. assertThat(period).isEqualTo(wornOutDelay);
  107. assertThat(unit).isEqualTo(TimeUnit.MINUTES);
  108. break;
  109. case 2:
  110. assertThat(initDelay).isEqualTo(unknownWorkerInitialDelay);
  111. assertThat(period).isEqualTo(unknownWorkerDelay);
  112. assertThat(unit).isEqualTo(TimeUnit.MINUTES);
  113. break;
  114. default:
  115. fail("Unknwon call of scheduleWithFixedDelay");
  116. }
  117. // synchronously execute command
  118. command.run();
  119. return null;
  120. }
  121. };
  122. CeCleaningSchedulerImpl underTest = new CeCleaningSchedulerImpl(executorService, mockedCeConfiguration,
  123. mockedInternalCeQueue, mockCeDistributedInformation(jobLock));
  124. underTest.startScheduling();
  125. assertThat(executorService.schedulerCounter).isOne();
  126. }
  127. private CeConfiguration mockCeConfiguration(long cleanCeTasksInitialDelay, long cleanCeTasksDelay) {
  128. CeConfiguration mockedCeConfiguration = mock(CeConfiguration.class);
  129. when(mockedCeConfiguration.getCleanTasksInitialDelay()).thenReturn(cleanCeTasksInitialDelay);
  130. when(mockedCeConfiguration.getCleanTasksDelay()).thenReturn(cleanCeTasksDelay);
  131. return mockedCeConfiguration;
  132. }
  133. private CeCleaningSchedulerImpl mockCeCleaningSchedulerImpl(InternalCeQueue internalCeQueue, CeDistributedInformation ceDistributedInformation) {
  134. return new CeCleaningSchedulerImpl(new CeCleaningAdapter() {
  135. @Override
  136. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
  137. // synchronously execute command
  138. command.run();
  139. return null;
  140. }
  141. }, mockCeConfiguration(1, 10), internalCeQueue, ceDistributedInformation);
  142. }
  143. private CeDistributedInformation mockCeDistributedInformation(Lock result) {
  144. CeDistributedInformation mocked = mock(CeDistributedInformation.class);
  145. when(mocked.acquireCleanJobLock()).thenReturn(result);
  146. when(result.tryLock()).thenReturn(true);
  147. return mocked;
  148. }
  149. /**
  150. * Implementation of {@link CeCleaningExecutorService} which throws {@link UnsupportedOperationException} for every
  151. * method.
  152. */
  153. private static class CeCleaningAdapter implements CeCleaningExecutorService {
  154. protected int schedulerCounter = 0;
  155. @Override
  156. public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
  157. throw createUnsupportedOperationException();
  158. }
  159. @Override
  160. public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
  161. throw createUnsupportedOperationException();
  162. }
  163. @Override
  164. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
  165. throw createUnsupportedOperationException();
  166. }
  167. @Override
  168. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
  169. throw createUnsupportedOperationException();
  170. }
  171. @Override
  172. public void shutdown() {
  173. throw createUnsupportedOperationException();
  174. }
  175. @Override
  176. public List<Runnable> shutdownNow() {
  177. throw createUnsupportedOperationException();
  178. }
  179. @Override
  180. public boolean isShutdown() {
  181. throw createUnsupportedOperationException();
  182. }
  183. @Override
  184. public boolean isTerminated() {
  185. throw createUnsupportedOperationException();
  186. }
  187. @Override
  188. public boolean awaitTermination(long timeout, TimeUnit unit) {
  189. throw createUnsupportedOperationException();
  190. }
  191. @Override
  192. public <T> Future<T> submit(Callable<T> task) {
  193. throw createUnsupportedOperationException();
  194. }
  195. @Override
  196. public <T> Future<T> submit(Runnable task, T result) {
  197. throw createUnsupportedOperationException();
  198. }
  199. @Override
  200. public Future<?> submit(Runnable task) {
  201. throw createUnsupportedOperationException();
  202. }
  203. @Override
  204. public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
  205. throw createUnsupportedOperationException();
  206. }
  207. @Override
  208. public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) {
  209. throw createUnsupportedOperationException();
  210. }
  211. @Override
  212. public <T> T invokeAny(Collection<? extends Callable<T>> tasks) {
  213. throw createUnsupportedOperationException();
  214. }
  215. @Override
  216. public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) {
  217. throw createUnsupportedOperationException();
  218. }
  219. @Override
  220. public void execute(Runnable command) {
  221. throw createUnsupportedOperationException();
  222. }
  223. private UnsupportedOperationException createUnsupportedOperationException() {
  224. return new UnsupportedOperationException("Unexpected call");
  225. }
  226. }
  227. }