/** * Waits for the given process to finish, in a separate background thread, holding {@link * CloudSdkServiceManager#getSdkReadLock()} lock. */ @SuppressWarnings("FutureReturnValueIgnored") private void holdCloudSdkReadLock(Process process) { ThreadUtil.getInstance() .executeInBackground( () -> { CloudSdkServiceManager.getInstance().getSdkReadLock().lock(); try { process.waitFor(); } catch (InterruptedException e) { // unexpected interruption, nothing can be done. Logger.getInstance(AppEngineExecutor.class) .warn("Waiting for gcloud process unexpectedly interrupted", e); } finally { CloudSdkServiceManager.getInstance().getSdkReadLock().unlock(); } }); } }
@Test public void install_blocks_whenSDKReadOperations_running() throws Exception { emulateMockSdkInstallationProcess(MOCK_SDK_PATH); SdkInstaller mockInstaller = mock(SdkInstaller.class); when(mockManagedCloudSdk.newInstaller()).thenReturn(mockInstaller); CloudSdkServiceManager.getInstance().getSdkReadLock().lock(); try { // signal when install is about to start write operation. CountDownLatch waitForInstallToStart = new CountDownLatch(1); doAnswer( invocationOnMock -> { waitForInstallToStart.countDown(); return false; }) .when(mockManagedCloudSdk) .isInstalled(); Runnable installProcess = () -> sdkService.install(); Thread installProcessThread = new Thread(installProcess, "test-install-blocking-thread"); installProcessThread.start(); // do timed wait in case of test issues not to cause it to hang. waitForInstallToStart.await(100, TimeUnit.MILLISECONDS); installProcessThread.interrupt(); // finalize install() installProcessThread.join(); // since the write block was not available at the install, install() should never be called. verifyNoMoreInteractions(mockInstaller); } finally { CloudSdkServiceManager.getInstance().getSdkReadLock().unlock(); } }
when(mockManagedCloudSdk.newUpdater()).thenReturn(mockUpdater); CloudSdkServiceManager.getInstance().getSdkReadLock().lock(); try { CloudSdkServiceManager.getInstance().getSdkReadLock().unlock();