From d742a6419f4d6bc27e6053ff757e9a98e678a4de Mon Sep 17 00:00:00 2001 From: Katsiaryna Tsytsenia Date: Tue, 5 Nov 2024 02:43:43 +0200 Subject: [PATCH] IJMP-1923 Fixed IDE error in case of invalid zowe.config Signed-off-by: Katsiaryna Tsytsenia --- .../ui/zosmf/ZOSMFConnectionConfigurable.kt | 15 +++- .../zowe/actions/UpdateZoweConfigAction.kt | 18 +++-- .../zowe/service/ZoweConfigServiceImpl.kt | 33 ++------- .../explorer/config/ZoweConfigTestSpec.kt | 17 +++++ .../zosmf/ZOSMFConnectionConfigurableTest.kt | 70 +++++++++++++++---- 5 files changed, 106 insertions(+), 47 deletions(-) diff --git a/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurable.kt b/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurable.kt index 27d6d58b..5b14c486 100644 --- a/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurable.kt +++ b/src/main/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurable.kt @@ -14,6 +14,9 @@ package org.zowe.explorer.config.connect.ui.zosmf +import com.google.gson.JsonSyntaxException +import com.intellij.ide.DataManager +import com.intellij.openapi.actionSystem.* import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.runInEdt import com.intellij.openapi.options.BoundSearchableConfigurable @@ -34,6 +37,7 @@ import org.zowe.explorer.config.connect.Credentials import org.zowe.explorer.config.ws.FilesWorkingSetConfig import org.zowe.explorer.config.ws.JesWorkingSetConfig import org.zowe.explorer.config.ws.WorkingSetConfig +import org.zowe.explorer.telemetry.NotificationsService import org.zowe.explorer.utils.crudable.getAll import org.zowe.explorer.utils.isThe import org.zowe.explorer.utils.runWriteActionInEdtAndWait @@ -109,7 +113,16 @@ class ZOSMFConnectionConfigurable : BoundSearchableConfigurable("z/OSMF Connecti return } - val zoweConfig = parseConfigJson(configFile.inputStream) + val zoweConfig = try { + parseConfigJson(configFile.inputStream) + } catch (e: JsonSyntaxException) { + NotificationsService.errorNotification( + e, + project = DataManager.getInstance().getDataContext(panel).getData(PlatformDataKeys.PROJECT), + custTitle = "Error with Zowe config file" + ) + return + } zoweConfig.extractSecureProperties(configFile.path.split("/").toTypedArray()) kotlin.runCatching { zoweConfig.updateFromState(state) diff --git a/src/main/kotlin/org/zowe/explorer/zowe/actions/UpdateZoweConfigAction.kt b/src/main/kotlin/org/zowe/explorer/zowe/actions/UpdateZoweConfigAction.kt index 7ef55583..3cfc2b24 100644 --- a/src/main/kotlin/org/zowe/explorer/zowe/actions/UpdateZoweConfigAction.kt +++ b/src/main/kotlin/org/zowe/explorer/zowe/actions/UpdateZoweConfigAction.kt @@ -14,6 +14,7 @@ package org.zowe.explorer.zowe.actions +import com.google.gson.JsonSyntaxException import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys @@ -84,12 +85,17 @@ class UpdateZoweConfigAction : DumbAwareAction() { zoweConfigService.localZoweConfig else zoweConfigService.globalZoweConfig - if (type == ZoweConfigType.LOCAL) { - zoweConfigService.localZoweConfig = parseConfigJson(editor.document.text) - zoweConfigService.localZoweConfig?.extractSecureProperties(vFile.path.split("/").toTypedArray()) - } else { - zoweConfigService.globalZoweConfig = parseConfigJson(editor.document.text) - zoweConfigService.globalZoweConfig?.extractSecureProperties(vFile.path.split("/").toTypedArray()) + try { + if (type == ZoweConfigType.LOCAL) { + zoweConfigService.localZoweConfig = parseConfigJson(editor.document.text) + zoweConfigService.localZoweConfig?.extractSecureProperties(vFile.path.split("/").toTypedArray()) + } else { + zoweConfigService.globalZoweConfig = parseConfigJson(editor.document.text) + zoweConfigService.globalZoweConfig?.extractSecureProperties(vFile.path.split("/").toTypedArray()) + } + } catch (ex: JsonSyntaxException) { + e.presentation.isEnabledAndVisible = false + return } val zoweState = zoweConfigService.getZoweConfigState(false, type = type) e.presentation.isEnabledAndVisible = diff --git a/src/main/kotlin/org/zowe/explorer/zowe/service/ZoweConfigServiceImpl.kt b/src/main/kotlin/org/zowe/explorer/zowe/service/ZoweConfigServiceImpl.kt index 0540e327..04f0d277 100644 --- a/src/main/kotlin/org/zowe/explorer/zowe/service/ZoweConfigServiceImpl.kt +++ b/src/main/kotlin/org/zowe/explorer/zowe/service/ZoweConfigServiceImpl.kt @@ -14,10 +14,8 @@ package org.zowe.explorer.zowe.service -import com.intellij.notification.Notification import com.intellij.notification.NotificationGroupManager import com.intellij.notification.NotificationType -import com.intellij.notification.Notifications import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.application.runReadAction import com.intellij.openapi.application.runWriteAction @@ -38,6 +36,7 @@ import org.zowe.explorer.dataops.DataOpsManager import org.zowe.explorer.dataops.operations.InfoOperation import org.zowe.explorer.dataops.operations.ZOSInfoOperation import org.zowe.explorer.explorer.EXPLORER_NOTIFICATION_GROUP_ID +import org.zowe.explorer.telemetry.NotificationsService import org.zowe.explorer.utils.crudable.find import org.zowe.explorer.utils.crudable.getAll import org.zowe.explorer.utils.runTask @@ -64,9 +63,6 @@ import java.util.regex.Pattern import java.util.stream.Collectors import kotlin.collections.set - -const val ZOWE_CONFIG_NOTIFICATION_GROUP_ID = "org.zowe.explorerzowe.service.ZoweConfigNotificationGroupId" - const val ZOWE_PROJECT_PREFIX = "zowe-" /** @@ -123,22 +119,6 @@ class ZoweConfigServiceImpl(override val myProject: Project) : ZoweConfigService override var globalZoweConfig: ZoweConfig? = null - /** - * Displays an error notification if an error was received. - * @param t thrown error. - * @param title error text. - */ - private fun notifyError(t: Throwable, title: String? = null) { - Notifications.Bus.notify( - Notification( - ZOWE_CONFIG_NOTIFICATION_GROUP_ID, - title ?: "Error with Zowe config file", - t.message ?: t.toString(), - NotificationType.ERROR - ) - ) - } - /** * Checks project contains zowe.config.json. If zowe config presented * it will parse it and save to object model inside zoweConfig field. @@ -162,7 +142,8 @@ class ZoweConfigServiceImpl(override val myProject: Project) : ZoweConfigService } } } catch (e: Exception) { - throw Exception("Cannot parse $type Zowe config file") + NotificationsService.errorNotification(e, project = myProject, custTitle="Error with Zowe config file") + return null } } @@ -306,7 +287,7 @@ class ZoweConfigServiceImpl(override val myProject: Project) : ZoweConfigService } } catch (e: Exception) { - notifyError(e) + NotificationsService.errorNotification(e, project = myProject, custTitle="Error with Zowe config file") } } @@ -384,7 +365,7 @@ class ZoweConfigServiceImpl(override val myProject: Project) : ZoweConfigService } } catch (e: Exception) { - notifyError(e) + NotificationsService.errorNotification(e, project = myProject, custTitle="Error with Zowe config file") } } @@ -490,11 +471,7 @@ class ZoweConfigServiceImpl(override val myProject: Project) : ZoweConfigService */ override fun getZoweConfigState(scanProject: Boolean, type: ZoweConfigType): ZoweConfigState { if (scanProject) { - try { scanForZoweConfig(type) - } catch (e: Exception) { - notifyError(e) - } } val zoweConfig = if (type == ZoweConfigType.LOCAL) localZoweConfig ?: return ZoweConfigState.NOT_EXISTS diff --git a/src/test/kotlin/org/zowe/explorer/config/ZoweConfigTestSpec.kt b/src/test/kotlin/org/zowe/explorer/config/ZoweConfigTestSpec.kt index b82b976f..3e2192d8 100644 --- a/src/test/kotlin/org/zowe/explorer/config/ZoweConfigTestSpec.kt +++ b/src/test/kotlin/org/zowe/explorer/config/ZoweConfigTestSpec.kt @@ -41,8 +41,10 @@ import org.zowe.explorer.dataops.operations.InfoOperation import org.zowe.explorer.dataops.operations.ZOSInfoOperation import org.zowe.explorer.explorer.Explorer import org.zowe.explorer.explorer.WorkingSet +import org.zowe.explorer.telemetry.NotificationsService import org.zowe.explorer.testutils.WithApplicationShouldSpec import org.zowe.explorer.testutils.testServiceImpl.TestDataOpsManagerImpl +import org.zowe.explorer.testutils.testServiceImpl.TestNotificationsServiceImpl import org.zowe.explorer.utils.crudable.* import org.zowe.explorer.utils.runIfTrue import org.zowe.explorer.utils.validateForBlank @@ -128,6 +130,21 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({ Optional.of(ConnectionConfig()) } + val notificationsService = NotificationsService.getService() as TestNotificationsServiceImpl + notificationsService.testInstance = object : TestNotificationsServiceImpl() { + override fun notifyError( + t: Throwable, + project: Project?, + custTitle: String?, + custDetailsShort: String?, + custDetailsLong: String? + ) { + if (custTitle == "Error with Zowe config file") { + notified = true + } + } + } + afterEach { isFilesWriteTriggered = false isRunWriteActionCalled = false diff --git a/src/test/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurableTest.kt b/src/test/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurableTest.kt index a0ccff45..283f9a3e 100644 --- a/src/test/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurableTest.kt +++ b/src/test/kotlin/org/zowe/explorer/config/connect/ui/zosmf/ZOSMFConnectionConfigurableTest.kt @@ -14,6 +14,9 @@ package org.zowe.explorer.config.connect.ui.zosmf +import com.intellij.ide.DataManager +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.project.Project import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.ui.Messages @@ -29,7 +32,9 @@ import org.zowe.explorer.common.ui.ValidatingTableView import org.zowe.explorer.config.ConfigStateV2 import org.zowe.explorer.config.connect.ConnectionConfig import org.zowe.explorer.config.makeCrudableWithoutListeners +import org.zowe.explorer.telemetry.NotificationsService import org.zowe.explorer.testutils.WithApplicationShouldSpec +import org.zowe.explorer.testutils.testServiceImpl.TestNotificationsServiceImpl import org.zowe.kotlinsdk.annotations.ZVersion import org.zowe.kotlinsdk.zowe.config.DefaultKeytarWrapper import org.zowe.kotlinsdk.zowe.config.KeytarWrapper @@ -49,6 +54,7 @@ class ZOSMFConnectionConfigurableTest : WithApplicationShouldSpec({ var isShowOkCancelDialogCalled = false var isFindFileByNioPathCalled = false var isInputStreamCalled = false + var notified = false afterSpec { clearAllMocks() @@ -59,10 +65,26 @@ class ZOSMFConnectionConfigurableTest : WithApplicationShouldSpec({ isShowOkCancelDialogCalled = false isFindFileByNioPathCalled = false isInputStreamCalled = false + notified = false } context("ZOSMFConnectionConfigurable:") { + val notificationsService = NotificationsService.getService() as TestNotificationsServiceImpl + notificationsService.testInstance = object : TestNotificationsServiceImpl() { + override fun notifyError( + t: Throwable, + project: Project?, + custTitle: String?, + custDetailsShort: String?, + custDetailsLong: String? + ) { + if (custTitle == "Error with Zowe config file") { + notified = true + } + } + } + val state = ConnectionDialogState( connectionUuid = "0000", connectionUrl = "https://111.111.111.111:111", @@ -156,6 +178,42 @@ class ZOSMFConnectionConfigurableTest : WithApplicationShouldSpec({ isFindFileByNioPathCalled = true vfMock } + every { vfMock.inputStream } answers { + isInputStreamCalled = true + val fileCont = "{\n" + + " \"\$schema\": \"./zowe.schema.json\",\n" + + " \"profiles\": {\n" + + " \"zosmf\": {\n" + + "}" + fileCont.toByteArray().inputStream() + } + every { vfMock.path } returns "/zowe/file/path/zowe.config.json" + every { vfMock.charset } returns Charsets.UTF_8 + every { vfMock.setBinaryContent(any()) } just Runs + + mockkObject(ZoweConfig) + val confMap = mutableMapOf>() + val configCredentialsMap = mutableMapOf() + configCredentialsMap["profiles.base.properties.user"] = "testUser" + configCredentialsMap["profiles.base.properties.password"] = "testPass" + confMap.clear() + confMap["/zowe/file/path/zowe.config.json"] = configCredentialsMap + every { ZoweConfig.Companion["readZoweCredentialsFromStorage"](any()) } returns confMap + + should("updateZoweConfigIfNeeded throw JsonSyntaxException") { + zOSMFConnectionConfigurableMock::class.declaredMemberFunctions.find { it.name == "updateZoweConfigIfNeeded" } + ?.let { + it.isAccessible = true + try { + it.call(zOSMFConnectionConfigurableMock, state) + } catch (t: Throwable) { + println("ghjkk") + t.cause.toString().shouldContain("Zowe config file not found") + } + } + notified shouldBe true + } + every { vfMock.inputStream } answers { isInputStreamCalled = true val fileCont = "{\n" + @@ -205,18 +263,6 @@ class ZOSMFConnectionConfigurableTest : WithApplicationShouldSpec({ "}" fileCont.toByteArray().inputStream() } - every { vfMock.path } returns "/zowe/file/path/zowe.config.json" - every { vfMock.charset } returns Charsets.UTF_8 - every { vfMock.setBinaryContent(any()) } just Runs - - mockkObject(ZoweConfig) - val confMap = mutableMapOf>() - val configCredentialsMap = mutableMapOf() - configCredentialsMap["profiles.base.properties.user"] = "testUser" - configCredentialsMap["profiles.base.properties.password"] = "testPass" - confMap.clear() - confMap["/zowe/file/path/zowe.config.json"] = configCredentialsMap - every { ZoweConfig.Companion["readZoweCredentialsFromStorage"](any()) } returns confMap should("updateZoweConfigIfNeeded success") { zOSMFConnectionConfigurableMock::class.declaredMemberFunctions.find { it.name == "updateZoweConfigIfNeeded" }