diff --git a/.gitignore b/.gitignore index b1adc24..35b386c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .idea/*.iml .idea/modules .idea/.gitignore +.idea/codeStyles build .gradle .gradle.properties diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2b87adc --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# R2Z Changelog + +All notable changes to the R2Z will be documented in this file. + +## `1.3.0 (2023-02-22)` + +* Deprecation: This library is deprecated since 1.3.0 + + +* Feature: GitHub issue #3: Zowe Kotlin SDK: Java-like Kotlin API ([56788c1a](https://github.com/zowe/zowe-explorer-intellij/commit/56788c1a)) +* Feature: Implement ZosUssFile (copying methods - from uss to dsn and to uss folder) ([2bb0b257](https://github.com/zowe/zowe-explorer-intellij/commit/2bb0b257)) + + +* Bugfix: GitHub issue #9: Error Creating Connection ([bbc16d72](https://github.com/zowe/zowe-client-kotlin-sdk/commit/bbc16d72)) diff --git a/README.md b/README.md index d09d6f9..dc2418b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# WARNING: THIS REPOSITORY IS MARKED AS 'DEPRECATED' AND WON'T BE MAINTAINED. CONSIDER SWITCHING TO ZOWE CLIENT KOTLIN SDK WITH THE SIMILAR APPROACH TO WORK WITH Z/OSMF REST API ([link](https://github.com/zowe/zowe-client-kotlin-sdk)) + ## zOSMF Retrofit Library This library covert zOSMF Rest API with kotlin object oriented code using Retrofit. r2z will allow you to send http requests to your zOSMF. @@ -42,6 +44,14 @@ if (response.isSuccessful){ ``` Please note that in order to create API stub, you have to specify that the response should be converted by gson. And that's how you can easily use r2z. +## Documentation with Dokka + +To build Dokka documentattion, run: +``` +./gradlew dokkaHtml +``` +Docs will be added to *build/dokka/html* + ## How to run tests ### Unit tests diff --git a/build.gradle b/build.gradle index 655bafb..6419668 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,12 @@ // Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ +import org.jetbrains.dokka.gradle.DokkaTask +import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id 'java' id 'org.jetbrains.kotlin.jvm' version '1.6.21' + id 'org.jetbrains.dokka' version '1.7.20' } apply plugin: 'java' @@ -26,7 +30,7 @@ repositories { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib" implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.21" - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2' testImplementation 'com.squareup.okhttp3:mockwebserver:4.10.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' implementation 'com.squareup.retrofit2:retrofit:2.9.0', @@ -34,21 +38,35 @@ dependencies { 'com.squareup.retrofit2:converter-scalars:2.9.0', 'com.google.code.gson:gson:2.10', 'com.starxg:java-keytar:1.0.0', - 'org.yaml:snakeyaml:1.29', - 'org.junit.jupiter:junit-jupiter-api:5.8.2' + 'org.yaml:snakeyaml:1.33' } test { useJUnitPlatform() } -tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { +tasks.withType(KotlinCompile).all { kotlinOptions { jvmTarget = JavaVersion.VERSION_11.toString() - languageVersion = org.jetbrains.kotlin.config.LanguageVersion.LATEST_STABLE.versionString + languageVersion = LanguageVersion.LATEST_STABLE.versionString } } +tasks.withType(DokkaTask.class) { + String dokkaBaseConfiguration = """ + { + "footerMessage": "(c) 2022 IBA Group", + "templatesDir": "${file("dokka/templates").getAbsolutePath().replace('\\', '/')}", + "customAssets": ["${file("dokka/assets/zowe-icon.png").getAbsolutePath().replace('\\', '/')}"], + "customStyleSheets": ["${file("dokka/assets/logo-styles.css").getAbsolutePath().replace('\\', '/')}"] + } + """ + pluginsMapConfiguration.set( + // fully qualified plugin name to json configuration + ["org.jetbrains.dokka.base.DokkaBase": dokkaBaseConfiguration] + ) +} + task sourceJar(type: Jar) { classifier "sources" from sourceSets.main.allSource diff --git a/dokka/assets/logo-styles.css b/dokka/assets/logo-styles.css new file mode 100644 index 0000000..0f410c7 --- /dev/null +++ b/dokka/assets/logo-styles.css @@ -0,0 +1,15 @@ +.library-name a { + position: relative; + margin-left: 55px; +} + +.library-name a::before { + content: ''; + background: url("../images/zowe-icon.png") center no-repeat; + background-size: contain; + position: absolute; + width: 50px; + height: 50px; + top: -18px; + left: -55px; +} diff --git a/dokka/assets/zowe-icon.png b/dokka/assets/zowe-icon.png new file mode 100644 index 0000000..5b979db Binary files /dev/null and b/dokka/assets/zowe-icon.png differ diff --git a/dokka/templates/includes/footer.ftl b/dokka/templates/includes/footer.ftl new file mode 100644 index 0000000..55e7a5e --- /dev/null +++ b/dokka/templates/includes/footer.ftl @@ -0,0 +1,15 @@ +<#macro display> + + diff --git a/dokka/templates/includes/header.ftl b/dokka/templates/includes/header.ftl new file mode 100644 index 0000000..87938fd --- /dev/null +++ b/dokka/templates/includes/header.ftl @@ -0,0 +1,25 @@ +<#import "source_set_selector.ftl" as source_set_selector> +<#macro display> + + diff --git a/dokka/templates/includes/page_metadata.ftl b/dokka/templates/includes/page_metadata.ftl new file mode 100644 index 0000000..67b4018 --- /dev/null +++ b/dokka/templates/includes/page_metadata.ftl @@ -0,0 +1,6 @@ +<#macro display> + ${pageName} - Zowe Client Kotlin SDK Documentation + <@template_cmd name="pathToRoot"> + + + diff --git a/gradle.properties b/gradle.properties index 27a74f1..0d8cdfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,4 +10,4 @@ signing.keyId=FADC1195 signing.password=key_pass signing.secretKeyRingFile=path/to/secret/key -projectVersion=1.2.3 +projectVersion=1.3.0-rc.11 diff --git a/src/intTest/kotlin/common/TsoApiTest.kt b/src/intTest/kotlin/common/TsoApiTest.kt index b0ef447..d5e0533 100644 --- a/src/intTest/kotlin/common/TsoApiTest.kt +++ b/src/intTest/kotlin/common/TsoApiTest.kt @@ -19,7 +19,7 @@ class TsoApiTest: BaseTest() { authorizationToken = BASIC_AUTH_TOKEN, proc = "IKJACCNT", chset = "697", - cpage = TsoCodePage.IBM_1047, + cpage = "1047", rows = 204, cols = 160, rsize = 50000, diff --git a/src/main/kotlin/eu/ibagroup/r2z/ConsoleAPI.kt b/src/main/kotlin/eu/ibagroup/r2z/ConsoleAPI.kt new file mode 100644 index 0000000..c1bcfc3 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/ConsoleAPI.kt @@ -0,0 +1,25 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z + +import eu.ibagroup.r2z.annotations.AvailableSince +import eu.ibagroup.r2z.annotations.ZVersion +import retrofit2.Call + +import retrofit2.http.Body +import retrofit2.http.Header +import retrofit2.http.PUT +import retrofit2.http.Path + +interface ConsoleAPI { + + @AvailableSince(ZVersion.ZOS_2_1) + @PUT("/zosmf/restconsoles/consoles/{consolename}") + fun issueCommand( + @Header("Authorization") authorizationToken: String, + @Header("Content-type") contentType: ContentType = ContentType.APP_JSON, + @Path("consolename") consoleName: String, + @Body body: IssueRequestBody + ): Call + +} \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/DataAPI.kt b/src/main/kotlin/eu/ibagroup/r2z/DataAPI.kt index 11af75a..e92b6b7 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/DataAPI.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/DataAPI.kt @@ -259,9 +259,12 @@ interface DataAPI { /** * Copy from - to - * SEQ -> SEQ - * PDS MEMBER -> SEQ (overwrites content) - * PDS MEMBER or MEMBERS -> PDS (adds or replaces) + * + * **SEQ** -> **SEQ** + * + * **PDS MEMBER** -> **SEQ** (overwrites content) + * + * **PDS MEMBER or MEMBERS** -> **PDS** (adds or replaces) */ @AvailableSince(ZVersion.ZOS_2_1) @PUT("/zosmf/restfiles/ds/{to-data-set-name}") @@ -275,10 +278,14 @@ interface DataAPI { /** * Volser for uncatalogued datasets + * * Copy from - to - * SEQ -> SEQ - * PDS MEMBER -> SEQ - * PDS MEMBER or MEMBERS -> PDS + * + * **SEQ** -> **SEQ** + * + * **PDS MEMBER** -> **SEQ** + * + * **PDS MEMBER** or **MEMBERS** -> **PDS** */ @AvailableSince(ZVersion.ZOS_2_1) @PUT("/zosmf/restfiles/ds/-({to-volser})/{to-data-set-name}") @@ -292,8 +299,9 @@ interface DataAPI { ): Call /** - * SEQ -> PDS MEMBER - * PDS MEMBER -> PDS MEMBER + * **SEQ** -> **PDS MEMBER** + * + * **PDS MEMBER** -> **PDS MEMBER** */ @AvailableSince(ZVersion.ZOS_2_1) @PUT("/zosmf/restfiles/ds/{to-data-set-name}({member-name})") @@ -307,9 +315,11 @@ interface DataAPI { ): Call /** - * Volser for uncatalogued datasets - * SEQ -> PDS MEMBER - * PDS MEMBER -> PDS MEMBER + * Volser for uncatalogued + * + * **SEQ** -> **PDS MEMBER** + * + * **PDS MEMBER** -> **PDS MEMBER** */ @AvailableSince(ZVersion.ZOS_2_1) @PUT("/zosmf/restfiles/ds/-({to-volser})/{to-data-set-name}({member-name})") @@ -324,7 +334,7 @@ interface DataAPI { ): Call /** - * USS FILE -> SEQ (truncates contents) + * **USS FILE** -> **SEQ** (truncates contents) */ @AvailableSince(ZVersion.ZOS_2_1) @PUT("/zosmf/restfiles/ds/{to-data-set-name}") @@ -337,7 +347,7 @@ interface DataAPI { ): Call /** - * USS FILE -> PDS MEMBER + * **USS FILE** -> **PDS MEMBER** */ @AvailableSince(ZVersion.ZOS_2_1) @PUT("/zosmf/restfiles/ds/{to-data-set-name}({member-name})") @@ -461,13 +471,15 @@ interface DataAPI { @Header("Authorization") authorizationToken: String, @Header("X-IBM-BPXK-AUTOCVT") xIBMBpxkAutoCvt: XIBMBpxkAutoCvt? = null, @Body body: CopyDataUSS.CopyFromFileOrDir, - @Path("filepath-name") filePath: FilePath, + @Path("filepath-name", encoded = true) filePath: FilePath, ): Call /** - * SEQ -> USS FILE - * PDS MEMBER -> USS FILE - * PDS -> USS DIR doesn't work + * **SEQ** -> **USS FILE** + * + * **PDS MEMBER** -> **USS FILE** + * + * **WARNING:** PDS -> USS DIR doesn't work */ @AvailableSince(ZVersion.ZOS_2_1) @PUT("/zosmf/restfiles/fs/{filepath-name}") diff --git a/src/main/kotlin/eu/ibagroup/r2z/InfoAPI.kt b/src/main/kotlin/eu/ibagroup/r2z/InfoAPI.kt index 764c2d3..cac58b8 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/InfoAPI.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/InfoAPI.kt @@ -11,10 +11,10 @@ interface InfoAPI { /** * An API function to get an information of the system where z/OSMF is currently running - * @return a wrapped instance of InfoResponse + * @return a wrapped instance of [InfoResponse] */ @AvailableSince(ZVersion.ZOS_2_1) @GET("zosmf/info") fun getSystemInfo() : Call -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/InfoResponse.kt b/src/main/kotlin/eu/ibagroup/r2z/InfoResponse.kt index 26a7c93..7ee561f 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/InfoResponse.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/InfoResponse.kt @@ -2,8 +2,13 @@ package eu.ibagroup.r2z +import com.google.gson.Gson +import com.google.gson.TypeAdapter import com.google.gson.annotations.Expose +import com.google.gson.annotations.JsonAdapter import com.google.gson.annotations.SerializedName +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter import eu.ibagroup.r2z.annotations.ZVersion data class InfoResponse ( @@ -24,6 +29,7 @@ data class InfoResponse ( val zosmfHostname: String = "null", @SerializedName("plugins") + @JsonAdapter(PluginsAdapter::class) @Expose val plugins: List = emptyList(), @@ -46,4 +52,22 @@ data class InfoResponse ( "04.28.00" -> ZVersion.ZOS_2_5 else -> ZVersion.ZOS_2_1 } -} \ No newline at end of file +} + +class PluginsAdapter : TypeAdapter>() { + private val gson = Gson() + override fun write(out: JsonWriter?, value: List?) { + gson.toJson(value, List::class.java, out) + } + + override fun read(reader: JsonReader): List { + var result = listOf() + runCatching { + result = gson.fromJson(reader, List::class.java) + }.onFailure { + reader.skipValue() + } + return result + } + +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/IssueRequestBody.kt b/src/main/kotlin/eu/ibagroup/r2z/IssueRequestBody.kt new file mode 100644 index 0000000..fda03b5 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/IssueRequestBody.kt @@ -0,0 +1,41 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +/** + * The z/OSMF console API parameters. See the z/OSMF REST API documentation for full details. + */ +class IssueRequestBody( + + /** + * The z/OS console command to issue. + */ + @SerializedName("cmd") + @Expose + val cmd: String, + + /** + * The solicited keyword to look for. + */ + @SerializedName("sol-key") + @Expose + val solKey: String? = null, + + /** + * The system in the sysplex to route the command. + */ + @SerializedName("system") + @Expose + val system: String? = null, + + /** + * The method of issuing the command. + */ + @SerializedName("async") + @Expose + val async: String? = null + +) \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/IssueResponse.kt b/src/main/kotlin/eu/ibagroup/r2z/IssueResponse.kt new file mode 100644 index 0000000..9281d63 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/IssueResponse.kt @@ -0,0 +1,48 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +/** + * z/OSMF synchronous console command response messages. See the z/OSMF REST API publication for complete details. + */ +data class IssueResponse( + + /** + * Follow-up response URL. + */ + @SerializedName("cmd-response-url") + @Expose + val cmdResponseUrl: String? = null, + + /** + * Command response text. + */ + @SerializedName("cmd-response") + @Expose + val cmdResponse: String? = null, + + /** + * The follow-up response URI. + */ + @SerializedName("cmd-response-uri") + @Expose + val cmdResponseUri: String? = null, + + /** + * The command response key used for follow-up requests. + */ + @SerializedName("cmd-response-key") + @Expose + val cmdResponseKey: String? = null, + + /** + * True if the solicited keyword requested is present. + */ + @SerializedName("sol-key-detected") + @Expose + val solKeyDetected: String? = null + +) \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/SystemsApi.kt b/src/main/kotlin/eu/ibagroup/r2z/SystemsApi.kt index 77664bb..0d8f9c1 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/SystemsApi.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/SystemsApi.kt @@ -12,8 +12,8 @@ interface SystemsApi { /** * An API function to get all available systems defined to z/OSMF - * @param authToken - is a base 64 encoding representation of : - * @return a wrapped instance of SystemsResponse + * @param authToken is a base 64 encoding representation of *userid*:*password* + * @return a wrapped instance of [SystemsResponse] */ @AvailableSince(ZVersion.ZOS_2_1) @GET("zosmf/resttopology/systems") @@ -22,4 +22,3 @@ interface SystemsApi { ): Call } - diff --git a/src/main/kotlin/eu/ibagroup/r2z/SystemsResponse.kt b/src/main/kotlin/eu/ibagroup/r2z/SystemsResponse.kt index ee90fe0..0464553 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/SystemsResponse.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/SystemsResponse.kt @@ -13,14 +13,14 @@ import eu.ibagroup.r2z.annotations.ZVersion data class SystemsResponse( /** - * @param items - a serialized list of SystemZOSInfo instances defined to z/OSMF + * @param items a serialized list of SystemZOSInfo instances defined to z/OSMF */ @SerializedName("items") @Expose val items: List = emptyList(), /** - * @param numRows - a serialized number of returned objects + * @param numRows a serialized number of returned objects */ @SerializedName("numRows") @Expose @@ -42,55 +42,55 @@ data class SystemsResponse( } /** - * A data class which represents a single SystemZOSInfo instance defined to z/OSMF + * A data class which represents a single [SystemZOSInfo] instance defined to z/OSMF */ data class SystemZOSInfo( /** - * @param systemNickName - a serialized unique name assigned to the system definition + * @param systemNickName a serialized unique name assigned to the system definition */ @SerializedName("systemNickName") @Expose val systemNickName: String = "null", /** - * @param systemName - a serialized name specified for the system on the SYSNAME parameter in the IEASYSxx parmlib member + * @param systemName a serialized name specified for the system on the SYSNAME parameter in the IEASYSxx parmlib member */ @SerializedName("systemName") @Expose val systemName: String = "null", /** - * @param sysplexName - a serialized name of the sysplex where the z/OS® system is a member + * @param sysplexName a serialized name of the sysplex where the z/OS® system is a member */ @SerializedName("sysplexName") @Expose val sysplexName: String = "null", /** - * @param groupNames - a serialized comma-separated list of the groups to which the system is assigned + * @param groupNames a serialized comma-separated list of the groups to which the system is assigned */ @SerializedName("groupNames") @Expose val groupNames: String = "null", /** - * @param url - a serialized URL used to access the z/OSMF instance that resides in the same sysplex as the system identified by the systemName attribute + * @param url a serialized URL used to access the z/OSMF instance that resides in the same sysplex as the system identified by the systemName attribute */ @SerializedName("url") @Expose val url: String = "null", /** - * @param zosVR - a serialized version and release of the z/OS image installed on the system + * @param zosVR a serialized version and release of the z/OS image installed on the system */ @SerializedName("zosVR") @Expose val zosVR: String = "null", /** - * @param jesMemberName - a serialized JES2 multi-access spool (MAS) member name or JES3 complex member name + * @param jesMemberName a serialized JES2 multi-access spool (MAS) member name or JES3 complex member name * that is assigned to the primary job entry subsystem (JES) that is running on the system */ @SerializedName("jesMemberName") @@ -98,28 +98,28 @@ data class SystemZOSInfo( val jesMemberName: String = "null", /** - * @param jesType - a serialized type for the primary job entry subsystem running on the system. The type is either JES2 or JES3 + * @param jesType a serialized type for the primary job entry subsystem running on the system. The type is either JES2 or JES3 */ @SerializedName("jesType") @Expose val jesType: String = "null", /** - * @param cpcName - a serialized name specified for the central processor complex (CPC) at the support element (SE) of that processor complex + * @param cpcName a serialized name specified for the central processor complex (CPC) at the support element (SE) of that processor complex */ @SerializedName("cpcName") @Expose val cpcName: String = "null", /** - * @param cpcSerial - a serialized serial number of the CPC + * @param cpcSerial a serialized serial number of the CPC */ @SerializedName("spcSerial") @Expose val cpcSerial: String = "null", /** - * @param httpProxyName - a serialized name of the HTTP proxy definition that specifies the settings required to access the system + * @param httpProxyName a serialized name of the HTTP proxy definition that specifies the settings required to access the system * through an HTTP or SOCKS proxy server */ @SerializedName("httpProxyName") @@ -127,7 +127,7 @@ data class SystemZOSInfo( val httpProxyName: String = "null", /** - * @param ftpDestinationName - a serialized name of the server definition that specifies the settings required to access the FTP or SFTP server + * @param ftpDestinationName a serialized name of the server definition that specifies the settings required to access the FTP or SFTP server * that is running on the system */ @SerializedName("ftpDestinationName") diff --git a/src/main/kotlin/eu/ibagroup/r2z/TsoApi.kt b/src/main/kotlin/eu/ibagroup/r2z/TsoApi.kt index 8726c76..c044d9c 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/TsoApi.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/TsoApi.kt @@ -11,19 +11,19 @@ interface TsoApi { /** * An API function to start a new TSO address space (session) - * @param authorizationToken - is a base 64 encoding representation of : - * @param contentType - content type of the request - * @param proc - a procedure name - * @param chset - a charset which should be used - * @param cpage - a codepage which should be used - * @param rows - a number of rows available for a new session - * @param cols - a number of columns available for a new session - * @param acct - an account number - * @param ugrp - an user group - * @param rsize - a region size - * @param appsessid - an application session identifier - * @param system - a system name - * @return a wrapped instance of TsoResponse + * @param authorizationToken is a base 64 encoding representation of : + * @param contentType content type of the request + * @param proc a procedure name + * @param chset a charset which should be used + * @param cpage a codepage which should be used + * @param rows a number of rows available for a new session + * @param cols a number of columns available for a new session + * @param acct an account number + * @param ugrp an user group + * @param rsize a region size + * @param appsessid an application session identifier + * @param system a system name + * @return a wrapped instance of [TsoResponse] */ @AvailableSince(ZVersion.ZOS_2_1) @POST("/zosmf/tsoApp/tso") @@ -32,7 +32,7 @@ interface TsoApi { @Header("Content-type") contentType: ContentType = ContentType.APP_JSON, @Query("proc") proc: String, @Query("chset") chset: String, - @Query("cpage") cpage: TsoCodePage, + @Query("cpage") cpage: String, @Query("rows") rows: Int, @Query("cols") cols: Int, @Query("acct") acct: String? = null, @@ -44,12 +44,12 @@ interface TsoApi { /** * An API function to send a message to TSO address space - * @param authorizationToken - is a base 64 encoding representation of : - * @param contentType - content type of the request - * @param body - wrapped instance of TsoData class - * @param servletKey - Unique identifier for the servlet entry - * @param readReply - is an optional parameter that indicates whether the service should send the message and immediately check for a response (default) or just send the message. - * @return a wrapped instance of TsoResponse + * @param authorizationToken is a base 64 encoding representation of *userid*:*password* + * @param contentType content type of the request + * @param body wrapped instance of TsoData class + * @param servletKey unique identifier for the servlet entry + * @param readReply is an optional parameter that indicates whether the service should send the message and immediately check for a response (default) or just send the message. + * @return a wrapped instance of [TsoResponse] */ @AvailableSince(ZVersion.ZOS_2_1) @PUT("/zosmf/tsoApp/tso/{servletKey}") @@ -63,10 +63,10 @@ interface TsoApi { /** * An API function to receive messages from TSO address space - * @param authorizationToken - is a base 64 encoding representation of : - * @param contentType - content type of the request - * @param servletKey - Unique identifier for the servlet entry - * @return a wrapped instance of TsoResponse + * @param authorizationToken is a base 64 encoding representation of *userid*:*password* + * @param contentType content type of the request + * @param servletKey unique identifier for the servlet entry + * @return a wrapped instance of [TsoResponse] */ @AvailableSince(ZVersion.ZOS_2_1) @GET("/zosmf/tsoApp/tso/{servletKey}") @@ -78,11 +78,11 @@ interface TsoApi { /** * An API function to close the TSO session - * @param authorizationToken - is a base 64 encoding representation of : - * @param contentType - content type of the request - * @param servletKey - Unique identifier for the servlet entry - * @param tsoForceCancel - is an optional parameter that indicates whether to use the CANCEL or LOGOFF command to end the TSO/E address space - * @return a wrapped instance of TsoResponse + * @param authorizationToken is a base 64 encoding representation of *userid*:*password* + * @param contentType content type of the request + * @param servletKey unique identifier for the servlet entry + * @param tsoForceCancel is an optional parameter that indicates whether to use the CANCEL or LOGOFF command to end the TSO/E address space + * @return a wrapped instance of [TsoResponse] */ @AvailableSince(ZVersion.ZOS_2_1) @DELETE("/zosmf/tsoApp/tso/{servletKey}") @@ -93,4 +93,4 @@ interface TsoApi { @Query("tsoforcecancel") tsoForceCancel: Boolean? = null, ): Call -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/TsoResponse.kt b/src/main/kotlin/eu/ibagroup/r2z/TsoResponse.kt index 3428281..8eecca1 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/TsoResponse.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/TsoResponse.kt @@ -90,10 +90,10 @@ data class MessageData( ) enum class TsoCodePage(val codePage: String) { - IBM_1025("1025"), - IBM_1047("1047"); + IBM_1025("1025"), + IBM_1047("1047"); - override fun toString(): String { - return codePage - } -} \ No newline at end of file + override fun toString(): String { + return codePage + } +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/core/ZOSConnection.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/core/ZOSConnection.kt index d466993..a3fcb9b 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/core/ZOSConnection.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/core/ZOSConnection.kt @@ -6,7 +6,7 @@ package eu.ibagroup.r2z.zowe.client.sdk.core * z/OS Connection information placeholder * * @author Frank Giordano - * @version 1.0 + * @author Uladzislau Kalesnikau */ class ZOSConnection( /** @@ -22,7 +22,7 @@ class ZOSConnection( */ val user: String, /** - * machine host username's password with access to backend z/OS instance + * machine host username\'s password with access to backend z/OS instance */ val password: String, /** diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosconsole/ConsoleResponse.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosconsole/ConsoleResponse.kt new file mode 100644 index 0000000..a2968c8 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosconsole/ConsoleResponse.kt @@ -0,0 +1,49 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zosconsole + +import eu.ibagroup.r2z.IssueResponse + +/** + * The Console API response. + */ +data class ConsoleResponse( + + /** + * True if the command was issued and the responses were collected. + */ + val success: Boolean? = false, + + /** + * The list of zOSMF console API responses. May issue multiple requests (because of user request) or + * to ensure that all messages are collected. Each individual response is placed here. + */ + val zosmfResponse: IssueResponse? = null, + + /** + * If an error occurs, returns the [ImperativeError], which contains case error. + */ + val failureResponse: String? = null, + + /** + * The command response text. + */ + var commandResponse: String? = null, + + /** + * The final command response key - used to "follow-up" and check for additional response messages for the command. + */ + val lastResponseKey: String? = null, + + /** + * If the solicited keyword is specified, indicates that the keyword was detected. + */ + val keywordDetected: Boolean? = false, + + /** + * The "follow-up" command response URL - you can paste this in the browser to do a "GET" using the command + * response key provided in the URI route. + */ + val cmdResponseUrl: String? = null + +) diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosconsole/IssueCommand.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosconsole/IssueCommand.kt new file mode 100644 index 0000000..b2faa52 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosconsole/IssueCommand.kt @@ -0,0 +1,109 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zosconsole + +import eu.ibagroup.r2z.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import okhttp3.Credentials +import okhttp3.OkHttpClient +import retrofit2.Response + +/** + * Issue MVS Console commands by using a system console + */ +class IssueCommand( + var connection: ZOSConnection, + var httpClient: OkHttpClient = UnsafeOkHttpClient.unsafeOkHttpClient +) { + + init { + connection.checkConnection() + } + + var response: Response<*>? = null + + /** + * Issue an MVS console command, returns "raw" z/OSMF response + * + * @param consoleName string name of the mvs console that is used to issue the command + * @param commandParams [IssueRequestBody] synchronous console issue parameters + * @return [IssueResponse] command response on resolve + * @throws Exception processing error + */ + fun issueCommon(consoleName: String, commandParams: IssueRequestBody): IssueResponse { + if (consoleName.isEmpty()) { + throw Exception("consoleName not specified") + } + if (commandParams.cmd.isEmpty()) { + throw Exception("command not specified") + } + + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val consoleApi = buildApi(url, httpClient) + val call = consoleApi.issueCommand( + authorizationToken = Credentials.basic(connection.user, connection.password), + consoleName = consoleName, + body = commandParams + ) + + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception(response?.errorBody()?.string()) + } + return response?.body() as IssueResponse? ?: throw Exception("No body returned") + } + + /** + * Issue an MVS console command in default console, returns "raw" z/OSMF response + * + * @param commandParams [IssueRequestBody] synchronous console issue parameters + * @return [IssueResponse] command response on resolve + * @throws Exception processing error + */ + fun issueDefConsoleCommon(commandParams: IssueRequestBody): IssueResponse { + return issueCommon("defcn", commandParams) + } + + /** + * Issue an MVS console command done synchronously - meaning solicited (direct command responses) are gathered + * immediately after the command is issued. However, after (according to the z/OSMF REST API documentation) + * approximately 3 seconds the response will be returned. + * + * @param params [IssueRequestBody] console issue parameters + * @return [ConsoleResponse] on resolve + * @throws Exception processing error + */ + fun issue(params: IssueRequestBody): ConsoleResponse { + val resp = issueCommon("defcn", params) + val consoleResponse = ConsoleResponse( + zosmfResponse = resp, + success = true, + keywordDetected = resp.solKeyDetected?.isNotEmpty() == true, + lastResponseKey = resp.cmdResponseKey, + cmdResponseUrl = resp.cmdResponseUrl + ) + + if (resp.cmdResponse != null) { + val responseValue = resp.cmdResponse.replace('\r', '\n') + consoleResponse.commandResponse = responseValue + + if (responseValue.isNotEmpty() && (responseValue.indexOf("\n") != responseValue.length - 1)) { + consoleResponse.commandResponse = responseValue + "\n" + } + } + + return consoleResponse + } + + /** + * Simple issue console command method. Does not accept parameters, so all defaults on the z/OSMF API are taken. + * + * @param command string command to issue + * @return [ConsoleResponse] object on resolve + * @throws Exception processing error + */ + fun issueSimple(command: String): ConsoleResponse { + return issue(IssueRequestBody(cmd = command)) + } + +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsn.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsn.kt index 65672b6..2e9f063 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsn.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsn.kt @@ -50,7 +50,7 @@ class ZosDsn( attribute = XIBMAttr.Type.BASE ) val dsLst: DataSetsList = zosDsnList.listDsn(dataSetSearchStr, params) - val dataSet: Dataset? = dsLst.items.filter { el -> el.name.contains(dataSetName) }.getOrNull(0) + val dataSet: Dataset? = dsLst.items.filter { el -> el.name.contains(dataSetName.uppercase()) }.getOrNull(0) return dataSet ?: emptyDataSet } diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsnDownload.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsnDownload.kt index 25f66b7..528e46c 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsnDownload.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsnDownload.kt @@ -14,7 +14,7 @@ import retrofit2.Response import java.io.InputStream /** - * ZosDsnDownload class that provides download DataSet function + * [ZosDsnDownload] class that provides download DataSet function */ class ZosDsnDownload ( var connection: ZOSConnection, @@ -32,7 +32,7 @@ class ZosDsnDownload ( * * @param datasetName name of a sequential dataset e.g. DATASET.SEQ.DATA * or a dataset member e.g. DATASET.LIB(MEMBER)) - * @param params download params parameters, see DownloadParams + * @param params [DownloadParams] * @return a content stream * @throws Exception error processing request */ @@ -59,4 +59,4 @@ class ZosDsnDownload ( return (response?.body() as ResponseBody).byteStream() ?: throw Exception("No stream returned") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsnList.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsnList.kt index dc4c8b5..9f4eec8 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsnList.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosfiles/ZosDsnList.kt @@ -12,7 +12,7 @@ import retrofit2.Response /** * ZosDsnList class that provides Dataset member list function * - * @property connection connection information, see ZOSConnection object + * @property conenction [ZOSConnection] object connection information * @property httpClient okHttpClient */ class ZosDsnList( @@ -30,7 +30,7 @@ class ZosDsnList( * Get a list of Dataset names * * @param dataSetName name of a dataset - * @param params list parameters, see ListParams object + * @param params [ListParams] object * @return A String list of Dataset names * @throws Exception error processing request */ @@ -57,7 +57,7 @@ class ZosDsnList( * Get a list of members from a Dataset * * @param datasetName name of a dataset - * @param listParams list parameters, see ListParams object + * @param listParams [ListParams] object * @return list of member names * @throws Exception error processing request */ diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/CancelJobs.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/CancelJobs.kt index 46e0843..dc7e715 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/CancelJobs.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/CancelJobs.kt @@ -51,7 +51,7 @@ class CancelJobs( /** * Cancel a job that resides in a z/OS data set. * - * @param params cancel job parameters, see ModifyJobParams object + * @param params [ModifyJobParams] cancel job parameters * @return job document with details about the canceled job * @throws Exception error canceling */ @@ -70,4 +70,4 @@ class CancelJobs( } return response?.body() as CancelJobRequest? ?: throw Exception("No body returned") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/DeleteJobs.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/DeleteJobs.kt index 5c79ba0..6050aa2 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/DeleteJobs.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/DeleteJobs.kt @@ -51,7 +51,7 @@ class DeleteJobs( /** * Delete a job that resides in a z/OS data set. * - * @param params delete job parameters, see ModifyJobParams object + * @param params [ModifyJobParams] delete job parameters * @return job document with details about the deleted job * @throws Exception error on deleting */ @@ -72,4 +72,4 @@ class DeleteJobs( } return response?.body() as CancelJobPurgeOutRequest? ?: throw Exception("No body returned") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/GetJobs.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/GetJobs.kt index ed4e0e4..ada490b 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/GetJobs.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/GetJobs.kt @@ -105,7 +105,7 @@ class GetJobs( /** * Get jobs filtered by owner and prefix. * - * @param params get job parameters, see GetJobParams object + * @param params [GetJobParams] object * @return list of job objects (matching jobs) * @throws Exception error on getting a list of jobs */ @@ -188,7 +188,7 @@ class GetJobs( /** * Get the status and other details (e.g. owner, return code) for a job. * - * @param params common job parameters, see CommonJobParams object + * @param params [CommonJobParams] object * @return job document (matching job) * @throws Exception error getting job status */ @@ -223,7 +223,7 @@ class GetJobs( * Get a list of all job spool files for a job. * * @param params common job parameters, see CommonJobParams object - * @return list of SpoolFile objects + * @return list of [SpoolFile] objects * @throws Exception error on getting spool files info */ @Suppress("UNCHECKED_CAST") @@ -248,7 +248,7 @@ class GetJobs( * other APIs such as SubmitJobs. * * @param job job for which you would like to get a list of job spool files - * @return list of SpoolFile objects + * @return list of [SpoolFile] objects * @throws Exception error on getting spool files info */ fun getSpoolFilesForJob(job: Job): List { @@ -264,7 +264,7 @@ class GetJobs( /** * Get the JCL that was used to submit a job. * - * @param params common job parameters, see CommonJobParams object + * @param params [CommonJobParams] object * @return JCL content * @throws Exception error on getting jcl content */ @@ -366,4 +366,4 @@ class GetJobs( } return String(response?.body() as ByteArray? ?: throw Exception("No body returned")) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/MonitorJobs.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/MonitorJobs.kt index 1e0b414..cbca20c 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/MonitorJobs.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/MonitorJobs.kt @@ -34,9 +34,7 @@ class MonitorJobs( /** * Given a Job document (has jobname/jobid), waits for the status of the job to be "OUTPUT". This API will poll for * the OUTPUT status once every 3 seconds indefinitely. If the polling interval/duration is NOT sufficient, use - * "waitForStatusCommon" to adjust. - *

- * See JSDoc for "waitForStatusCommon" for full details on polling and other logic. + * [waitForStatusCommon] to adjust. * * @param job document of the z/OS job to wait for (see z/OSMF Jobs APIs for details) * @return job document @@ -52,10 +50,7 @@ class MonitorJobs( /** * Given the jobname/jobid, waits for the status of the job to be "OUTPUT". This API will poll for the OUTPUT status * once every 3 seconds indefinitely. If the polling interval/duration is NOT sufficient, use - * "waitForStatusCommon" to adjust. - * - * - * See JavaDoc for "waitForStatusCommon" for full details on polling and other logic. + * [waitForStatusCommon] to adjust. * * @param jobName the z/OS jobname of the job to wait for output status (see z/OSMF Jobs APIs for details) * @param jobId the z/OS jobid of the job to wait for output status (see z/OSMF Jobs APIS for details) @@ -78,7 +73,7 @@ class MonitorJobs( * than the current status of the job, then the method returns immediately (since the job will never enter the * requested status) with the current status of the job. * - * @param params monitor jobs parameters, see MonitorJobWaitForParams object + * @param params [MonitorJobWaitForParams] object * @return job document * @throws Exception error processing wait check request */ @@ -98,7 +93,7 @@ class MonitorJobs( /** * "Polls" (sets timeouts and continuously checks) for the status of the job to match the desired status. * - * @param params monitor jobs params, see MonitorJobWaitForParams + * @param params [MonitorJobWaitForParams] object * @return job document * @throws Exception error processing poll check request */ @@ -128,7 +123,7 @@ class MonitorJobs( /** * Checks the status of the job for the expected status (OR that the job has progressed passed the expected status). * - * @param params monitor jobs params, see MonitorJobWaitForParams + * @param params [MonitorJobWaitForParams] object * @return boolean true when the job status is obtained * @throws Exception error processing check request */ @@ -168,7 +163,7 @@ class MonitorJobs( /** * Checks if the given message is within the job output within line limit. * - * @param params monitor jobs params, see MonitorJobWaitForParams + * @param params [MonitorJobWaitForParams] object * @param message message string * @return boolean message found status * @throws Exception error processing check request @@ -201,7 +196,7 @@ class MonitorJobs( /** * "Polls" (sets timeouts and continuously checks) for the given message within the job output. * - * @param params monitor jobs params, see MonitorJobWaitForParams + * @param params [MonitorJobWaitForParams] object * @param message message string * @return boolean message found status * @throws Exception error processing poll check request @@ -230,7 +225,7 @@ class MonitorJobs( /** * Determines if a given job is in a running state or not. * - * @param params monitor jobs params, see MonitorJobWaitForParams + * @param params [MonitorJobWaitForParams] object * @return true if in running state * @throws Exception error processing running status check */ @@ -246,7 +241,7 @@ class MonitorJobs( /** * Given jobname/jobid, checks for the desired message continuously (based on the interval and attempts specified). * - * @param params monitor jobs parameters, see MonitorJobWaitForParams object + * @param params [MonitorJobWaitForParams] object * @param message message string * @return job document * @throws Exception error processing wait check request @@ -268,7 +263,7 @@ class MonitorJobs( /** * Given a Job document (has jobname/jobid), waits for the given message from the job. This API will poll for * the given message once every 3 seconds for at least 1000 times. If the polling interval/duration is NOT - * sufficient, use "waitForMessageCommon" method to adjust. + * sufficient, use [waitForMessageCommon] method to adjust. * * @param job document of the z/OS job to wait for (see z/OSMF Jobs APIs for details) * @param message message string @@ -290,9 +285,7 @@ class MonitorJobs( /** * Given a Job document (has jobname/jobid), waits for the given status of the job. This API will poll for * the given status once every 3 seconds for at least 1000 times. If the polling interval/duration is NOT - * sufficient, use "waitForStatusCommon" method to adjust. - *

- * See JavaDoc for "waitForStatusCommon" for full details on polling and other logic. + * sufficient, use [waitForStatusCommon] method to adjust. * * @param job document of the z/OS job to wait for (see z/OSMF Jobs APIs for details) * @param statusType status type, see JobStatus.Type object @@ -309,7 +302,7 @@ class MonitorJobs( /** * Given the jobname/jobid, waits for the given status of the job. This API will poll for the given status once * every 3 seconds for at least 1000 times. If the polling interval/duration is NOT sufficient, use - * "waitForStatusCommon" method to adjust. + * [waitForStatusCommon] method to adjust. * * @param jobName the z/OS jobname of the job to wait for output status (see z/OSMF Jobs APIs for details) * @param jobId the z/OS jobid of the job to wait for output status (see z/OSMF Jobs APIS for details) @@ -328,4 +321,4 @@ class MonitorJobs( )) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/SubmitJobs.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/SubmitJobs.kt index e501b43..13472b5 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/SubmitJobs.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosjobs/SubmitJobs.kt @@ -27,7 +27,7 @@ class SubmitJobs( /** * Submit a job that resides in a z/OS data set. * - * @param jobDataSet job Dataset to be translated into SubmitJobParams object + * @param jobDataSet job Dataset to be translated into [SubmitJobParams] object * @return job document with details about the submitted job * @throws Exception error on submitting */ @@ -38,7 +38,7 @@ class SubmitJobs( /** * Submit a job that resides in a z/OS data set. * - * @param params submit job parameters, see SubmitJobParams object + * @param params [SubmitJobParams] object * @return job document with details about the submitted job * @throws Exception error on submitting */ @@ -75,7 +75,7 @@ class SubmitJobs( /** * Submit a JCL string to run * - * @param params submit jcl parameters, see SubmitJclParams object + * @param params [SubmitJclParams] object * @return job document with details about the submitted job * @throws Exception error on submitting */ @@ -98,4 +98,4 @@ class SubmitJobs( return response?.body() as SubmitJobRequest? ?: throw Exception("No body returned") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/CollectedResponses.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/CollectedResponses.kt new file mode 100644 index 0000000..59771e8 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/CollectedResponses.kt @@ -0,0 +1,21 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.TsoResponse + +/** + * Tso collected Responses + */ +data class CollectedResponses( + + /** + * z/OSMF synchronous most tso command response messages. + */ + val tsos: List = emptyList(), + + /** + * Appended collected messages including READY prompt at the end. + */ + val messages: String? = null +) \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/IssueResponse.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/IssueResponse.kt new file mode 100644 index 0000000..d7bfe29 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/IssueResponse.kt @@ -0,0 +1,43 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.TsoResponse + +/** + * The TsoSend API response + */ +data class IssueResponse( + + /** + * True if the command was issued and the responses were collected. + */ + val success: Boolean = false, + + /** + * zOSMF start TSO API response. + */ + val startResponse: StartStopResponses? = null, + + /** + * Indicates if started TSO contains "READY " message + */ + val startReady: Boolean = false, + + /** + * zOSMF stop TSO API response. + */ + val stopResponse: StartStopResponse? = null, + + /** + * The list of zOSMF send API responses. May issue multiple requests or + * to ensure that all messages are collected. Each individual response is placed here. + */ + val zosmfResponses: List? = emptyList(), + + /** + * The command response text. + */ + val commandResponses: String? = null + +) \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/IssueTso.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/IssueTso.kt new file mode 100644 index 0000000..3fd0fd4 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/IssueTso.kt @@ -0,0 +1,88 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.TsoResponse +import eu.ibagroup.r2z.UnsafeOkHttpClient +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zostso.input.StartTsoParams +import okhttp3.OkHttpClient +import retrofit2.Response + +/** + * Class to handle issue command to TSO + */ +class IssueTso( + var connection: ZOSConnection, + var httpClient: OkHttpClient = UnsafeOkHttpClient.unsafeOkHttpClient +) { + + init { + connection.checkConnection() + } + + var response: Response<*>? = null + + /** + * API method to start a TSO address space with provided parameters, issue a command, + * collect responses until prompt is reached, and terminate the address space. + * + * @param accountNumber accounting info for Jobs + * @param command command text to issue to the TSO address space. + * @param startParams start tso parameters, see startParams object + * @return issue tso response, see IssueResponse object + * @throws Exception error executing command + */ + fun issueTsoCommand(accountNumber: String, command: String, startParams: StartTsoParams): IssueResponse { + if (accountNumber.isEmpty()) { + throw Exception("accountNumber not specified") + } + if (command.isEmpty()) { + throw Exception("command not specified") + } + + // first stage open tso servlet session to use for our tso command processing + val startTso = StartTso(connection, httpClient) + val startResponse = startTso.start(accountNumber, startParams) + + if (!startResponse.success) { + throw Exception("TSO address space failed to start. Error: ${startResponse.failureResponse ?: "Unknown error"}") + } + + val zosmfTsoResponses = mutableListOf() + zosmfTsoResponses.add(startResponse.tsoResponse ?: throw Exception("no zosmf start tso response")) + val servletKey = startResponse.servletKey + + // second stage send command to tso servlet session created in first stage and collect all tso responses + val sendTso = SendTso(connection, httpClient) + val sendResponse = sendTso.sendDataToTSOCollect(servletKey, command) + + zosmfTsoResponses.addAll(sendResponse.tsoResponses) + + // lastly save the command response to our issueResponse reference + val stopTso = StopTso(connection, httpClient) + val stopResponse = stopTso.stop(servletKey) + + return IssueResponse( + success = sendResponse.success, + startResponse = startResponse, + zosmfResponses = zosmfTsoResponses, + commandResponses = sendResponse.commandResponse ?: throw Exception("error getting command response"), + stopResponse = stopResponse + ) + } + + /** + * API method to start a TSO address space, issue a command, collect responses until prompt is reached, and + * terminate the address space. + * + * @param accountNumber accounting info for Jobs + * @param command command text to issue to the TSO address space. + * @return issue tso response, see IssueResponse object + * @throws Exception error executing command + */ + fun issueTsoCommand(accountNumber: String, command: String): IssueResponse { + return issueTsoCommand(accountNumber, command, StartTsoParams()) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/SendResponse.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/SendResponse.kt new file mode 100644 index 0000000..a3b6b40 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/SendResponse.kt @@ -0,0 +1,27 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.TsoResponse + +/** + * The TsoSend API response + */ +data class SendResponse( + + /** + * True if the command was issued and the responses were collected. + */ + val success: Boolean, + + /** + * The list of zOSMF send API responses. May issue multiple requests or + * to ensure that all messages are collected. Each individual response is placed here. + */ + val tsoResponses: List = emptyList(), + + /** + * The command response text. + */ + val commandResponse: String? = null +) diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/SendTso.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/SendTso.kt new file mode 100644 index 0000000..6727b25 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/SendTso.kt @@ -0,0 +1,168 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zostso.input.SendTsoParams +import okhttp3.Credentials +import okhttp3.OkHttpClient +import retrofit2.Response +import kotlin.jvm.Throws + +/** + * Class to handle sending data to TSO + */ +class SendTso( + var connection: ZOSConnection, + var httpClient: OkHttpClient = UnsafeOkHttpClient.unsafeOkHttpClient +) { + + init { + connection.checkConnection() + } + + var response: Response<*>? = null + + /** + * Create Response + * + * @param responses responses from CollectedResponses object + * @return [SendResponse] + */ + @Throws(Exception::class) + private fun createResponse(responses: CollectedResponses): SendResponse { + return SendResponse( + true, + responses.tsos, + responses.messages ?: throw Exception("no responses messages exist") + ) + } + + /** + * Collects responses from address space until it reaches prompt + * + * @param tsoResponse object from first Tso response from witch responses are needed, see [TsoResponse] + * @return [CollectedResponses] response object + * @throws Exception error executing command + */ + @Throws(Exception::class) + fun getAllResponses(tsoResponse: TsoResponse): CollectedResponses { + var tso = tsoResponse + var done = false + val messages = StringBuilder() + val tsos = mutableListOf() + tsos.add(tso) + while(!done) { + if (tso.tsoData.isNotEmpty()) { + tso.tsoData.forEach { + if (it.tsoMessage != null) { + val tsoMsg = it.tsoMessage + tsoMsg?.data?.let { data -> + messages.append(data) + messages.append("\n") + } + } else if (it.tsoPrompt != null) { + if (messages.toString().contains("IKJ56602I COMMAND SYSTEM RESTARTING DUE TO ERROR")) { + val IKJ56602I = "IKJ56602I COMMAND SYSTEM RESTARTING DUE TO ERROR" + val msg = messages.toString() + val startIndex = msg.indexOf("IKJ56602I") + messages.delete(startIndex, startIndex + IKJ56602I.length + "\nREADY".length) + } else if (messages.isNotEmpty() && messages.toString().contains("READY")) { + done = true + } + // TSO PROMPT reached without getting any data, retrying + } + } + } + if (!done) { + tso.servletKey?.let { tso = getDataFromTso(it) } ?: throw Exception("servlet key missing") + tsos.add(tso) + } + } + return CollectedResponses(tsos, messages.toString()) + } + + /** + * Retrieve tso http request response + * + * @param servletKey key of tso address space + * @return z/OSMF [TsoResponse] + * @throws Exception error executing command + */ + @Throws(Exception::class) + private fun getDataFromTso(servletKey: String): TsoResponse { + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val tsoApi = buildApi(url, httpClient) + val call = tsoApi.receiveMessagesFromTso( + authorizationToken = Credentials.basic(connection.user, connection.password), + servletKey = servletKey + ) + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception("Follow up TSO Messages from TSO command cannot be retrieved. " + response?.errorBody()?.string()) + } + return response?.body() as TsoResponse? ?: throw Exception("No body returned") + } + + /** + * API method to send data to already started TSO address space, but will read TSO data until a PROMPT is reached. + * + * @param command to send to the TSO address space. + * @param servletKey returned from a successful start + * @return [SendResponse] object + * @throws Exception error executing command + */ + @Throws(Exception::class) + fun sendDataToTSOCollect(servletKey: String, command: String): SendResponse { + if (servletKey.isEmpty()) { + throw Exception("servletKey not specified") + } + if (command.isEmpty()) { + throw Exception("command not specified") + } + + val putResponse = sendDataToTSOCommon( + SendTsoParams(servletKey = servletKey, data = command) + ) + + val responses = getAllResponses(putResponse) + return createResponse(responses) + } + + /** + * API method to send data to already started TSO address space + * + * @param commandParams [SendTsoParams] object with required parameters + * @return [TsoResponse] object + * @throws Exception error executing command + */ + @Throws(Exception::class) + fun sendDataToTSOCommon(commandParams: SendTsoParams): TsoResponse { + if (commandParams.data.isEmpty()) { + throw Exception("commandParams data not specified") + } + if (commandParams.servletKey.isEmpty()) { + throw Exception("commandParams servletKey not specified") + } + + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val tsoApi = buildApi(url, httpClient) + val call = tsoApi.sendMessageToTso( + authorizationToken = Credentials.basic(connection.user, connection.password), + body = TsoData( + tsoResponse = MessageType(version = "0100", data = commandParams.data) + ), + servletKey = commandParams.servletKey + ) + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception( + "No results from executing tso command after getting TSO address space. " + + response?.errorBody()?.string() + ) + } + return response?.body() as TsoResponse? ?: throw Exception("No body returned") + } + +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartStopResponse.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartStopResponse.kt new file mode 100644 index 0000000..d2c86f9 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartStopResponse.kt @@ -0,0 +1,32 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.TsoResponse + +/** + * The TsoStartStop API response + */ +data class StartStopResponse( + + /** + * Response from z/OSMF to start rest call + */ + val tsoResponse: TsoResponse? = null, + + /** + * Servlet key from ZosmfTsoResponse + */ + val servletKey: String? = null, + + /** + * If an error occurs, returns error which contains cause error. + */ + var failureResponse: String? = null, + + /** + * True if the command was issued and the responses were collected. + */ + val success: Boolean? = false + +) \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartStopResponses.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartStopResponses.kt new file mode 100644 index 0000000..f062dbd --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartStopResponses.kt @@ -0,0 +1,63 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.TsoResponse + +/** + * The TsoStartStop API responses + */ +class StartStopResponses( + + /** + * Response from z/OSMF to start rest call + */ + val tsoResponse: TsoResponse?, + + collectedResponses: CollectedResponses? +) { + + /** + * If an error occurs, returns the error which contains cause error. + */ + val failureResponse: String? + + /** + * Appended collected messages including READY prompt at the end. + */ + val messages: String + + /** + * True if the command was issued and the responses were collected. + */ + val success: Boolean + + /** + * Collected responses from z/OSMF + */ + var collectedResponses: List + + /** + * Servlet key from TsoResponse + */ + var servletKey: String + + init { + tsoResponse ?: throw Exception("tsoResponse is null") + + if (tsoResponse.msgData.isNotEmpty()) { + this.success = false + val zosmfMsg = tsoResponse.msgData[0] + this.failureResponse = zosmfMsg.messageText ?: "zOSMF unknown error response" + } else { + this.success = true + this.failureResponse = null + } + + this.servletKey = tsoResponse.servletKey ?: throw Exception("servletKey is missing") + + val tsoMsgLst = tsoResponse.tsoData + this.messages = tsoMsgLst.joinToString() + this.collectedResponses = collectedResponses?.tsos ?: emptyList() + } +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartTso.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartTso.kt new file mode 100644 index 0000000..2e2ef6b --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StartTso.kt @@ -0,0 +1,89 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zostso.input.StartTsoParams +import okhttp3.Credentials +import okhttp3.OkHttpClient +import retrofit2.Response + +/** + * Start TSO address space and receive servlet key + */ +class StartTso( + var connection: ZOSConnection, + var httpClient: OkHttpClient = UnsafeOkHttpClient.unsafeOkHttpClient +) { + + init { + connection.checkConnection() + } + + var response: Response<*>? = null + + /** + * Start TSO address space with provided parameters. + * + * @param accountNumber this key of StartTsoParams required, because it cannot be default. + * @param params optional [StartTsoParams] object with required parameters + * @return [StartStopResponses] command response on resolve + * @throws Exception error executing command + */ + @Throws(Exception::class) + fun start(accountNumber: String, params: StartTsoParams): StartStopResponses { + if (accountNumber.isEmpty()) { + throw Exception("accountNumber not specified") + } + + val customParams = StartTsoParams( + account = accountNumber, + characterSet = params.characterSet ?: TsoConstants.DEFAULT_CHSET, + codePage = params.codePage ?: TsoConstants.DEFAULT_CPAGE, + rows = params.rows ?: TsoConstants.DEFAULT_ROWS, + columns = params.columns ?: TsoConstants.DEFAULT_COLS, + logonProcedure = params.logonProcedure ?: TsoConstants.DEFAULT_PROC, + regionSize = params.regionSize ?: TsoConstants.DEFAULT_RSIZE, + ) + + val tsoResponse = startCommon(customParams) + + var collectedResponses: CollectedResponses? = null + if (tsoResponse.servletKey != null) { + val sendTso = SendTso(connection, httpClient) + collectedResponses = sendTso.getAllResponses(tsoResponse) + } + + return StartStopResponses(tsoResponse, collectedResponses) + } + + /** + * Start TSO address space with provided parameters + * + * @param commandParams [StartTsoParams] object with required parameters + * @return [TsoResponse] z/OSMF response object + * @throws Exception error executing command + */ + @Throws(Exception::class) + fun startCommon(commandParams: StartTsoParams): TsoResponse { + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val tsoApi = buildApi(url, httpClient) + val call = tsoApi.startTso( + authorizationToken = Credentials.basic(connection.user, connection.password), + acct = commandParams.account ?: throw Exception("account num not specified"), + proc = commandParams.logonProcedure ?: TsoConstants.DEFAULT_PROC, + chset = commandParams.characterSet ?: TsoConstants.DEFAULT_CHSET, + cpage = commandParams.codePage ?: TsoConstants.DEFAULT_CPAGE, + rows = commandParams.rows?.toInt() ?: TsoConstants.DEFAULT_ROWS.toInt(), + cols = commandParams.columns?.toInt() ?: TsoConstants.DEFAULT_COLS.toInt(), + rsize = commandParams.regionSize?.toInt() ?: TsoConstants.DEFAULT_RSIZE.toInt() + ) + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception("No results from executing tso command while setting up TSO address space. " + + response?.errorBody()?.string()) + } + return response?.body() as TsoResponse? ?: throw Exception("No body returned") + } +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StopTso.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StopTso.kt new file mode 100644 index 0000000..c21c2b3 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/StopTso.kt @@ -0,0 +1,82 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +import eu.ibagroup.r2z.TsoApi +import eu.ibagroup.r2z.TsoResponse +import eu.ibagroup.r2z.UnsafeOkHttpClient +import eu.ibagroup.r2z.buildApi +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zostso.input.StopTsoParams +import okhttp3.Credentials +import okhttp3.OkHttpClient +import retrofit2.Response + +/** + * Stop active TSO address space using servlet key + */ +class StopTso( + var connection: ZOSConnection, + var httpClient: OkHttpClient = UnsafeOkHttpClient.unsafeOkHttpClient +) { + + init { + connection.checkConnection() + } + + var response: Response<*>? = null + + /** + * Stop TSO address space and populates response with [StartStopResponse] + * + * @param servletKey unique servlet entry identifier + * @return [StartStopResponse] object + * @throws Exception error on TSO sto command + */ + fun stop(servletKey: String): StartStopResponse { + if (servletKey.isEmpty()) { + throw Exception("servletKey not specified") + } + + val tsoResponse = stopCommon(StopTsoParams(servletKey)) + val startStopResponse = StartStopResponse( + tsoResponse = tsoResponse, + servletKey = tsoResponse.servletKey ?: "", + success = tsoResponse.servletKey != null + ) + if (tsoResponse.msgData.isNotEmpty()) { + val zosmfMsg = tsoResponse.msgData[0] + val msgText = zosmfMsg.messageText ?: TsoConstants.ZOSMF_UNKNOWN_ERROR + startStopResponse.failureResponse = msgText + } + + return startStopResponse + } + + /** + * Sends REST call to z/OSMF for stopping active TSO address space + * + * @param commandParams [StopTsoParams] command parameters + * @return [TsoResponse] z/OSMF response object + * @throws Exception error on TSO sto command + */ + fun stopCommon(commandParams: StopTsoParams): TsoResponse { + if (commandParams.servletKey.isNullOrEmpty()) { + throw Exception("commandParams servletKey not specified") + } + + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val tsoApi = buildApi(url, httpClient) + val call = tsoApi.endTso( + authorizationToken = Credentials.basic(connection.user, connection.password), + servletKey = commandParams.servletKey + ) + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception("Failed to stop active TSO address space. ${response?.errorBody()?.string()}") + } + + return response?.body() as TsoResponse? ?: throw Exception("No body returned") + } + +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/TsoConstants.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/TsoConstants.kt new file mode 100644 index 0000000..2ebc5fa --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/TsoConstants.kt @@ -0,0 +1,43 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso + +/** + * Constants for various tso related info + */ +object TsoConstants { + /** + * Default character-set value + */ + const val DEFAULT_CHSET = "697" + + /** + * Default number of columns value + */ + const val DEFAULT_COLS = "80" + + /** + * Default code page value + */ + const val DEFAULT_CPAGE = "1047" + + /** + * Default logonProcedure value + */ + const val DEFAULT_PROC = "IZUFPROC" + + /** + * Default number of rows value + */ + const val DEFAULT_ROWS = "24" + + /** + * Default region-size value + */ + const val DEFAULT_RSIZE = "4096" + + /** + * z/OSMF unknown error + */ + const val ZOSMF_UNKNOWN_ERROR = "zOSMF unknown error response" +} \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/SendTsoParams.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/SendTsoParams.kt new file mode 100644 index 0000000..281d071 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/SendTsoParams.kt @@ -0,0 +1,19 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso.input + +/** + * TSO issue command z/OSMF parameters + */ +data class SendTsoParams( + + /** + * Servlet key of an active address space. + */ + val servletKey: String, + + /** + * Data to be sent to the active address space. + */ + val data: String +) \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/StartTsoParams.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/StartTsoParams.kt new file mode 100644 index 0000000..48eb178 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/StartTsoParams.kt @@ -0,0 +1,44 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso.input + +/** + * TSO start command z/OSMF parameters + */ +data class StartTsoParams( + + /** + * User's z/OS permission account number + */ + val account: String? = null, + + /** + * Character set for address space + */ + val characterSet: String? = null, + + /** + * Code page for tso address space + */ + val codePage: String? = null, + + /** + * Number of columns + */ + val columns: String? = null, + + /** + * Name of the logonProcedure for address space + */ + val logonProcedure: String? = null, + + /** + * Region size for tso address space + */ + val regionSize: String? = null, + + /** + * Number of rows + */ + val rows: String? = null +) diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/StopTsoParams.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/StopTsoParams.kt new file mode 100644 index 0000000..ff82dc5 --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zostso/input/StopTsoParams.kt @@ -0,0 +1,15 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zostso.input + +/** + * TSO stop command z/OSMF parameters + */ +data class StopTsoParams( + + /** + * Servlet key of an active address space + */ + val servletKey: String? = null + +) \ No newline at end of file diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosuss/ZosUssCopy.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosuss/ZosUssCopy.kt new file mode 100644 index 0000000..db3506d --- /dev/null +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosuss/ZosUssCopy.kt @@ -0,0 +1,108 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.client.sdk.zosuss + +import eu.ibagroup.r2z.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import okhttp3.Credentials +import okhttp3.OkHttpClient +import retrofit2.Response + +class ZosUssCopy ( + var connection: ZOSConnection, + var httpClient: OkHttpClient = UnsafeOkHttpClient.unsafeOkHttpClient +) { + init { + connection.checkConnection() + } + + var response: Response<*>? = null + + /** + * Copies USS file + * + * @param filePath path of the file or directory (e.g. u/jiahj/text.txt) + * @param destPath path where to copy the file + * @param replace if true file in the target destination will be overwritten + * @return http response object + * @throws Exception error processing request + */ + fun copy(filePath: String, destPath: String, replace: Boolean): Response<*> { + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val dataApi = buildApi(url, httpClient) + val call = dataApi.copyUssFile( + authorizationToken = Credentials.basic(connection.user, connection.password), + body = CopyDataUSS.CopyFromFileOrDir( + from = filePath, + overwrite = replace + ), + filePath = FilePath(destPath) + ) + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception(response?.errorBody()?.string()) + } + return response ?: throw Exception("No response returned") + } + + /** + * Copies USS file to sequential dataset + * + * @param filePath path of the file or directory (e.g. u/jiahj/text.txt) + * @param dsn dataset where to copy the file + * @param replace if true information in the target dataset will be replaced + * @return http response object + * @throws Exception error processing request + */ + fun copyToDS(filePath: String, dsn: String, replace: Boolean): Response<*> { + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val dataApi = buildApi(url, httpClient) + val call = dataApi.copyToDatasetFromUss( + authorizationToken = Credentials.basic(connection.user, connection.password), + body = CopyDataZOS.CopyFromFile( + file = CopyDataZOS.CopyFromFile.File( + fileName = filePath + ), + replace = replace + ), + toDatasetName = dsn + ) + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception(response?.errorBody()?.string()) + } + return response ?: throw Exception("No response returned") + } + + /** + * Copies USS file to dataset member + * + * @param filePath path of the file or directory (e.g. u/jiahj/text.txt) + * @param dsn dataset where to copy the file + * @param member dataset member where to copy the file + * @param replace if true information in the target member will be replaced + * @return http response object + * @throws Exception error processing request + */ + fun copyToMember(filePath: String, dsn: String, member: String, replace: Boolean): Response<*> { + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val dataApi = buildApi(url, httpClient) + val call = dataApi.copyToDatasetMemberFromUssFile( + authorizationToken = Credentials.basic(connection.user, connection.password), + body = CopyDataZOS.CopyFromFile( + file = CopyDataZOS.CopyFromFile.File( + fileName = filePath + ), + replace = replace + ), + toDatasetName = dsn, + memberName = member + ) + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception(response?.errorBody()?.string()) + } + return response ?: throw Exception("No response returned") + } + +} diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosuss/ZosUssFile.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosuss/ZosUssFile.kt index 5bbe6dc..5b94d70 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosuss/ZosUssFile.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/client/sdk/zosuss/ZosUssFile.kt @@ -43,7 +43,7 @@ class ZosUssFile ( * Creates a new file or directory with specified parameters * * @param filePath path of the file or directory (e.g. u/jiahj/text.txt) - * @param params create USS file parameters, see CreateUssFile class + * @param params [CreateUssFile] parameters * @return http response object * @throws Exception error processing request */ @@ -72,7 +72,7 @@ class ZosUssFile ( */ fun writeToFile(filePath: String, text: ByteArray): Response<*> { val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" - val dataApi = buildApi(url, httpClient) + val dataApi = buildApiWithBytesConverter(url, httpClient) val call = dataApi.writeToUssFile( authorizationToken = Credentials.basic(connection.user, connection.password), filePath = FilePath(filePath), @@ -84,4 +84,29 @@ class ZosUssFile ( } return response ?: throw Exception("No response returned") } + + /** + * Writes to USS binary file. Creates new if not exist + * + * @param filePath path of the file or directory (e.g. u/jiahj/text.txt) + * @param inputFile file to be written to + * @return http response object + * @throws Exception error processing request + */ + fun writeToFileBin(filePath: String, inputFile: ByteArray): Response<*> { + val url = "${connection.protocol}://${connection.host}:${connection.zosmfPort}" + val dataApi = buildApiWithBytesConverter(url, httpClient) + val call = dataApi.writeToUssFile( + authorizationToken = Credentials.basic(connection.user, connection.password), + filePath = FilePath(filePath), + body = inputFile, + xIBMDataType = XIBMDataType(XIBMDataType.Type.BINARY), + contentType = "application/octet-stream" + ) + response = call.execute() + if (response?.isSuccessful != true) { + throw Exception(response?.errorBody()?.string()) + } + return response ?: throw Exception("No response returned") + } } diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/config/ZoweConfig.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/config/ZoweConfig.kt index 8e1abe7..1e7f5ee 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/config/ZoweConfig.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/config/ZoweConfig.kt @@ -13,7 +13,6 @@ package eu.ibagroup.r2z.zowe.config import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.annotations.SerializedName -import eu.ibagroup.r2z.CodePage import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection import java.io.File import java.lang.IllegalStateException @@ -40,7 +39,7 @@ class ZoweConfig( /** * Builder class for setting the sequence of profiles to search property by name. - * @param propName - property name to search. + * @param propName property name to search. */ inner class PropertyBuilder(val propName: String) { var profilesToSearchProp = mutableListOf() @@ -117,10 +116,10 @@ class ZoweConfig( /** * Searches for a property with creating profiles sequence to search. * @see search - * @param propName - property name to search. - * @param block - extension function for PropertyBuilder class. This parameter is needed for - * creating a sequence of profiles to search by invoking corresponding methods - * in the right order. + * @param propName property name to search. + * @param block extension function for PropertyBuilder class. This parameter is needed for + * creating a sequence of profiles to search by invoking corresponding methods + * in the right order. * @return Property value. */ fun searchProperty (propName: String, block: PropertyBuilder.() -> Unit): Any? { @@ -130,10 +129,10 @@ class ZoweConfig( /** * Searches for a property and updates it in found profile with creating profiles sequence to search. * @see set - * @param propName - property name to search. - * @param block - extension function for PropertyBuilder class. This parameter is needed for - * creating a sequence of profiles to search by invoking corresponding methods - * in the right order. + * @param propName property name to search. + * @param block extension function for PropertyBuilder class. This parameter is needed for + * creating a sequence of profiles to search by invoking corresponding methods + * in the right order. * @return Nothing. */ fun updateProperty (propName: String, propValue: Any?, block: PropertyBuilder.() -> Unit) { @@ -144,7 +143,7 @@ class ZoweConfig( * Extracts and decodes config object of all files from credential storage. * @see KeytarWrapper * @see DefaultKeytarWrapper - * @param keytar - instance of KeytarWrapper class. This param is needed for accessing credential storage. + * @param keytar instance of [KeytarWrapper]. This param is needed for accessing credential storage. * @return Map where key is config file path and value is map of secure properties. * For example: * { @@ -174,8 +173,8 @@ class ZoweConfig( /** * Extracts secure properties from secure store by zowe config file path in current instance. * @see readZoweCredentialsFromStorage - * @param filePath - path of zowe.config.json file. Secure props will be extracted by this parameter. - * @param keytar - instance of KeytarWrapper class. This param is needed for accessing credential storage. + * @param filePath path of zowe.config.json file. Secure props will be extracted by this parameter. + * @param keytar instance of [KeytarWrapper]. This param is needed for accessing credential storage. * @return Nothing. */ fun extractSecureProperties (filePath: String, keytar: KeytarWrapper = DefaultKeytarWrapper()) { @@ -196,9 +195,9 @@ class ZoweConfig( /** * Updates secure object for provided file in credential object and save these changes to credential storage. * @see readZoweCredentialsFromStorage - * @param filePath - path of zowe.config.json file. Secure props will be saved - * inside this property of connection object. - * @param keytar - instance of KeytarWrapper class. This param is needed for accessing credential storage. + * @param filePath path of zowe.config.json file. Secure props will be saved + * inside this property of connection object. + * @param keytar instance of [KeytarWrapper]. This param is needed for accessing credential storage. * @return Nothing. */ fun saveSecureProperties (filePath: String, keytar: KeytarWrapper = DefaultKeytarWrapper()) { @@ -228,9 +227,9 @@ class ZoweConfig( /** * Extracts secure properties from secure store by zowe config file path in current instance. * @see readZoweCredentialsFromStorage - * @param filePathTokens - path of zowe.config.json file splitted by delimiter. - * Secure props will be extracted by this parameter. - * @param keytar - instance of KeytarWrapper class. This param is needed for accessing credential storage. + * @param filePathTokens path of zowe.config.json file splitted by delimiter. + * Secure props will be extracted by this parameter. + * @param keytar instance of [KeytarWrapper]. This param is needed for accessing credential storage. * @return Nothing. */ fun extractSecureProperties (filePathTokens: Array, keytar: KeytarWrapper = DefaultKeytarWrapper()) { @@ -240,9 +239,9 @@ class ZoweConfig( /** * Updates secure object for provided file in credential object and save these changes to credential storage. * @see readZoweCredentialsFromStorage - * @param filePath - path of zowe.config.json file splitted by delimiter. - * Secure props will be saved inside this property of connection object. - * @param keytar - instance of KeytarWrapper class. This param is needed for accessing credential storage. + * @param filePath path of zowe.config.json file splitted by delimiter. + * Secure props will be saved inside this property of connection object. + * @param keytar instance of [KeytarWrapper]. This param is needed for accessing credential storage. * @return Nothing. */ fun saveSecureProperties (filePathTokens: Array, keytar: KeytarWrapper = DefaultKeytarWrapper()) { @@ -250,7 +249,7 @@ class ZoweConfig( } /** - * Deserializes current instance of ZoweConfig to json string without secure properties. + * Deserializes current [ZoweConfig] instance to JSON string without secure properties. * @return String with deserialized object. */ fun toJson (): String { @@ -265,9 +264,8 @@ class ZoweConfig( } /** - * Creates ZOSConnection based on zowe config or throws exception if data is not correct. - * @return ZOSConnection instance - * @see ZOSConnection + * Creates [ZOSConnection] based on zowe config or throws exception if data is not correct. + * @return [ZOSConnection] instance */ fun toZosConnection(): ZOSConnection { if (host?.isEmpty() != false || port == null || user?.isEmpty() != false || password == null || protocol.isEmpty()){ @@ -312,15 +310,11 @@ class ZoweConfig( get() = searchProperty("responseTimeout") { zosmf(); base() } as Long? ?: 600 set(el) { updateProperty("responseTimeout", el) { zosmf(); base() } } - var codePage: CodePage - get() = CodePage.valueOf("IBM_${(searchProperty("codePage") { tso(); base() } as String).filter { it.isDigit() }}") - set(el) { updateProperty("codePage", el.codePage.filter { it.isDigit() }) { tso(); base() } } - /** * Searches profile by its path. For example if profile has path "gr1.example" then it will search * profile "example" in "gr1" group. - * @param searchPath - path to search profile - * @return found profile or null if searchPath is not valid or no one profile exists by this path + * @param searchPath path to search profile + * @return found profile or null if *searchPath* is not valid or no one profile exists by this path */ fun profile(searchPath: String?): ZoweConfigProfile? { searchPath ?: return null diff --git a/src/main/kotlin/eu/ibagroup/r2z/zowe/config/utils.kt b/src/main/kotlin/eu/ibagroup/r2z/zowe/config/utils.kt index 8c7cfa0..3f2d050 100644 --- a/src/main/kotlin/eu/ibagroup/r2z/zowe/config/utils.kt +++ b/src/main/kotlin/eu/ibagroup/r2z/zowe/config/utils.kt @@ -79,9 +79,9 @@ private fun formProfiles (profiles: Map?) { } /** - * Parses json string to ZoweConfig object model. - * @param configString - json string with zowe config. - * @return ZoweConfig object model. + * Parses JSON string to [ZoweConfig] object model. + * @param configString JSON string with zowe config. + * @return [ZoweConfig] object model. */ fun parseConfigJson(configString: String): ZoweConfig { val zoweConfig = Gson().fromJson(configString, ZoweConfig::class.java) @@ -105,32 +105,32 @@ fun parseConfigJson (inputStream: InputStream): ZoweConfig = parseConfigJson(Str interface KeytarWrapper { /** * Returns a password by service name and account. - * @param service - service name. - * @param account - account name. + * @param service service name. + * @param account account name. * @return extracted password. */ fun getPassword(service: String, account: String): String /** * Updates or creates password for account of service. - * @param service - service name. - * @param account - account name + * @param service service name. + * @param account account name * @return Nothing. */ fun setPassword(service: String, account: String, password: String) /** * Removes credentials for account in service. If account in service is single than it removes a service. - * @param service - service name. - * @param account - account name. + * @param service service name. + * @param account account name. * @return true if success and false otherwise. */ fun deletePassword(service: String, account: String): Boolean /** * Extracts all credentials for service. - * @param service - service name. - * @return Map where key is account name in service and value is password for this account. + * @param service service name. + * @return [Map] where key is account name in service and value is password for this account. */ fun getCredentials(service: String): Map } diff --git a/src/test/kotlin/eu/ibagroup/r2z/InfoAPITest.kt b/src/test/kotlin/eu/ibagroup/r2z/InfoAPITest.kt new file mode 100644 index 0000000..719398d --- /dev/null +++ b/src/test/kotlin/eu/ibagroup/r2z/InfoAPITest.kt @@ -0,0 +1,83 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z + +import com.google.gson.GsonBuilder +import eu.ibagroup.r2z.zowe.* +import okhttp3.OkHttpClient +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.lang.Exception +import java.net.InetSocketAddress +import java.net.Proxy + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class InfoAPITest { + lateinit var mockServer: MockWebServer + lateinit var proxyClient: OkHttpClient + lateinit var responseDispatcher: MockResponseDispatcher + lateinit var infoAPI: InfoAPI + + @BeforeAll + fun createMockServer() { + mockServer = MockWebServer() + responseDispatcher = MockResponseDispatcher() + mockServer.dispatcher = responseDispatcher + mockServer.start() + val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(mockServer.hostName, mockServer.port)) + proxyClient = OkHttpClient.Builder().proxy(proxy).build() + val gson = GsonBuilder().create() + infoAPI = Retrofit.Builder() + .baseUrl("http://${TEST_HOST}:${TEST_PORT}") + .addConverterFactory(GsonConverterFactory.create(gson)) + .client(proxyClient) + .build() + .create(InfoAPI::class.java) + } + + @AfterEach + fun cleanupTest() { + responseDispatcher.clearValidationList() + } + + @AfterAll + fun stopMockServer() { + mockServer.shutdown() + } + + @Test + fun testPluginsAdapterForArrayResponse() { + responseDispatcher.injectEndpoint( + { true }, + { MockResponse().setBody(responseDispatcher.readMockJson("infoResponse") ?: "") } + ) + responseDispatcher.removeAuthorizationFromZosmfEndpoint("info") + + val response = infoAPI.getSystemInfo().execute() + Assertions.assertEquals(response.isSuccessful, true) + val result = response.body() ?: throw Exception("Response for info request should not be empty") + Assertions.assertEquals(result.plugins.size, 3) + } + + @Test + fun testPluginsAdapterForObjectResponse() { + responseDispatcher.injectEndpoint( + { true }, + { MockResponse().setBody(responseDispatcher.readMockJson("infoResponsePluginsError") ?: "") } + ) + responseDispatcher.removeAuthorizationFromZosmfEndpoint("info") + + val response = infoAPI.getSystemInfo().execute() + Assertions.assertEquals(response.isSuccessful, true) + val result = response.body() ?: throw Exception("Response for info request should not be empty") + Assertions.assertEquals(result.plugins.size, 0) + } +} \ No newline at end of file diff --git a/src/test/kotlin/eu/ibagroup/r2z/zowe/MockResponseDispatcher.kt b/src/test/kotlin/eu/ibagroup/r2z/zowe/MockResponseDispatcher.kt index ff79d5c..c3fd7d9 100644 --- a/src/test/kotlin/eu/ibagroup/r2z/zowe/MockResponseDispatcher.kt +++ b/src/test/kotlin/eu/ibagroup/r2z/zowe/MockResponseDispatcher.kt @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Assertions class MockResponseDispatcher : Dispatcher() { var validationList = mutableListOfBoolean, (RecordedRequest?)->MockResponse>>() + private var endpointsWithoutAuthorization = mutableSetOf() private fun getResourceText(resourcePath: String): String? { return javaClass.classLoader.getResource(resourcePath)?.readText() @@ -23,6 +24,10 @@ class MockResponseDispatcher : Dispatcher() { return base64Credentials.decodeFromBase64() } + fun removeAuthorizationFromZosmfEndpoint (endpoint: String) { + endpointsWithoutAuthorization.add(endpoint) + } + fun injectEndpoint (acceptable: (RecordedRequest?)->Boolean, handler: (RecordedRequest?)->MockResponse) { validationList.add(Pair(acceptable, handler)) } @@ -32,12 +37,15 @@ class MockResponseDispatcher : Dispatcher() { } override fun dispatch(request: RecordedRequest): MockResponse { - val authTokenRequest = request.getHeader("Authorization") ?: Assertions.fail("auth token must be presented.") - val credentials = decodeBasicAuthToken(authTokenRequest).split(":") - val usernameRequest = credentials[0] - val passwordRequest = credentials[1] - Assertions.assertEquals(usernameRequest, TEST_USER) - Assertions.assertEquals(passwordRequest, TEST_PASSWORD) + val zosmfPath = request.requestLine.split("/zosmf/").last() + if (endpointsWithoutAuthorization.none { zosmfPath.contains(it) }) { + val authTokenRequest = request.getHeader("Authorization") ?: Assertions.fail("auth token must be presented.") + val credentials = decodeBasicAuthToken(authTokenRequest).split(":") + val usernameRequest = credentials[0] + val passwordRequest = credentials[1] + Assertions.assertEquals(usernameRequest, TEST_USER) + Assertions.assertEquals(passwordRequest, TEST_PASSWORD) + } return validationList.firstOrNull { it.first(request) }?.second?.let { it(request) } ?: return MockResponse().setResponseCode(404) } diff --git a/src/test/kotlin/eu/ibagroup/r2z/zowe/zosconsole/IssueCommandTest.kt b/src/test/kotlin/eu/ibagroup/r2z/zowe/zosconsole/IssueCommandTest.kt new file mode 100644 index 0000000..218d59c --- /dev/null +++ b/src/test/kotlin/eu/ibagroup/r2z/zowe/zosconsole/IssueCommandTest.kt @@ -0,0 +1,92 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.zosconsole + +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import eu.ibagroup.r2z.IssueRequestBody +import eu.ibagroup.r2z.zowe.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zosconsole.IssueCommand +import okhttp3.OkHttpClient +import org.junit.jupiter.api.* +import java.net.InetSocketAddress +import java.net.Proxy +import kotlin.concurrent.thread + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class IssueCommandTest { + lateinit var mockServer: MockWebServer + lateinit var proxyClient: OkHttpClient + lateinit var responseDispatcher: MockResponseDispatcher + + @BeforeAll + fun createMockServer() { + mockServer = MockWebServer() + responseDispatcher = MockResponseDispatcher() + mockServer.dispatcher = responseDispatcher + mockServer.start() + val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(mockServer.hostName, mockServer.port)) + proxyClient = OkHttpClient.Builder().proxy(proxy).build() + } + + @AfterAll + fun stopMockServer() { + mockServer.shutdown() + } + + @Test + fun issueCommonTest() { + val connection = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val issueCommand = IssueCommand(connection, proxyClient) + + val issueParams = IssueRequestBody( + cmd = "d a,PEGASUS", + solKey = "PEGASUS" + ) + + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("PUT http://.*/zosmf/restconsoles/consoles/ibmusecn HTTP/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("issueCommand") ?: "") + } + ) + + val response = issueCommand.issueCommon("ibmusecn", issueParams) + + Assertions.assertEquals("C8529621", response.cmdResponseKey) + Assertions.assertTrue( + response.cmdResponse?.contains( + " D A,PEGASUS\r\n CNZ4106I 17.06.33 DISPLAY ACTIVITY 128\r") == true + ) + + responseDispatcher.clearValidationList() + } + + @Test + fun issueSimple() { + val connection = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val issueCommand = IssueCommand(connection, proxyClient) + + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("PUT http://.*/zosmf/restconsoles/consoles/defcn HTTP/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("issueCommand") ?: "") + } + ) + + val response = issueCommand.issueSimple("d a,PEGASUS") + + Assertions.assertTrue(response.success == true) + Assertions.assertEquals("C8529621", response.lastResponseKey) + + responseDispatcher.clearValidationList() + } + + + +} diff --git a/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/IssueTsoTest.kt b/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/IssueTsoTest.kt new file mode 100644 index 0000000..4651cea --- /dev/null +++ b/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/IssueTsoTest.kt @@ -0,0 +1,98 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.zostso + +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import eu.ibagroup.r2z.zowe.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zostso.IssueTso +import eu.ibagroup.r2z.zowe.client.sdk.zostso.input.StartTsoParams +import okhttp3.OkHttpClient +import org.junit.jupiter.api.* +import java.net.InetSocketAddress +import java.net.Proxy +import kotlin.concurrent.thread + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class IssueTsoTest { + lateinit var mockServer: MockWebServer + lateinit var proxyClient: OkHttpClient + lateinit var responseDispatcher: MockResponseDispatcher + + @BeforeAll + fun createMockServer() { + mockServer = MockWebServer() + responseDispatcher = MockResponseDispatcher() + mockServer.dispatcher = responseDispatcher + mockServer.start() + val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(mockServer.hostName, mockServer.port)) + proxyClient = OkHttpClient.Builder().proxy(proxy).build() + } + + @AfterAll + fun stopMockServer() { + mockServer.shutdown() + } + + @Test + fun issueTsoTest() { + val connection = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val issueTso = IssueTso(connection, proxyClient) + + val startTsoParams = StartTsoParams( + characterSet = "697", + codePage = "1047", + columns = "160", + rows = "204", + logonProcedure = "DBSPROCB", + regionSize = "50000" + ) + + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("POST http://.*/zosmf/tsoApp/tso.*proc=DBSPROCB.*acct=IZUACCT.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("startTso") ?: "") + } + ) + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("PUT http://.*/zosmf/tsoApp/tso/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("sendMessageToTso") ?: "") + } + ) + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("GET http://.*/zosmf/tsoApp/tso/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("receiveMessagesFromTso") ?: "") + } + ) + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("DELETE http://.*/zosmf/tsoApp/tso/DLIS-121-aabcaaat HTTP/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("stopTso") ?: "") + } + ) + + val response = issueTso.issueTsoCommand("IZUACCT", "TIME", startTsoParams) + + Assertions.assertTrue(response.success) + Assertions.assertEquals("DLIS-121-aabcaaat", response.startResponse?.servletKey) + Assertions.assertTrue( + response.commandResponses?.contains( + "IKJ56650I TIME-06:43:59 PM. CPU-00:00:00 SERVICE-595 SESSION-00:05:00 SEPTEMBER 22,2022") == true + ) + Assertions.assertEquals("DLIS-121-aabcaaat", response.stopResponse?.servletKey) + + responseDispatcher.clearValidationList() + } + +} diff --git a/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/SendTsoTest.kt b/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/SendTsoTest.kt new file mode 100644 index 0000000..951f6f7 --- /dev/null +++ b/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/SendTsoTest.kt @@ -0,0 +1,93 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.zostso + +import com.google.gson.Gson +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import eu.ibagroup.r2z.TsoResponse +import eu.ibagroup.r2z.zowe.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zostso.SendTso +import okhttp3.OkHttpClient +import org.junit.jupiter.api.* +import java.net.InetSocketAddress +import java.net.Proxy +import kotlin.concurrent.thread + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class SendTsoTest { + lateinit var mockServer: MockWebServer + lateinit var proxyClient: OkHttpClient + lateinit var responseDispatcher: MockResponseDispatcher + + @BeforeAll + fun createMockServer() { + mockServer = MockWebServer() + responseDispatcher = MockResponseDispatcher() + mockServer.dispatcher = responseDispatcher + mockServer.start() + val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(mockServer.hostName, mockServer.port)) + proxyClient = OkHttpClient.Builder().proxy(proxy).build() + } + + @AfterAll + fun stopMockServer() { + mockServer.shutdown() + } + + @Test + fun getAllResponses() { + val connection = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val sendTso = SendTso(connection, proxyClient) + + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("GET http://.*/zosmf/tsoApp/tso/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("receiveMessagesFromTso") ?: "") + } + ) + + val tsoResponse = Gson().fromJson(responseDispatcher.readMockJson("startTso"), TsoResponse::class.java) + val response = sendTso.getAllResponses(tsoResponse) + + Assertions.assertEquals(tsoResponse.servletKey, response.tsos[0].servletKey) + Assertions.assertTrue(response.messages?.contains("LOGON IN PROGRESS AT 17:31:11 ON SEPTEMBER 22, 2022") == true) + } + + @Test + fun sendDataToTSOCollect() { + val connection = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val sendTso = SendTso(connection, proxyClient) + + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("PUT http://.*/zosmf/tsoApp/tso/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("sendMessageToTso") ?: "") + } + ) + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("GET http://.*/zosmf/tsoApp/tso/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("receiveMessagesFromTso") ?: "") + } + ) + + val servletKey = "DLIS-121-aabcaaat" + val response = sendTso.sendDataToTSOCollect(servletKey, "TIME") + + Assertions.assertEquals(servletKey, response.tsoResponses[0].servletKey) + Assertions.assertTrue( + response.commandResponse?.contains( + "IKJ56650I TIME-06:43:59 PM. CPU-00:00:00 SERVICE-595 SESSION-00:05:00 SEPTEMBER 22,2022") == true + ) + + responseDispatcher.clearValidationList() + } +} diff --git a/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/StartTsoTest.kt b/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/StartTsoTest.kt new file mode 100644 index 0000000..ddc513b --- /dev/null +++ b/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/StartTsoTest.kt @@ -0,0 +1,77 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.zostso + +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import eu.ibagroup.r2z.zowe.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zostso.StartTso +import eu.ibagroup.r2z.zowe.client.sdk.zostso.input.StartTsoParams +import okhttp3.OkHttpClient +import org.junit.jupiter.api.* +import java.net.InetSocketAddress +import java.net.Proxy +import kotlin.concurrent.thread + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class StartTsoTest { + lateinit var mockServer: MockWebServer + lateinit var proxyClient: OkHttpClient + lateinit var responseDispatcher: MockResponseDispatcher + + @BeforeAll + fun createMockServer() { + mockServer = MockWebServer() + responseDispatcher = MockResponseDispatcher() + mockServer.dispatcher = responseDispatcher + mockServer.start() + val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(mockServer.hostName, mockServer.port)) + proxyClient = OkHttpClient.Builder().proxy(proxy).build() + } + + @AfterAll + fun stopMockServer() { + mockServer.shutdown() + } + + @Test + fun start() { + val connection = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val startTso = StartTso(connection, proxyClient) + + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("POST http://.*/zosmf/tsoApp/tso.*proc=DBSPROCB.*acct=IZUACCT.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("startTso") ?: "") + } + ) + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("GET http://.*/zosmf/tsoApp/tso/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("receiveMessagesFromTso") ?: "") + } + ) + + val startTsoParams = StartTsoParams( + characterSet = "697", + codePage = "1047", + columns = "160", + rows = "204", + logonProcedure = "DBSPROCB", + regionSize = "50000" + ) + val response = startTso.start("IZUACCT", startTsoParams) + + Assertions.assertTrue(response.success) + Assertions.assertEquals(null, response.failureResponse) + Assertions.assertEquals("DLIS-121-aabcaaat", response.tsoResponse?.servletKey) + + responseDispatcher.clearValidationList() + } + +} diff --git a/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/StopTsoTest.kt b/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/StopTsoTest.kt new file mode 100644 index 0000000..e35c8b1 --- /dev/null +++ b/src/test/kotlin/eu/ibagroup/r2z/zowe/zostso/StopTsoTest.kt @@ -0,0 +1,65 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.zostso + +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import eu.ibagroup.r2z.zowe.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zostso.StopTso +import eu.ibagroup.r2z.zowe.client.sdk.zostso.input.StopTsoParams +import okhttp3.OkHttpClient +import org.junit.jupiter.api.* +import java.net.InetSocketAddress +import java.net.Proxy +import kotlin.concurrent.thread + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class StopTsoTest { + lateinit var mockServer: MockWebServer + lateinit var proxyClient: OkHttpClient + lateinit var responseDispatcher: MockResponseDispatcher + + @BeforeAll + fun createMockServer() { + mockServer = MockWebServer() + responseDispatcher = MockResponseDispatcher() + mockServer.dispatcher = responseDispatcher + mockServer.start() + val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(mockServer.hostName, mockServer.port)) + proxyClient = OkHttpClient.Builder().proxy(proxy).build() + } + + @AfterAll + fun stopMockServer() { + mockServer.shutdown() + } + + @Test + fun stopTsoTest() { + val connection = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val stopTso = StopTso(connection, proxyClient) + + val stopTsoParams = StopTsoParams( + servletKey = "DLIS-121-aabcaaat" + ) + + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("DELETE http://.*/zosmf/tsoApp/tso/DLIS-121-aabcaaat HTTP/.*")) == true + }, + { + MockResponse().setBody(responseDispatcher.readMockJson("stopTso") ?: "") + } + ) + + val stopCommonResponse = stopTso.stopCommon(stopTsoParams) + val stopResponse = stopTso.stop("DLIS-121-aabcaaat") + + Assertions.assertEquals("DLIS-121-aabcaaat", stopResponse.servletKey) + Assertions.assertEquals("DLIS-121-aabcaaat", stopCommonResponse.servletKey) + + responseDispatcher.clearValidationList() + } + +} diff --git a/src/test/kotlin/eu/ibagroup/r2z/zowe/zosuss/ZosUssCopyTest.kt b/src/test/kotlin/eu/ibagroup/r2z/zowe/zosuss/ZosUssCopyTest.kt new file mode 100644 index 0000000..7e45279 --- /dev/null +++ b/src/test/kotlin/eu/ibagroup/r2z/zowe/zosuss/ZosUssCopyTest.kt @@ -0,0 +1,86 @@ +// Copyright © 2020 IBA Group, a.s. All rights reserved. Use of this source code is governed by Eclipse Public License – v 2.0 that can be found at: https://www.eclipse.org/legal/epl-2.0/ + +package eu.ibagroup.r2z.zowe.zosfiles + +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import eu.ibagroup.r2z.zowe.* +import eu.ibagroup.r2z.zowe.client.sdk.core.ZOSConnection +import eu.ibagroup.r2z.zowe.client.sdk.zosuss.ZosUssCopy +import okhttp3.OkHttpClient +import org.junit.jupiter.api.* +import java.net.InetSocketAddress +import java.net.Proxy + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ZosUssCopyTest { + lateinit var mockServer: MockWebServer + lateinit var proxyClient: OkHttpClient + lateinit var responseDispatcher: MockResponseDispatcher + + @BeforeAll + fun createMockServer() { + mockServer = MockWebServer() + responseDispatcher = MockResponseDispatcher() + mockServer.dispatcher = responseDispatcher + mockServer.start() + val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(mockServer.hostName, mockServer.port)) + proxyClient = OkHttpClient.Builder().proxy(proxy).build() + } + + @AfterAll + fun stopMockServer() { + mockServer.shutdown() + } + + @Test + fun testCopyFile() { + val conn = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val zosUssCopy = ZosUssCopy(conn, proxyClient) + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("PUT http://.*/zosmf/restfiles/fs/u/IJMP/destFile HTTP/.*")) == true + }, { + MockResponse().setResponseCode(204) + } + ) + val response = zosUssCopy.copy("/u/IJMP/fileToCopy", "/u/IJMP/destFile", replace = true) + Assertions.assertEquals(204, response.code()) + + responseDispatcher.clearValidationList() + } + + @Test + fun testCopyFileToDS() { + val conn = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val zosUssCopy = ZosUssCopy(conn, proxyClient) + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("PUT http://.*/zosmf/restfiles/ds/IJMP.TEST.DATA HTTP/.*")) == true + }, { + MockResponse().setResponseCode(204) + } + ) + val response = zosUssCopy.copyToDS("/u/IJMP/fileToCopy", "IJMP.TEST.DATA", replace = true) + Assertions.assertEquals(204, response.code()) + + responseDispatcher.clearValidationList() + } + + @Test + fun testCopyFileToMember() { + val conn = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val zosUssCopy = ZosUssCopy(conn, proxyClient) + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("PUT http://.*/zosmf/restfiles/ds/IJMP.TEST.DATA\\(TESTMEM\\) HTTP/.*")) == true + }, { + MockResponse().setResponseCode(204) + } + ) + val response = zosUssCopy.copyToMember("/u/IJMP/fileToCopy", "IJMP.TEST.DATA", "TESTMEM", replace = true) + Assertions.assertEquals(204, response.code()) + + responseDispatcher.clearValidationList() + } +} diff --git a/src/test/kotlin/eu/ibagroup/r2z/zowe/zosuss/ZosUssFileTest.kt b/src/test/kotlin/eu/ibagroup/r2z/zowe/zosuss/ZosUssFileTest.kt index a4c8192..76c30b6 100644 --- a/src/test/kotlin/eu/ibagroup/r2z/zowe/zosuss/ZosUssFileTest.kt +++ b/src/test/kotlin/eu/ibagroup/r2z/zowe/zosuss/ZosUssFileTest.kt @@ -115,5 +115,23 @@ class ZosUssFileTest { responseDispatcher.clearValidationList() } + + @Test + fun writeToFileBin() { + val connection = ZOSConnection(TEST_HOST, TEST_PORT, TEST_USER, TEST_PASSWORD, "http") + val zosUssFile = ZosUssFile(connection, proxyClient) + val text = "Hello There!" + + responseDispatcher.injectEndpoint( + { + it?.requestLine?.matches(Regex("PUT http://.*/zosmf/restfiles/fs/u/IJMP/file HTTP/.*")) == true + }, + { MockResponse().setResponseCode(201) } + ) + val response = zosUssFile.writeToFileBin("/u/IJMP/file", text.toByteArray()) + Assertions.assertEquals(201, response.code()) + + responseDispatcher.clearValidationList() + } } diff --git a/src/test/resources/mock/infoResponse.json b/src/test/resources/mock/infoResponse.json new file mode 100644 index 0000000..3d383cb --- /dev/null +++ b/src/test/resources/mock/infoResponse.json @@ -0,0 +1,26 @@ +{ + "zos_version": "04.26.00", + "zosmf_port": "10443", + "zosmf_version": "26", + "zosmf_hostname": "S0W1.DAL-EBIS.IHOST.COM", + "plugins": [ + { + "pluginVersion": "HSMA230;PH15438P;2019-09-16T04:53:43", + "pluginDefaultName": "z/OS Operator Consoles", + "pluginStatus": "ACTIVE" + }, + { + "pluginVersion": "HSMA234;PH09032P;2019-03-04T16:37:21", + "pluginDefaultName": "Software Deployment", + "pluginStatus": "ACTIVE" + }, + { + "pluginVersion": "HSMA230;PI96931P;2018-05-22T06:55:26", + "pluginDefaultName": "Variables", + "pluginStatus": "ACTIVE" + } + ], + "zosmf_saf_realm": "SAFRealm", + "zosmf_full_version": "26.0", + "api_version": "1" +} \ No newline at end of file diff --git a/src/test/resources/mock/infoResponsePluginsError.json b/src/test/resources/mock/infoResponsePluginsError.json new file mode 100644 index 0000000..de5af88 --- /dev/null +++ b/src/test/resources/mock/infoResponsePluginsError.json @@ -0,0 +1,13 @@ +{ + "zos_version": "04.28.00", + "zosmf_port": "1443", + "zosmf_version": "28", + "zosmf_hostname": "stuff", + "plugins": { + "msgId": "IZUG612E", + "msgText": "IZUG612E" + }, + "zosmf_saf_realm": "SAFRealm", + "zosmf_full_version": "28.0", + "api_version": "1" +} \ No newline at end of file diff --git a/src/test/resources/mock/issueCommand.json b/src/test/resources/mock/issueCommand.json new file mode 100644 index 0000000..3a9b23c --- /dev/null +++ b/src/test/resources/mock/issueCommand.json @@ -0,0 +1 @@ +{"cmd-response-key":"C8529621","cmd-response-url":"https:\/\/172.20.2.121:10443\/zosmf\/restconsoles\/consoles\/ibmusecn\/solmsgs\/C8529621","consoleRoutcde":"","consoleMscope":"","cmd-response-uri":"\/zosmf\/restconsoles\/consoles\/ibmusecn\/solmsgs\/C8529621","cmd-response":" D A,PEGASUS\r\n CNZ4106I 17.06.33 DISPLAY ACTIVITY 128\r JOBS M\/S TS USERS SYSAS INITS ACTIVE\/MAX VTAM OAS\r 00017 00034 00003 00034 00032 00001\/00040 00046\r PEGASUS NOT FOUND","consoleAuth":"","sol-key-detected":true} \ No newline at end of file diff --git a/src/test/resources/mock/receiveMessagesFromTso.json b/src/test/resources/mock/receiveMessagesFromTso.json new file mode 100644 index 0000000..bad8fd7 --- /dev/null +++ b/src/test/resources/mock/receiveMessagesFromTso.json @@ -0,0 +1,74 @@ +{ + "servletKey": "DLIS-121-aabcaaat", + "ver": "0100", + "tsoData": [ + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* USERID PASSWORD COMMENT *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* ---------------- ------------ -------------- *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* IBMUSER - SYS1/IBMUSER FULL AUTHORITY *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* ADCDMST - ADCDMST FULL AUTHORITY *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* ADCDA THRU ADCDZ - TEST LIMITED AUTHORITY(NO OMVS)*" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* OPEN1 THRU OPEN3 - SYS1 UID(0) (NO TSO) *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "*****************************************************************" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": " " + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "READY " + } + }, + { + "TSO PROMPT": { + "VERSION": "0100", + "HIDDEN": "FALSE" + } + } + ], + "reused": false, + "timeout": false +} \ No newline at end of file diff --git a/src/test/resources/mock/sendMessageToTso.json b/src/test/resources/mock/sendMessageToTso.json new file mode 100644 index 0000000..3ba3603 --- /dev/null +++ b/src/test/resources/mock/sendMessageToTso.json @@ -0,0 +1,26 @@ +{ + "servletKey": "DLIS-121-aabcaaat", + "ver": "0100", + "tsoData": [ + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "IKJ56650I TIME-06:43:59 PM. CPU-00:00:00 SERVICE-595 SESSION-00:05:00 SEPTEMBER 22,2022" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "READY " + } + }, + { + "TSO PROMPT": { + "VERSION": "0100", + "HIDDEN": "FALSE" + } + } + ], + "reused": false, + "timeout": false +} \ No newline at end of file diff --git a/src/test/resources/mock/startTso.json b/src/test/resources/mock/startTso.json new file mode 100644 index 0000000..fddd077 --- /dev/null +++ b/src/test/resources/mock/startTso.json @@ -0,0 +1,76 @@ +{ + "servletKey": "DLIS-121-aabcaaat", + "queueID": "8192030", + "sessionID": "0x79", + "ver": "0100", + "tsoData": [ + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "IKJ56455I DLIS LOGON IN PROGRESS AT 17:31:11 ON SEPTEMBER 22, 2022" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "IKJ56951I NO BROADCAST MESSAGES" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "*****************************************************************" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* APPLICATION DEVELOPER'S CONTROLLED DISTRIBUTION (ADCD) *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* ADCD.Z23D.CLIST(ISPFCL) PRODUCES THIS MESSAGE *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* ADCD.* DATASETS CONTAIN SYSTEM CUSTOMIZATION *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* SMP/E DATASETS CAN BE LOCATED FROM 3.4 WITH DSNAME **.CSI *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* HTTP://DTSC.DFW.IBM.COM/ADCD.HTML CONTAINS DOCUMENTATION *" + } + }, + { + "TSO MESSAGE": { + "VERSION": "0100", + "DATA": "* *" + } + } + ], + "reused": false, + "timeout": false +} \ No newline at end of file diff --git a/src/test/resources/mock/stopTso.json b/src/test/resources/mock/stopTso.json new file mode 100644 index 0000000..af69e90 --- /dev/null +++ b/src/test/resources/mock/stopTso.json @@ -0,0 +1 @@ +{"servletKey":"DLIS-121-aabcaaat","ver":"0100","reused":false,"timeout":false} \ No newline at end of file