From 97726bf29e23ff2b121a836e23366c9fe50c532b Mon Sep 17 00:00:00 2001 From: Drew Baugher <46505179+dbbaughe@users.noreply.github.com> Date: Mon, 3 Aug 2020 11:34:29 -0700 Subject: [PATCH] Adds more tests --- .../step/transition/AttemptTransitionStep.kt | 5 +- .../indexstatemanagement/TestHelpers.kt | 6 + .../action/TransitionActionIT.kt | 63 +++++++++++ .../model/XContentTests.kt | 21 ++++ .../step/AttemptTransitionStepTests.kt | 103 ++++++++++++++++++ 5 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/action/TransitionActionIT.kt create mode 100644 src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/step/AttemptTransitionStepTests.kt diff --git a/src/main/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/step/transition/AttemptTransitionStep.kt b/src/main/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/step/transition/AttemptTransitionStep.kt index a6b34077b..57f44ac40 100644 --- a/src/main/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/step/transition/AttemptTransitionStep.kt +++ b/src/main/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/step/transition/AttemptTransitionStep.kt @@ -90,9 +90,8 @@ class AttemptTransitionStep( ) return this } - - numDocs = statsResponse.primaries.docs?.count ?: 0 - indexSize = ByteSizeValue(statsResponse.primaries.docs?.totalSizeInBytes ?: 0) + numDocs = statsResponse.primaries.getDocs()?.count ?: 0 + indexSize = ByteSizeValue(statsResponse.primaries.getDocs()?.totalSizeInBytes ?: 0) } // Find the first transition that evaluates to true and get the state to transition to, otherwise return null if none are true diff --git a/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/TestHelpers.kt b/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/TestHelpers.kt index 72e5c4a92..d7a32a398 100644 --- a/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/TestHelpers.kt +++ b/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/TestHelpers.kt @@ -20,6 +20,7 @@ import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.ChangePo import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.Conditions import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.ErrorNotification import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.ManagedIndexConfig +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.ManagedIndexMetaData import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.Policy import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.State import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.StateFilter @@ -378,6 +379,11 @@ fun ManagedIndexConfig.toJsonString(): String { return this.toXContent(builder, ToXContent.EMPTY_PARAMS).string() } +fun ManagedIndexMetaData.toJsonString(): String { + val builder = XContentFactory.jsonBuilder().startObject() + return this.toXContent(builder, ToXContent.EMPTY_PARAMS).endObject().string() +} + fun SnapshotActionConfig.toJsonString(): String { val builder = XContentFactory.jsonBuilder() return this.toXContent(builder, ToXContent.EMPTY_PARAMS).string() diff --git a/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/action/TransitionActionIT.kt b/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/action/TransitionActionIT.kt new file mode 100644 index 000000000..e6a35d5b6 --- /dev/null +++ b/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/action/TransitionActionIT.kt @@ -0,0 +1,63 @@ +package com.amazon.opendistroforelasticsearch.indexstatemanagement.action + +import com.amazon.opendistroforelasticsearch.indexstatemanagement.IndexStateManagementRestTestCase +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.Conditions +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.Policy +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.State +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.Transition +import com.amazon.opendistroforelasticsearch.indexstatemanagement.randomErrorNotification +import com.amazon.opendistroforelasticsearch.indexstatemanagement.step.transition.AttemptTransitionStep +import com.amazon.opendistroforelasticsearch.indexstatemanagement.waitFor +import java.time.Instant +import java.time.temporal.ChronoUnit +import java.util.Locale + +class TransitionActionIT : IndexStateManagementRestTestCase() { + + private val testIndexName = javaClass.simpleName.toLowerCase(Locale.ROOT) + + fun `test doc count condition`() { + val indexName = "${testIndexName}_index_1" + val policyID = "${testIndexName}_testPolicyName_1" + val secondStateName = "second" + val states = listOf( + State("first", listOf(), listOf(Transition(secondStateName, Conditions(docCount = 5L)))), + State(secondStateName, listOf(), listOf()) + ) + + val policy = Policy( + id = policyID, + description = "$testIndexName description", + schemaVersion = 1L, + lastUpdatedTime = Instant.now().truncatedTo(ChronoUnit.MILLIS), + errorNotification = randomErrorNotification(), + defaultState = states[0].name, + states = states + ) + + createPolicy(policy, policyID) + createIndex(indexName, policyID) + + val managedIndexConfig = getExistingManagedIndexConfig(indexName) + + // Initializing the policy/metadata + updateManagedIndexConfigStartTime(managedIndexConfig) + + waitFor { assertEquals(policyID, getExplainManagedIndexMetaData(indexName).policyID) } + + // Evaluating transition conditions for first time + updateManagedIndexConfigStartTime(managedIndexConfig) + + // Should not have evaluated to true + waitFor { assertEquals(AttemptTransitionStep.getEvaluatingMessage(indexName), getExplainManagedIndexMetaData(indexName).info?.get("message")) } + + // Add 6 documents (>5) + insertSampleData(indexName, 6) + + // Evaluating transition conditions for second time + updateManagedIndexConfigStartTime(managedIndexConfig) + + // Should have evaluated to true + waitFor { assertEquals(AttemptTransitionStep.getSuccessMessage(indexName, secondStateName), getExplainManagedIndexMetaData(indexName).info?.get("message")) } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/model/XContentTests.kt b/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/model/XContentTests.kt index c426b6cfc..7919de0c3 100644 --- a/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/model/XContentTests.kt +++ b/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/model/XContentTests.kt @@ -187,6 +187,27 @@ class XContentTests : ESTestCase() { assertEquals("Round tripping ManagedIndexConfig doesn't work with id and version", configThree, parsedConfigThree) } + fun `test managed index metadata parsing`() { + val metadata = ManagedIndexMetaData( + index = randomAlphaOfLength(10), + indexUuid = randomAlphaOfLength(10), + policyID = randomAlphaOfLength(10), + policySeqNo = randomNonNegativeLong(), + policyPrimaryTerm = randomNonNegativeLong(), + policyCompleted = null, + rolledOver = null, + transitionTo = randomAlphaOfLength(10), + stateMetaData = null, + actionMetaData = null, + stepMetaData = null, + policyRetryInfo = null, + info = null + ) + val metadataString = metadata.toJsonString() + val parsedMetaData = ManagedIndexMetaData.parse(parser(metadataString)) + assertEquals("Round tripping ManagedIndexMetaData doesn't work", metadata, parsedMetaData) + } + fun `test change policy parsing`() { val changePolicy = randomChangePolicy() diff --git a/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/step/AttemptTransitionStepTests.kt b/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/step/AttemptTransitionStepTests.kt new file mode 100644 index 000000000..9bd2cacc3 --- /dev/null +++ b/src/test/kotlin/com/amazon/opendistroforelasticsearch/indexstatemanagement/step/AttemptTransitionStepTests.kt @@ -0,0 +1,103 @@ +package com.amazon.opendistroforelasticsearch.indexstatemanagement.step + +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.Conditions +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.ManagedIndexMetaData +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.Transition +import com.amazon.opendistroforelasticsearch.indexstatemanagement.model.action.TransitionsActionConfig +import com.amazon.opendistroforelasticsearch.indexstatemanagement.step.transition.AttemptTransitionStep +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.doAnswer +import com.nhaarman.mockitokotlin2.doReturn +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.whenever +import kotlinx.coroutines.runBlocking +import org.elasticsearch.action.ActionListener +import org.elasticsearch.action.admin.indices.stats.CommonStats +import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse +import org.elasticsearch.client.AdminClient +import org.elasticsearch.client.Client +import org.elasticsearch.client.IndicesAdminClient +import org.elasticsearch.cluster.ClusterState +import org.elasticsearch.cluster.metadata.IndexMetadata +import org.elasticsearch.cluster.metadata.Metadata +import org.elasticsearch.cluster.service.ClusterService +import org.elasticsearch.index.shard.DocsStats +import org.elasticsearch.rest.RestStatus +import org.elasticsearch.test.ESTestCase +import org.elasticsearch.transport.RemoteTransportException + +class AttemptTransitionStepTests : ESTestCase() { + + private val indexMetadata: IndexMetadata = mock() + private val metadata: Metadata = mock { on { index(any()) } doReturn indexMetadata } + private val clusterState: ClusterState = mock { on { metadata() } doReturn metadata } + private val clusterService: ClusterService = mock { on { state() } doReturn clusterState } + + private val docsStats: DocsStats = mock() + private val primaries: CommonStats = mock { on { getDocs() } doReturn docsStats } + private val statsResponse: IndicesStatsResponse = mock { on { primaries } doReturn primaries } + + fun `test stats response not OK`() { + whenever(indexMetadata.creationDate).doReturn(5L) + whenever(statsResponse.status).doReturn(RestStatus.INTERNAL_SERVER_ERROR) + whenever(statsResponse.shardFailures).doReturn(IndicesStatsResponse.EMPTY) + whenever(docsStats.count).doReturn(6L) + whenever(docsStats.totalSizeInBytes).doReturn(2) + val client = getClient(getAdminClient(getIndicesAdminClient(statsResponse, null))) + + runBlocking { + val config = TransitionsActionConfig(listOf(Transition("some_state", Conditions(docCount = 5L)))) + val managedIndexMetaData = ManagedIndexMetaData("test", "indexUuid", "policy_id", null, null, null, null, null, null, null, null, null, null) + val step = AttemptTransitionStep(clusterService, client, config, managedIndexMetaData) + step.execute() + val updatedManagedIndexMetaData = step.getUpdatedManagedIndexMetaData(managedIndexMetaData) + assertEquals("Step status is not FAILED", Step.StepStatus.FAILED, updatedManagedIndexMetaData.stepMetaData?.stepStatus) + assertEquals("Did not get correct failed message", AttemptTransitionStep.getFailedStatsMessage("test"), updatedManagedIndexMetaData.info!!["message"]) + } + } + + fun `test transitions fails on exception`() { + whenever(indexMetadata.creationDate).doReturn(5L) + val exception = IllegalArgumentException("example") + val client = getClient(getAdminClient(getIndicesAdminClient(null, exception))) + + runBlocking { + val config = TransitionsActionConfig(listOf(Transition("some_state", Conditions(docCount = 5L)))) + val managedIndexMetaData = ManagedIndexMetaData("test", "indexUuid", "policy_id", null, null, null, null, null, null, null, null, null, null) + val step = AttemptTransitionStep(clusterService, client, config, managedIndexMetaData) + step.execute() + val updatedManagedIndexMetaData = step.getUpdatedManagedIndexMetaData(managedIndexMetaData) + assertEquals("Step status is not FAILED", Step.StepStatus.FAILED, updatedManagedIndexMetaData.stepMetaData?.stepStatus) + assertEquals("Did not get cause from nested exception", "example", updatedManagedIndexMetaData.info!!["cause"]) + } + } + + fun `test transitions remote transport exception`() { + whenever(indexMetadata.creationDate).doReturn(5L) + val exception = RemoteTransportException("rte", IllegalArgumentException("nested")) + val client = getClient(getAdminClient(getIndicesAdminClient(null, exception))) + + runBlocking { + val config = TransitionsActionConfig(listOf(Transition("some_state", Conditions(docCount = 5L)))) + val managedIndexMetaData = ManagedIndexMetaData("test", "indexUuid", "policy_id", null, null, null, null, null, null, null, null, null, null) + val step = AttemptTransitionStep(clusterService, client, config, managedIndexMetaData) + step.execute() + val updatedManagedIndexMetaData = step.getUpdatedManagedIndexMetaData(managedIndexMetaData) + assertEquals("Step status is not FAILED", Step.StepStatus.FAILED, updatedManagedIndexMetaData.stepMetaData?.stepStatus) + assertEquals("Did not get cause from nested exception", "nested", updatedManagedIndexMetaData.info!!["cause"]) + } + } + + private fun getClient(adminClient: AdminClient): Client = mock { on { admin() } doReturn adminClient } + private fun getAdminClient(indicesAdminClient: IndicesAdminClient): AdminClient = mock { on { indices() } doReturn indicesAdminClient } + private fun getIndicesAdminClient(statsResponse: IndicesStatsResponse?, exception: Exception?): IndicesAdminClient { + assertTrue("Must provide one and only one response or exception", (statsResponse != null).xor(exception != null)) + return mock { + doAnswer { invocationOnMock -> + val listener = invocationOnMock.getArgument>(1) + if (statsResponse != null) listener.onResponse(statsResponse) + else listener.onFailure(exception) + }.whenever(this.mock).stats(any(), any()) + } + } +} \ No newline at end of file