ENT-1456 Adding try-catch to jira ticket processing (#667)

* Adding try-catch to jira ticket processing

* Addressing review comments

* Addressing review comments

* Refactoring getTransitionId method.

* Addressing review comments

* Refactoring to use requireNotNull

* Refactoring to use more requireNotNull

* Fixing missing map population
This commit is contained in:
Michal Kit 2018-04-13 07:46:16 +01:00 committed by GitHub
parent 179e479aa0
commit a320c8d49f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 100 additions and 105 deletions

View File

@ -31,8 +31,9 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
// Get matching CSR
validate(request)
val csr = retrieveCsr(request.certificateSerialNumber, request.csrRequestId, request.legalName)
csr ?: throw IllegalArgumentException("No CSR matching the given criteria was found")
val csr = requireNotNull(retrieveCsr(request.certificateSerialNumber, request.csrRequestId, request.legalName)) {
"No CSR matching the given criteria was found"
}
// Check if there is an entry for the given certificate serial number
val revocation = uniqueEntityWhere<CertificateRevocationRequestEntity> { builder, path ->
val serialNumberEqual = builder.equal(path.get<BigInteger>(CertificateRevocationRequestEntity::certificateSerialNumber.name), request.certificateSerialNumber)
@ -168,8 +169,9 @@ class PersistentCertificateRevocationRequestStorage(private val database: CordaP
// Even though, we have an assumption that there is always a single instance of the doorman service running,
// the SERIALIZABLE isolation level is used here just to ensure data consistency between the updates.
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
val request = getRevocationRequestEntity(requestId, RequestStatus.NEW)
request ?: throw IllegalArgumentException("Error when creating request ticket with id: $requestId. Request does not exist or its status is not NEW.")
val request = requireNotNull(getRevocationRequestEntity(requestId, RequestStatus.NEW)) {
"Error when creating request ticket with id: $requestId. Request does not exist or its status is not NEW."
}
val update = request.copy(
modifiedAt = Instant.now(),
status = RequestStatus.TICKET_CREATED)

View File

@ -39,12 +39,11 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
override fun putCertificatePath(requestId: String, certPath: CertPath, signedBy: String) {
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
val request = uniqueEntityWhere<CertificateSigningRequestEntity> { builder, path ->
val request = requireNotNull(uniqueEntityWhere<CertificateSigningRequestEntity> { builder, path ->
val requestIdEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::requestId.name), requestId)
val statusEq = builder.equal(path.get<String>(CertificateSigningRequestEntity::status.name), RequestStatus.APPROVED)
builder.and(requestIdEq, statusEq)
}
request ?: throw IllegalArgumentException("Cannot retrieve 'APPROVED' certificate signing request for request id: $requestId")
}) { "Cannot retrieve 'APPROVED' certificate signing request for request id: $requestId" }
val certificateSigningRequest = request.copy(
modifiedBy = signedBy,
modifiedAt = Instant.now(),
@ -97,9 +96,8 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
}
override fun markRequestTicketCreated(requestId: String) {
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
val request = findRequest(requestId, RequestStatus.NEW)
request ?: throw IllegalArgumentException("Error when creating request ticket with id: $requestId. Request does not exist or its status is not NEW.")
database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
val request = requireNotNull(findRequest(requestId, RequestStatus.NEW)) { "Error when creating request ticket with id: $requestId. Request does not exist or its status is not NEW." }
val update = request.copy(
modifiedAt = Instant.now(),
status = RequestStatus.TICKET_CREATED)
@ -108,7 +106,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
}
override fun approveRequest(requestId: String, approvedBy: String) {
return database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
findRequest(requestId, RequestStatus.TICKET_CREATED)?.let {
val update = it.copy(
modifiedBy = approvedBy,
@ -121,8 +119,7 @@ class PersistentCertificateSigningRequestStorage(private val database: CordaPers
override fun rejectRequest(requestId: String, rejectedBy: String, rejectReason: String?) {
database.transaction(TransactionIsolationLevel.SERIALIZABLE) {
val request = findRequest(requestId)
request ?: throw IllegalArgumentException("Error when rejecting request with id: $requestId. Request does not exist.")
val request = requireNotNull(findRequest(requestId)) { "Error when rejecting request with id: $requestId. Request does not exist." }
val update = request.copy(
modifiedBy = rejectedBy,
modifiedAt = Instant.now(),

View File

@ -44,14 +44,8 @@ class CrrJiraClient(restClient: JiraRestClient, projectCode: String) : JiraClien
.fail { CsrJiraClient.logger.error("Error processing request '${createdIssue.key}' : Exception when uploading attachment to JIRA.", it) }.claim()
}
fun updateDoneCertificateRevocationRequests(doneRequests: List<String>) {
doneRequests.forEach { id ->
val issue = getIssueById(id)
issue ?: throw IllegalStateException("Missing the JIRA ticket for the request ID: $id")
if (doneTransitionId == -1) {
doneTransitionId = restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == "Done" }.id
}
restClient.issueClient.transition(issue, TransitionInput(doneTransitionId)).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
}
fun updateDoneCertificateRevocationRequest(requestId: String) {
val issue = requireNotNull(getIssueById(requestId)) { "Missing the JIRA ticket for the request ID: $requestId" }
restClient.issueClient.transition(issue, TransitionInput(getTransitionId(DONE_TRANSITION_KEY, issue))).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
}
}

View File

@ -75,19 +75,12 @@ class CsrJiraClient(restClient: JiraRestClient, projectCode: String) : JiraClien
restClient.issueClient.createIssue(issue.build()).fail { logger.error("Exception when creating JIRA issue.", it) }.claim()
}
fun updateDoneCertificateSigningRequests(signedRequests: Map<String, CertPath>) {
fun updateDoneCertificateSigningRequest(requestId: String, certPath: CertPath) {
// Retrieving certificates for signed CSRs to attach to the jira tasks.
signedRequests.forEach { (id, certPath) ->
val certificate = certPath.certificates.first()
val issue = getIssueById(id)
if (issue != null) {
if (doneTransitionId == -1) {
doneTransitionId = restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == "Done" }.id
}
restClient.issueClient.transition(issue, TransitionInput(doneTransitionId)).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
restClient.issueClient.addAttachment(issue.attachmentsUri, certificate.encoded.inputStream(), "${X509Utilities.CORDA_CLIENT_CA}.cer")
.fail { logger.error("Error processing request '${issue.key}' : Exception when uploading attachment to JIRA.", it) }.claim()
}
}
val certificate = certPath.certificates.first()
val issue = requireNotNull(getIssueById(requestId)) { "Cannot find the JIRA ticket `request ID` = $requestId" }
restClient.issueClient.transition(issue, TransitionInput(getTransitionId(DONE_TRANSITION_KEY, issue))).fail { logger.error("Exception when transiting JIRA status.", it) }.claim()
restClient.issueClient.addAttachment(issue.attachmentsUri, certificate.encoded.inputStream(), "${X509Utilities.CORDA_CLIENT_CA}.cer")
.fail { logger.error("Error processing request '${issue.key}' : Exception when uploading attachment to JIRA.", it) }.claim()
}
}

View File

@ -18,25 +18,29 @@ import com.atlassian.jira.rest.client.api.domain.Issue
import com.atlassian.jira.rest.client.api.domain.IssueType
import com.atlassian.jira.rest.client.api.domain.input.TransitionInput
import net.corda.core.utilities.contextLogger
import org.slf4j.Logger
abstract class JiraClient(protected val restClient: JiraRestClient, protected val projectCode: String) {
companion object {
val logger = contextLogger()
const val DONE_TRANSITION_KEY = "Done"
const val START_TRANSITION_KEY = "Start Progress"
const val STOP_TRANSITION_KEY = "Stop Progress"
}
// The JIRA project must have a Request ID and reject reason field, and the Task issue type.
protected val requestIdField: Field = restClient.metadataClient.fields.claim().find { it.name == "Request ID" } ?: throw IllegalArgumentException("Request ID field not found in JIRA '$projectCode'")
protected val taskIssueType: IssueType = restClient.metadataClient.issueTypes.claim().find { it.name == "Task" } ?: throw IllegalArgumentException("Task issue type field not found in JIRA '$projectCode'")
protected val rejectReasonField: Field = restClient.metadataClient.fields.claim().find { it.name == "Reject Reason" } ?: throw IllegalArgumentException("Reject Reason field not found in JIRA '$projectCode'")
protected val requestIdField: Field = requireNotNull(restClient.metadataClient.fields.claim().find { it.name == "Request ID" }) { "Request ID field not found in JIRA '$projectCode'" }
protected val taskIssueType: IssueType = requireNotNull(restClient.metadataClient.issueTypes.claim().find { it.name == "Task" }) { "Task issue type field not found in JIRA '$projectCode'" }
protected val rejectReasonField: Field = requireNotNull(restClient.metadataClient.fields.claim().find { it.name == "Reject Reason" }) { "Reject Reason field not found in JIRA '$projectCode'" }
protected var doneTransitionId: Int = -1
private var canceledTransitionId: Int = -1
private var startProgressTransitionId: Int = -1
private val transitions = mutableMapOf<String, Int>()
fun getApprovedRequests(): List<ApprovedRequest> {
val issues = restClient.searchClient.searchJql("project = $projectCode AND status = Approved").claim().issues
return issues.mapNotNull { issue ->
val requestId = issue.getField(requestIdField.id)?.value?.toString() ?: throw IllegalArgumentException("Error processing request '${issue.key}' : RequestId cannot be null.")
val requestId = requireNotNull(issue.getField(requestIdField.id)?.value?.toString()) { "Error processing request '${issue.key}' : RequestId cannot be null." }
// Issue retrieved via search doesn't contain change logs.
val fullIssue = restClient.issueClient.getIssue(issue.key, listOf(IssueRestClient.Expandos.CHANGELOG)).claim()
val approvedBy = fullIssue.changelog?.last { it.items.any { it.field == "status" && it.toString == "Approved" } }
@ -47,7 +51,7 @@ abstract class JiraClient(protected val restClient: JiraRestClient, protected va
fun getRejectedRequests(): List<RejectedRequest> {
val issues = restClient.searchClient.searchJql("project = $projectCode AND status = Rejected").claim().issues
return issues.mapNotNull { issue ->
val requestId = issue.getField(requestIdField.id)?.value?.toString() ?: throw IllegalArgumentException("Error processing request '${issue.key}' : RequestId cannot be null.")
val requestId = requireNotNull(issue.getField(requestIdField.id)?.value?.toString()) { "Error processing request '${issue.key}' : RequestId cannot be null." }
val rejectedReason = issue.getField(rejectReasonField.id)?.value?.toString()
// Issue retrieved via search doesn't contain comments.
val fullIssue = restClient.issueClient.getIssue(issue.key, listOf(IssueRestClient.Expandos.CHANGELOG)).claim()
@ -56,29 +60,38 @@ abstract class JiraClient(protected val restClient: JiraRestClient, protected va
}
}
fun updateRejectedRequests(rejectedRequests: List<String>) {
rejectedRequests.mapNotNull { getIssueById(it) }
.forEach { issue ->
// Move status to in progress.
if (startProgressTransitionId == -1) {
startProgressTransitionId = restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == "Start Progress" }.id
}
restClient.issueClient.transition(issue, TransitionInput(startProgressTransitionId)).fail { logger.error("Error processing request '${issue.key}' : Exception when transiting JIRA status.", it) }.claim()
// Move status to cancelled.
if (canceledTransitionId == -1) {
canceledTransitionId = restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == "Stop Progress" }.id
}
restClient.issueClient.transition(issue, TransitionInput(canceledTransitionId)).fail { logger.error("Error processing request '${issue.key}' : Exception when transiting JIRA status.", it) }.claim()
restClient.issueClient.addComment(issue.commentsUri, Comment.valueOf("Request cancelled by doorman.")).claim()
}
fun updateRejectedRequest(requestId: String) {
val issue = requireNotNull(getIssueById(requestId)) { "Issue with the `request ID` = $requestId does not exist." }
// Move status to in progress.
restClient.issueClient.transition(issue, TransitionInput(getTransitionId(START_TRANSITION_KEY, issue))).fail { logger.error("Error processing request '${issue.key}' : Exception when transiting JIRA status.", it) }.claim()
// Move status to stopped.
restClient.issueClient.transition(issue, TransitionInput(getTransitionId(STOP_TRANSITION_KEY, issue))).fail { logger.error("Error processing request '${issue.key}' : Exception when transiting JIRA status.", it) }.claim()
restClient.issueClient.addComment(issue.commentsUri, Comment.valueOf("Request cancelled by doorman.")).claim()
}
protected fun getIssueById(requestId: String): Issue? {
// Jira only support ~ (contains) search for custom textfield.
return restClient.searchClient.searchJql("'Request ID' ~ $requestId").claim().issues.firstOrNull()
}
protected fun getTransitionId(transitionKey: String, issue: Issue): Int {
return transitions.computeIfAbsent(transitionKey, { key ->
restClient.issueClient.getTransitions(issue.transitionsUri).claim().single { it.name == key }.id
})
}
}
data class ApprovedRequest(val requestId: String, val approvedBy: String)
data class RejectedRequest(val requestId: String, val rejectedBy: String, val reason: String?)
inline fun <T : Any> Iterable<T>.forEachWithExceptionLogging(logger: Logger, action: (T) -> Unit) {
for (element in this) {
try {
action(element)
} catch (e: Exception) {
logger.error("Error while processing an element: $element", e)
}
}
}

View File

@ -19,7 +19,6 @@ import net.corda.core.internal.exists
import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.nodeapi.internal.crypto.X509Utilities
import org.slf4j.LoggerFactory
import java.nio.file.NoSuchFileException
import java.time.Instant
import kotlin.system.exitProcess
@ -71,7 +70,7 @@ private fun processKeyStore(config: NetworkManagementServerConfig): Pair<CertPat
private fun rootKeyGenMode(cmdLineOptions: DoormanCmdLineOptions, config: NetworkManagementServerConfig) {
generateRootKeyPair(
config.rootStorePath ?: throw IllegalArgumentException("The 'rootStorePath' parameter must be specified when generating keys!"),
requireNotNull(config.rootStorePath) { "The 'rootStorePath' parameter must be specified when generating keys!" },
config.rootKeystorePassword,
config.rootPrivateKeyPassword,
cmdLineOptions.trustStorePassword
@ -80,8 +79,8 @@ private fun rootKeyGenMode(cmdLineOptions: DoormanCmdLineOptions, config: Networ
private fun caKeyGenMode(config: NetworkManagementServerConfig) {
generateSigningKeyPairs(
config.keystorePath ?: throw IllegalArgumentException("The 'keystorePath' parameter must be specified when generating keys!"),
config.rootStorePath ?: throw IllegalArgumentException("The 'rootStorePath' parameter must be specified when generating keys!"),
requireNotNull(config.keystorePath) { "The 'keystorePath' parameter must be specified when generating keys!" },
requireNotNull(config.rootStorePath) { "The 'rootStorePath' parameter must be specified when generating keys!" },
config.rootKeystorePassword,
config.rootPrivateKeyPassword,
config.keystorePassword,

View File

@ -53,7 +53,7 @@ class DefaultCsrHandler(private val storage: CertificateSigningRequestStorage,
return when (response?.status) {
RequestStatus.NEW, RequestStatus.APPROVED, RequestStatus.TICKET_CREATED, null -> CertificateResponse.NotReady
RequestStatus.REJECTED -> CertificateResponse.Unauthorised(response.remark ?: "Unknown reason")
RequestStatus.DONE -> CertificateResponse.Ready(response.certData?.certPath ?: throw IllegalArgumentException("Certificate should not be null."))
RequestStatus.DONE -> CertificateResponse.Ready(requireNotNull(response.certData?.certPath) { "Certificate should not be null." })
}
}

View File

@ -16,6 +16,7 @@ import com.r3.corda.networkmanage.common.persistence.RequestStatus
import com.r3.corda.networkmanage.doorman.ApprovedRequest
import com.r3.corda.networkmanage.doorman.CrrJiraClient
import com.r3.corda.networkmanage.doorman.RejectedRequest
import com.r3.corda.networkmanage.doorman.forEachWithExceptionLogging
import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.network.CertificateRevocationRequest
@ -50,24 +51,21 @@ class JiraCrrHandler(private val jiraClient: CrrJiraClient,
private fun updateRequestStatuses(): Pair<List<ApprovedRequest>, List<RejectedRequest>> {
// Update local request statuses.
val approvedRequest = jiraClient.getApprovedRequests()
approvedRequest.forEach { (id, approvedBy) -> crrStorage.approveRevocationRequest(id, approvedBy) }
approvedRequest.forEachWithExceptionLogging(logger) { (id, approvedBy) -> crrStorage.approveRevocationRequest(id, approvedBy) }
val rejectedRequest = jiraClient.getRejectedRequests()
rejectedRequest.forEach { (id, rejectedBy, reason) -> crrStorage.rejectRevocationRequest(id, rejectedBy, reason) }
rejectedRequest.forEachWithExceptionLogging(logger) { (id, rejectedBy, reason) -> crrStorage.rejectRevocationRequest(id, rejectedBy, reason) }
return Pair(approvedRequest, rejectedRequest)
}
private fun updateJiraTickets(approvedRequest: List<ApprovedRequest>, rejectedRequest: List<RejectedRequest>) {
// Reconfirm request status and update jira status
val doneRequests = approvedRequest.mapNotNull { crrStorage.getRevocationRequest(it.requestId) }
approvedRequest.mapNotNull { crrStorage.getRevocationRequest(it.requestId) }
.filter { it.status == RequestStatus.DONE }
.map { it.requestId }
.forEachWithExceptionLogging(logger) { jiraClient.updateDoneCertificateRevocationRequest(it.requestId) }
jiraClient.updateDoneCertificateRevocationRequests(doneRequests)
val rejectedRequestIDs = rejectedRequest.mapNotNull { crrStorage.getRevocationRequest(it.requestId) }
rejectedRequest.mapNotNull { crrStorage.getRevocationRequest(it.requestId) }
.filter { it.status == RequestStatus.REJECTED }
.map { it.requestId }
jiraClient.updateRejectedRequests(rejectedRequestIDs)
.forEachWithExceptionLogging(logger) { jiraClient.updateRejectedRequest(it.requestId) }
}
/**
@ -77,12 +75,8 @@ class JiraCrrHandler(private val jiraClient: CrrJiraClient,
* they might be left in the [RequestStatus.NEW] state if Jira is down.
*/
private fun createTickets() {
crrStorage.getRevocationRequests(RequestStatus.NEW).forEach {
try {
createTicket(it)
} catch (e: Exception) {
logger.warn("There were errors while creating Jira tickets for request '${it.requestId}'", e)
}
crrStorage.getRevocationRequests(RequestStatus.NEW).forEachWithExceptionLogging(logger) {
createTicket(it)
}
}

View File

@ -17,12 +17,13 @@ import com.r3.corda.networkmanage.common.persistence.RequestStatus
import com.r3.corda.networkmanage.doorman.ApprovedRequest
import com.r3.corda.networkmanage.doorman.CsrJiraClient
import com.r3.corda.networkmanage.doorman.RejectedRequest
import com.r3.corda.networkmanage.doorman.forEachWithExceptionLogging
import net.corda.core.utilities.contextLogger
import org.bouncycastle.pkcs.PKCS10CertificationRequest
class JiraCsrHandler(private val jiraClient: CsrJiraClient, private val storage: CertificateSigningRequestStorage, private val delegate: CsrHandler) : CsrHandler by delegate {
private companion object {
val log = contextLogger()
val logger = contextLogger()
}
override fun saveRequest(rawRequest: PKCS10CertificationRequest): String {
@ -34,7 +35,7 @@ class JiraCsrHandler(private val jiraClient: CsrJiraClient, private val storage:
storage.markRequestTicketCreated(requestId)
}
} catch (e: Exception) {
log.warn("There was an error while creating Jira tickets", e)
logger.warn("There was an error while creating Jira tickets", e)
} finally {
return requestId
}
@ -50,24 +51,28 @@ class JiraCsrHandler(private val jiraClient: CsrJiraClient, private val storage:
private fun updateRequestStatus(): Pair<List<ApprovedRequest>, List<RejectedRequest>> {
// Update local request statuses.
val approvedRequest = jiraClient.getApprovedRequests()
approvedRequest.forEach { (id, approvedBy) -> storage.approveRequest(id, approvedBy) }
approvedRequest.forEachWithExceptionLogging(logger) { (id, approvedBy) ->
storage.approveRequest(id, approvedBy)
}
val rejectedRequest = jiraClient.getRejectedRequests()
rejectedRequest.forEach { (id, rejectedBy, reason) -> storage.rejectRequest(id, rejectedBy, reason) }
rejectedRequest.forEachWithExceptionLogging(logger) { (id, rejectedBy, reason) ->
storage.rejectRequest(id, rejectedBy, reason)
}
return Pair(approvedRequest, rejectedRequest)
}
private fun updateJiraTickets(approvedRequest: List<ApprovedRequest>, rejectedRequest: List<RejectedRequest>) {
// Reconfirm request status and update jira status
val signedRequests = approvedRequest.mapNotNull { storage.getRequest(it.requestId) }
approvedRequest.mapNotNull { storage.getRequest(it.requestId) }
.filter { it.status == RequestStatus.DONE && it.certData != null }
.associateBy { it.requestId }
.mapValues { it.value.certData!!.certPath }
jiraClient.updateDoneCertificateSigningRequests(signedRequests)
val rejectedRequestIDs = rejectedRequest.mapNotNull { storage.getRequest(it.requestId) }
.forEachWithExceptionLogging(logger) {
jiraClient.updateDoneCertificateSigningRequest(it.requestId, it.certData!!.certPath)
}
rejectedRequest.mapNotNull { storage.getRequest(it.requestId) }
.filter { it.status == RequestStatus.REJECTED }
.map { it.requestId }
jiraClient.updateRejectedRequests(rejectedRequestIDs)
.forEachWithExceptionLogging(logger) {
jiraClient.updateRejectedRequest(it.requestId)
}
}
/**
@ -77,12 +82,8 @@ class JiraCsrHandler(private val jiraClient: CsrJiraClient, private val storage:
* they might be left in the [RequestStatus.NEW] state if Jira is down.
*/
private fun createTickets() {
storage.getRequests(RequestStatus.NEW).forEach {
try {
createTicket(it)
} catch (e: Exception) {
log.warn("There were errors while creating Jira tickets for request '${it.requestId}'", e)
}
storage.getRequests(RequestStatus.NEW).forEachWithExceptionLogging(logger) {
createTicket(it)
}
}

View File

@ -113,7 +113,7 @@ class NetworkMapWebService(private val nodeInfoStorage: NodeInfoStorage,
return try {
val signedParametersHash = input.readObject<SignedData<SecureHash>>()
val hash = signedParametersHash.verified()
networkMapStorage.getSignedNetworkParameters(hash) ?: throw IllegalArgumentException("No network parameters with hash $hash")
requireNotNull(networkMapStorage.getSignedNetworkParameters(hash)) { "No network parameters with hash $hash" }
logger.debug { "Received ack-parameters with $hash from ${signedParametersHash.sig.by}" }
nodeInfoStorage.ackNodeInfoParametersUpdate(signedParametersHash.sig.by, hash)
ok()

View File

@ -35,7 +35,7 @@ class ConsoleInputReader : InputReader {
String(console.readPassword(format))
} else {
print(format)
kotlin.io.readLine() ?: throw IllegalArgumentException("Password required")
requireNotNull(kotlin.io.readLine()) { "Password required" }
}
}

View File

@ -50,17 +50,19 @@ class CsrJiraClientTest {
@Test
fun updateSignedRequests() {
val requests = jiraClient.getApprovedRequests()
val selfSignedCaCertPath = X509Utilities.buildCertPath(X509Utilities.createSelfSignedCACertificate(
X500Principal("O=test,L=london,C=GB"),
Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)))
jiraClient.updateDoneCertificateSigningRequests(requests.associateBy({ it.requestId }, { selfSignedCaCertPath }))
jiraClient.getApprovedRequests().forEach {
jiraClient.updateDoneCertificateSigningRequest(it.requestId, selfSignedCaCertPath)
}
}
@Test
fun updateRejectedRequests() {
val requests = jiraClient.getRejectedRequests()
jiraClient.updateRejectedRequests(requests.map { it.requestId })
jiraClient.getRejectedRequests().forEach {
jiraClient.updateRejectedRequest(it.requestId)
}
assert(jiraClient.getRejectedRequests().isEmpty())
}

View File

@ -144,8 +144,8 @@ class JiraCsrHandlerTest : TestBase() {
assertEquals(RequestStatus.REJECTED, requests[id2]!!.status)
// Verify jira client get the correct call.
verify(jiraClient).updateRejectedRequests(listOf(id2))
verify(jiraClient).updateDoneCertificateSigningRequests(emptyMap())
verify(jiraClient).updateRejectedRequest(id2)
verify(jiraClient, never()).updateDoneCertificateSigningRequest(any(), any())
// Sign request 1
val certPath = mock<CertPath>()
@ -156,6 +156,6 @@ class JiraCsrHandlerTest : TestBase() {
jiraCsrHandler.processRequests()
// Update signed request should be called.
verify(jiraClient).updateDoneCertificateSigningRequests(mapOf(id1 to certPath))
verify(jiraClient).updateDoneCertificateSigningRequest(id1, certPath)
}
}