Skip to content

Commit

Permalink
IJMP-1845 Fixed synchronization issues
Browse files Browse the repository at this point in the history
Signed-off-by: Katsiaryna Tsytsenia <[email protected]>
  • Loading branch information
Katsiaryna Tsytsenia authored and Katsiaryna Tsytsenia committed Aug 16, 2024
1 parent 1ffd506 commit f265dc5
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,16 @@ class CredentialServiceImpl : CredentialService {
* @return user credentials [Credentials] if they are.
*/
private fun getCredentials(connectionConfigUuid: String): Credentials? {
return service<PasswordSafe>().get(createCredentialAttributes(connectionConfigUuid))
val credentialAttributes = createCredentialAttributes(connectionConfigUuid)
var ret = service<PasswordSafe>().get(credentialAttributes)
//Another attempt to read the password was added, since the saving of credentials occurs in a separate thread
//and depends on the operating system. If we saved the credentials and try to read them in another thread,
//but they have not yet actually been saved in storage.
if (ret==null){
Thread.sleep(10)
ret = service<PasswordSafe>().get(credentialAttributes)
}
return ret
}

/**
Expand Down
12 changes: 8 additions & 4 deletions src/main/kotlin/org/zowe/explorer/zowe/ZoweStartupActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ import org.zowe.explorer.config.connect.ConnectionConfig
import org.zowe.explorer.explorer.EXPLORER_NOTIFICATION_GROUP_ID
import org.zowe.explorer.utils.subscribe
import org.zowe.explorer.zowe.service.*
import org.zowe.explorer.zowe.service.ZoweConfigService.Companion.lock
import org.zowe.kotlinsdk.zowe.config.ZoweConfig
import java.util.regex.Pattern
import kotlin.concurrent.write

const val ZOWE_CONFIG_NAME = "zowe.config.json"

Expand Down Expand Up @@ -88,10 +90,12 @@ fun showDialogForDeleteZoweConfigIfNeeded(project: Project, type: ZoweConfigType
zoweConfigService.deleteZoweConfig(type)
}
}
if (type == ZoweConfigType.LOCAL)
zoweConfigService.localZoweConfig = null
else
zoweConfigService.globalZoweConfig = null
lock.write {
if (type == ZoweConfigType.LOCAL)
zoweConfigService.localZoweConfig = null
else
zoweConfigService.globalZoweConfig = null
}
zoweConfigService.checkAndRemoveOldZoweConnection(type)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.components.service
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.project.DumbAwareAction
import org.zowe.explorer.utils.write
import org.zowe.explorer.zowe.service.ZoweConfigService
import org.zowe.explorer.zowe.service.ZoweConfigService.Companion.lock
import org.zowe.explorer.zowe.service.ZoweConfigServiceImpl
import org.zowe.explorer.zowe.service.ZoweConfigState
import org.zowe.explorer.zowe.service.ZoweConfigType
Expand All @@ -29,8 +31,7 @@ import org.zowe.kotlinsdk.zowe.config.parseConfigJson
* @since 2021-02-12
*/
class UpdateZoweConfigAction : DumbAwareAction() {

override fun getActionUpdateThread() = ActionUpdateThread.EDT
override fun getActionUpdateThread() = ActionUpdateThread.BGT

override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: let {
Expand Down Expand Up @@ -75,27 +76,26 @@ class UpdateZoweConfigAction : DumbAwareAction() {
type = ZoweConfigType.LOCAL

val zoweConfigService = project.service<ZoweConfigService>()

val prevZoweConfig = if (type == ZoweConfigType.LOCAL)
zoweConfigService.localZoweConfig
else
zoweConfigService.globalZoweConfig
runCatching {
lock.write {
val prevZoweConfig = if (type == ZoweConfigType.LOCAL)
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())
}
}
val zoweState = zoweConfigService.getZoweConfigState(false, type = type)
e.presentation.isEnabledAndVisible =
zoweState == ZoweConfigState.NEED_TO_UPDATE || zoweState == ZoweConfigState.NEED_TO_ADD
if (type == ZoweConfigType.LOCAL) {
zoweConfigService.localZoweConfig = prevZoweConfig
} else {
zoweConfigService.globalZoweConfig = prevZoweConfig
val zoweState = zoweConfigService.getZoweConfigState(false, type = type)
e.presentation.isEnabledAndVisible =
zoweState == ZoweConfigState.NEED_TO_UPDATE || zoweState == ZoweConfigState.NEED_TO_ADD
if (type == ZoweConfigType.LOCAL) {
zoweConfigService.localZoweConfig = prevZoweConfig
} else {
zoweConfigService.globalZoweConfig = prevZoweConfig
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.intellij.util.messages.Topic
import org.zowe.explorer.config.connect.ConnectionConfig
import org.zowe.explorer.config.connect.ui.zosmf.ConnectionDialogState
import org.zowe.kotlinsdk.zowe.config.ZoweConfig
import java.util.concurrent.locks.ReentrantReadWriteLock


/**
Expand Down Expand Up @@ -102,6 +103,7 @@ interface ZoweConfigService {

companion object {
fun getInstance(project: Project): ZoweConfigService = project.getService(ZoweConfigService::class.java)
val lock = ReentrantReadWriteLock()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ 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.utils.*
import org.zowe.explorer.utils.crudable.find
import org.zowe.explorer.utils.crudable.getAll
import org.zowe.explorer.utils.runReadActionInEdtAndWait
import org.zowe.explorer.utils.runTask
import org.zowe.explorer.utils.sendTopic
import org.zowe.explorer.utils.toMutableList
import org.zowe.explorer.zowe.ZOWE_CONFIG_NAME
import org.zowe.explorer.zowe.service.ZoweConfigService.Companion.lock
import org.zowe.kotlinsdk.annotations.ZVersion
import org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection
import org.zowe.kotlinsdk.zowe.config.ZoweConfig
Expand Down Expand Up @@ -145,10 +143,12 @@ class ZoweConfigServiceImpl(override val myProject: Project) : ZoweConfigService
zoweFile.inputStream.use { zoweFileInputStream ->
parseConfigJson(zoweFileInputStream).also { tmpZoweConfig ->
tmpZoweConfig.extractSecureProperties(zoweFile.path.split("/").toTypedArray())
if(type == ZoweConfigType.LOCAL)
localZoweConfig = tmpZoweConfig
else
globalZoweConfig = tmpZoweConfig
lock.write {
if (type == ZoweConfigType.LOCAL)
localZoweConfig = tmpZoweConfig
else
globalZoweConfig = tmpZoweConfig
}
}
}
} catch (e: Exception) {
Expand Down Expand Up @@ -288,7 +288,6 @@ class ZoweConfigServiceImpl(override val myProject: Project) : ZoweConfigService
val zoweConnection = prepareConnection(zosmfConnection, type)
val connectionOpt = configCrudable.addOrUpdate(zoweConnection)
if (!connectionOpt.isEmpty) {
CredentialService.instance.setCredentials(connectionOpt.get().uuid, username, password)
var topic = if (type == ZoweConfigType.LOCAL)
LOCAL_ZOWE_CONFIG_CHANGED
else
Expand Down
99 changes: 39 additions & 60 deletions src/test/kotlin/org/zowe/explorer/config/ZoweConfigTestSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,7 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({

val connectionId = "000000000000"
val connection = ConnectionConfig(
"ID$connectionId",
connectionId,
"URL$connectionId",
true,
ZVersion.ZOS_2_4,
zoweConfigPath = "/zowe/config/path"
"ID$connectionId", connectionId, "URL$connectionId", true, ZVersion.ZOS_2_4, zoweConfigPath = "/zowe/config/path"
)
val crudableMockk = mockk<Crudable>()
every { crudableMockk.getAll<ConnectionConfig>() } returns Stream.of()
Expand Down Expand Up @@ -255,19 +250,16 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({
if (infoRes.zosVersion == "throw1") {
throw Throwable("Test performInfoOperation throw")
}
@Suppress("UNCHECKED_CAST")
return SystemsResponse(numRows = 1) as R
@Suppress("UNCHECKED_CAST") return SystemsResponse(numRows = 1) as R
}
if (operation is ZOSInfoOperation) {
isZOSInfoCalled = true
if (infoRes.zosVersion == "throw2") {
throw Throwable("Test performOperation throw")
}
@Suppress("UNCHECKED_CAST")
return infoRes as R
@Suppress("UNCHECKED_CAST") return infoRes as R
}
@Suppress("UNCHECKED_CAST")
return InfoResponse() as R
@Suppress("UNCHECKED_CAST") return InfoResponse() as R
}
}

Expand All @@ -284,8 +276,7 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({
should("getZoweConfigLocation") {
getZoweConfigLocation(mockedProject, ZoweConfigType.LOCAL) shouldBe "test/zowe.config.json"
getZoweConfigLocation(
mockedProject,
ZoweConfigType.GLOBAL
mockedProject, ZoweConfigType.GLOBAL
) shouldBe System.getProperty("user.home").replace("((\\*)|(/*))$", "") + "/.zowe/" + ZOWE_CONFIG_NAME
getZoweConfigLocation(null, ZoweConfigType.LOCAL) shouldBe "null/zowe.config.json"
}
Expand Down Expand Up @@ -447,19 +438,15 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({

should("addOrUpdateZoweConfig throw Cannot get Zowe config") {
mockedZoweConfigService.addOrUpdateZoweConfig(
scanProject = false,
checkConnection = true,
type = ZoweConfigType.GLOBAL
scanProject = false, checkConnection = true, type = ZoweConfigType.GLOBAL
)
notified shouldBe true
}

should("addOrUpdateZoweConfig throw Cannot get password") {
every { zoweConfigMock.password } returns null
mockedZoweConfigService.addOrUpdateZoweConfig(
scanProject = false,
checkConnection = true,
type = ZoweConfigType.LOCAL
scanProject = false, checkConnection = true, type = ZoweConfigType.LOCAL
)
every { zoweConfigMock.password } returns "password"
notified shouldBe true
Expand All @@ -468,9 +455,7 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({
should("addOrUpdateZoweConfig throw Cannot get username") {
every { zoweConfigMock.user } returns null
mockedZoweConfigService.addOrUpdateZoweConfig(
scanProject = false,
checkConnection = true,
type = ZoweConfigType.LOCAL
scanProject = false, checkConnection = true, type = ZoweConfigType.LOCAL
)
every { zoweConfigMock.user } returns "ZoweUserName"
notified shouldBe true
Expand All @@ -491,9 +476,7 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({

should("addOrUpdateZoweConfig New ConnectionConfig throw on check") {
mockedZoweConfigService.addOrUpdateZoweConfig(
scanProject = false,
checkConnection = true,
type = ZoweConfigType.LOCAL
scanProject = false, checkConnection = true, type = ZoweConfigType.LOCAL
)
notified shouldBe true
}
Expand Down Expand Up @@ -642,28 +625,23 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({
credentialsGetter: () -> MutableList<Credentials> = { mutableListOf() },
stateGetter: () -> ConfigStateV2
): Crudable {
val crudableLists = CrudableLists(
addFilter = object : AddFilter {
override operator fun <T : Any> invoke(clazz: Class<out T>, addingRow: T): Boolean {
return ConfigService.instance.getConfigDeclaration(clazz).getDecider().canAdd(addingRow)
}
},
updateFilter = object : UpdateFilter {
override operator fun <T : Any> invoke(clazz: Class<out T>, currentRow: T, updatingRow: T): Boolean {
return ConfigService.instance.getConfigDeclaration(clazz).getDecider().canUpdate(currentRow, updatingRow)
}
},
nextUuidProvider = { UUID.randomUUID().toString() },
getListByClass = {
if (it == Credentials::class.java) {
withCredentials.runIfTrue {
credentialsGetter()
}
} else {
stateGetter().get(it)
val crudableLists = CrudableLists(addFilter = object : AddFilter {
override operator fun <T : Any> invoke(clazz: Class<out T>, addingRow: T): Boolean {
return ConfigService.instance.getConfigDeclaration(clazz).getDecider().canAdd(addingRow)
}
}, updateFilter = object : UpdateFilter {
override operator fun <T : Any> invoke(clazz: Class<out T>, currentRow: T, updatingRow: T): Boolean {
return ConfigService.instance.getConfigDeclaration(clazz).getDecider().canUpdate(currentRow, updatingRow)
}
}, nextUuidProvider = { UUID.randomUUID().toString() }, getListByClass = {
if (it == Credentials::class.java) {
withCredentials.runIfTrue {
credentialsGetter()
}
} else {
stateGetter().get(it)
}
)
})
return ConcurrentCrudable(crudableLists, SimpleReadWriteAdapter())
}

Expand All @@ -674,10 +652,8 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({
Pair(JesWorkingSetConfig::class.java.name, mutableListOf<ConnectionConfig>()),
)
val sandboxState = SandboxState(ConfigStateV2(configCollections))
val crudable =
org.zowe.explorer.config.makeCrudableWithoutListeners(
true,
{ sandboxState.credentials }) { sandboxState.configState }
val crudable = org.zowe.explorer.config.makeCrudableWithoutListeners(true,
{ sandboxState.credentials }) { sandboxState.configState }

mockedZoweConfigService::class.declaredMemberProperties.find { it.name == "configCrudable" }?.let {
it.isAccessible = true
Expand All @@ -688,27 +664,31 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({
it.isAccessible = true
(it.call(mockedZoweConfigService, ZoweConfigType.LOCAL) as List<ConnectionConfig>).size shouldBe 1
it.call(mockedZoweConfigService, ZoweConfigType.GLOBAL) shouldBe null
connection.name="zowe-global-zosmf"
connection.name = "zowe-global-zosmf"
it.call(mockedZoweConfigService, ZoweConfigType.GLOBAL) shouldBe null
connection.zoweConfigPath=getZoweConfigLocation(mockedProject, ZoweConfigType.GLOBAL)
connection.zoweConfigPath = getZoweConfigLocation(mockedProject, ZoweConfigType.GLOBAL)
(it.call(mockedZoweConfigService, ZoweConfigType.GLOBAL) as List<ConnectionConfig>).size shouldBe 1
}
}

should("findExistingConnection") {
mockedZoweConfigService::class.declaredMemberFunctions.find { it.name == "findExistingConnection" }?.let {
it.isAccessible = true
connection.name="zowe-local-zosmf/testProj"
connection.zoweConfigPath=getZoweConfigLocation(mockedProject, ZoweConfigType.LOCAL)
(it.call(mockedZoweConfigService, ZoweConfigType.LOCAL, "zosmf") as ConnectionConfig).name shouldBe connection.name
connection.name="zowe-global-zosmf"
connection.zoweConfigPath=getZoweConfigLocation(mockedProject, ZoweConfigType.LOCAL)
connection.name = "zowe-local-zosmf/testProj"
connection.zoweConfigPath = getZoweConfigLocation(mockedProject, ZoweConfigType.LOCAL)
(it.call(
mockedZoweConfigService,
ZoweConfigType.LOCAL,
"zosmf"
) as ConnectionConfig).name shouldBe connection.name
connection.name = "zowe-global-zosmf"
connection.zoweConfigPath = getZoweConfigLocation(mockedProject, ZoweConfigType.LOCAL)
it.call(mockedZoweConfigService, ZoweConfigType.LOCAL, "zosmf") shouldBe null
it.call(mockedZoweConfigService, ZoweConfigType.GLOBAL, "zosmf") shouldBe null
}
}

should ("validateForBlank"){
should("validateForBlank") {
validateForBlank(JPasswordField())?.message shouldBe "This field must not be blank"
validateForBlank(JTextField())?.message shouldBe "This field must not be blank"
}
Expand All @@ -734,8 +714,7 @@ class ZoweConfigTestSpec : WithApplicationShouldSpec({
connection.name = "zowe-global-lpar.zosmf"
every {
mockedZoweConfigService["findExistingConnection"](
any<ZoweConfigType>(),
any<String>()
any<ZoweConfigType>(), any<String>()
)
} returns connection
mockedZoweConfigService.getZoweConfigState(false, ZoweConfigType.LOCAL) shouldBe ZoweConfigState.NEED_TO_ADD
Expand Down

0 comments on commit f265dc5

Please sign in to comment.