/** Shortcut for getting currently active implementation of {@link CloudSdkService}. */ static CloudSdkService getInstance() { CloudSdkServiceManager service = ServiceManager.getService(CloudSdkServiceManager.class); // The service itself may be null if used from IDEs where the App Engine integration is not // loaded (due to optional depends). return service != null ? service.getCloudSdkService() : null; }
/** * 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 installingSdk_then_userCancel_doesNotShowWarningNotification() { mockSdkStatusChange(SdkStatus.INSTALLING, SdkStatus.INSTALLING); // mock cancel operation for incomplete install. doReturn(true).when(cloudSdkServiceManager).checkIfCancelled(); cloudSdkServiceManager.runWhenSdkReady(mockProject, mockRunnable, "", mockStatusHandler); ApplicationManager.getApplication() .invokeAndWait( () -> // explicit parameters are not relevant but need to be passed for spy to work. verify(cloudSdkServiceManager, never()) .showCloudSdkNotification("", NotificationType.WARNING)); }
private void executeWithSdkWriteLock(ThrowableRunnable<Exception> runWithLock) throws Exception { try { // if write lock is not available, show a progress to a user that all SDK processes must be // finished in order to update SDK. if (!CloudSdkServiceManager.getInstance().getSdkWriteLock().tryLock()) { ProgressListener waitForSdkProcessesProgress = ManagedCloudSdkServiceUiPresenter.getInstance().createProgressListener(this); waitForSdkProcessesProgress.start( CloudSdkMessageBundle.message("managedsdk.progress.wait.for.processes"), ProgressListener.UNKNOWN); try { CloudSdkServiceManager.getInstance().getSdkWriteLock().lockInterruptibly(); } finally { // make sure the indicator goes away in case of this job error/cancel waitForSdkProcessesProgress.done(); } } runWithLock.run(); } finally { CloudSdkServiceManager.getInstance().getSdkWriteLock().unlock(); } }
CloudSdkServiceManager.getInstance() .runWhenSdkReady( task.getProject(), deployRunner,
@Test public void installingSdk_then_stillInstalling_doesNotRun() { mockSdkStatusChange(SdkStatus.INSTALLING, SdkStatus.INSTALLING); // mock cancel operation for incomplete install. doReturn(true).when(cloudSdkServiceManager).checkIfCancelled(); cloudSdkServiceManager.runWhenSdkReady(mockProject, mockRunnable, "", mockStatusHandler); ApplicationManager.getApplication().invokeAndWait(() -> verifyNoMoreInteractions(mockRunnable)); }
@Test public void installingSdk_then_invalidSdk_showsErrorNotification() { mockSdkStatusChange(SdkStatus.INSTALLING, SdkStatus.INVALID); String errorMessage = "Deployment failed: Google Cloud SDK is not ready."; when(mockStatusHandler.getErrorMessage(SdkStatus.INVALID)).thenReturn(errorMessage); cloudSdkServiceManager.runWhenSdkReady(mockProject, mockRunnable, "", mockStatusHandler); ApplicationManager.getApplication() .invokeAndWait( () -> verify(cloudSdkServiceManager) .showCloudSdkNotification(errorMessage, NotificationType.WARNING)); }
@Test public void waitFor_installingSdk_then_invalidSdk_showsErrorNotification() throws InterruptedException { mockSdkStatusChange(SdkStatus.INSTALLING, SdkStatus.INVALID); when(mockStatusHandler.getErrorMessage(SdkStatus.INVALID)) .thenReturn("invalid SDK after waiting"); cloudSdkServiceManager.blockUntilSdkReady(mockProject, "", mockStatusHandler); ApplicationManager.getApplication() .invokeAndWait( () -> verify(cloudSdkServiceManager) .showCloudSdkNotification( "invalid SDK after waiting", NotificationType.WARNING)); }
@Test public void installingSdk_then_readySdk_correctly_runs() { mockSdkStatusChange(SdkStatus.INSTALLING, SdkStatus.READY); cloudSdkServiceManager.runWhenSdkReady(mockProject, mockRunnable, "", mockStatusHandler); ApplicationManager.getApplication().invokeAndWait(() -> verify(mockRunnable).run()); }
public void apply() throws ConfigurationException { CloudSdkServiceUserSettings sdkServiceUserSettings = CloudSdkServiceUserSettings.getInstance(); if (customRadioButton.isSelected()) { String customSdkPathText = getCloudSdkDirectoryText(); if (CloudSdkValidator.getInstance() .validateCloudSdk(customSdkPathText) .contains(CloudSdkValidationResult.MALFORMED_PATH)) { throw new ConfigurationException( CloudSdkMessageBundle.message("appengine.cloudsdk.location.badchars.message")); } sdkServiceUserSettings.setCustomSdkPath(customSdkPathText); } CloudSdkServiceType previousSdkType = sdkServiceUserSettings.getUserSelectedSdkServiceType(); if (previousSdkType != selectedCloudSdkServiceType) { // notify SDK manager about changed selection ServiceManager.getService(CloudSdkServiceManager.class) .onNewCloudSdkServiceTypeSelected(selectedCloudSdkServiceType); } sdkServiceUserSettings.setUserSelectedSdkServiceType(selectedCloudSdkServiceType); boolean previousAutomaticUpdateEnabled = sdkServiceUserSettings.isAutomaticUpdateEnabled(); sdkServiceUserSettings.setEnableAutomaticUpdates(enableAutomaticUpdatesCheckbox.isSelected()); if (enableAutomaticUpdatesCheckbox.isSelected() && !previousAutomaticUpdateEnabled) { // activate updates again. ManagedCloudSdkUpdateService.getInstance().activate(); } // settings are applied and saved, clear modification status settingsModified = false; }
@Override public void run(@NotNull ProgressIndicator indicator) { try { while (installationCompletionLatch.getCount() > 0) { // wait interruptibility to check for user cancel each second. installationCompletionLatch.await(1, SECONDS); if (checkIfCancelled()) { sdkLogging.onUserCancel(); break; } } } catch (InterruptedException e) { /* valid cancellation exception, no handling needed. */ } finally { // process UI related activities ApplicationManager.getApplication() .invokeLater( () -> { // remove the notification listener regardless of waiting outcome. cloudSdkService.removeStatusUpdateListener(sdkStatusUpdateListener); // process logging and error notifications. handleErrors(sdkLogging); }); // run the activity after wait is over, regardless of outcome. afterWaitComplete.run(); } } });
/** Checks the current SDK status after waiting for readiness, notifies and logs about errors. */ private void handleErrors(CloudSdkStatusHandler sdkLogging) { // check the status of SDK after install. SdkStatus postInstallSdkStatus = CloudSdkService.getInstance().getStatus(); switch (postInstallSdkStatus) { case READY: // can continue without logging anything. break; case INSTALLING: // still installing, do nothing, up to caller to decide which message to show. break; case NOT_AVAILABLE: case INVALID: String message; NotificationType notificationType; boolean fatalSdkError = !CloudSdkService.getInstance().isInstallSupported(); if (fatalSdkError) { message = CloudSdkMessageBundle.message("managedsdk.not.available"); notificationType = NotificationType.ERROR; } else { message = sdkLogging.getErrorMessage(postInstallSdkStatus); notificationType = NotificationType.WARNING; } sdkLogging.onError(message); showCloudSdkNotification(message, notificationType); break; default: // do nothing, no error, not ready. } }
@Test public void waitFor_when_sdkInstallNotSupported_showsFatalErrorNotification() throws InterruptedException { mockSdkStatusChange(SdkStatus.NOT_AVAILABLE, SdkStatus.NOT_AVAILABLE); when(mockSdkService.isInstallSupported()).thenReturn(false); cloudSdkServiceManager.blockUntilSdkReady(mockProject, "", mockStatusHandler); ApplicationManager.getApplication() .invokeAndWait( () -> verify(cloudSdkServiceManager) .showCloudSdkNotification( CloudSdkMessageBundle.message("managedsdk.not.available"), NotificationType.ERROR)); }
@Test public void installingSdk_then_invalidSdk_doesNotRun() { mockSdkStatusChange(SdkStatus.INSTALLING, SdkStatus.INVALID); cloudSdkServiceManager.runWhenSdkReady(mockProject, mockRunnable, "", mockStatusHandler); ApplicationManager.getApplication().invokeAndWait(() -> verifyNoMoreInteractions(mockRunnable)); }
@Test public void changeSdkType_apply_callsChangedSdkTypeCallback() { ApplicationManager.getApplication() .invokeAndWait( () -> { // use non-spy panel as spy messes up with UI event thread field updates. CloudSdkPanel sdkPanel = new CloudSdkPanel(); CloudSdkServiceUserSettings.getInstance() .setUserSelectedSdkServiceType(CloudSdkServiceType.MANAGED_SDK); sdkPanel.reset(); sdkPanel.getCustomRadioButton().doClick(); String customSdkPath = "/home/gcloud"; sdkPanel.getCloudSdkDirectoryField().setText(customSdkPath); try { sdkPanel.apply(); } catch (ConfigurationException e) { throw new AssertionError(e); } verify(mockCloudSdkServiceManager) .onNewCloudSdkServiceTypeSelected(CloudSdkServiceType.CUSTOM_SDK); }); }
@Before public void setUp() { when(mockCloudSdkServiceManager.getCloudSdkService()).thenReturn(mockCloudSdkService); }
@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(); } }
@Test public void installingSdk_then_notAvailableSdk_doesNotRun() { mockSdkStatusChange(SdkStatus.INSTALLING, SdkStatus.NOT_AVAILABLE); cloudSdkServiceManager.runWhenSdkReady(mockProject, mockRunnable, "", mockStatusHandler); ApplicationManager.getApplication().invokeAndWait(() -> verifyNoMoreInteractions(mockRunnable)); }
@Before public void setUp() { when(mockCloudSdkServiceManager.getCloudSdkService()).thenReturn(mockSdkService); // empty error messages by default when(mockStatusHandler.getErrorMessage(any())).thenReturn(""); }
when(mockManagedCloudSdk.newUpdater()).thenReturn(mockUpdater); CloudSdkServiceManager.getInstance().getSdkReadLock().lock(); try { CloudSdkServiceManager.getInstance().getSdkReadLock().unlock();