diff --git a/src/test/java/org/opensearch/ad/AnomalyDetectorJobRunnerTests.java b/src/test/java/org/opensearch/ad/AnomalyDetectorJobRunnerTests.java index 0db8b9ef5..77ed1226e 100644 --- a/src/test/java/org/opensearch/ad/AnomalyDetectorJobRunnerTests.java +++ b/src/test/java/org/opensearch/ad/AnomalyDetectorJobRunnerTests.java @@ -221,7 +221,7 @@ public void setup() throws Exception { ActionListener listener = (ActionListener) args[1]; if (request.index().equals(CommonName.JOB_INDEX)) { - Job job = TestHelpers.randomAnomalyDetectorJob(true); + Job job = TestHelpers.randomJob(true); listener.onResponse(TestHelpers.createGetResponse(job, randomAlphaOfLength(5), CommonName.JOB_INDEX)); } return null; @@ -788,7 +788,7 @@ public void testMarkResultIndexQueried() throws IOException { doAnswer(invocation -> { ActionListener> listener = invocation.getArgument(1); - listener.onResponse(Optional.of(TestHelpers.randomAnomalyDetectorJob(true, Instant.ofEpochMilli(1602401500000L), null))); + listener.onResponse(Optional.of(TestHelpers.randomJob(true, Instant.ofEpochMilli(1602401500000L), null))); return null; }).when(nodeStateManager).getJob(any(String.class), any(ActionListener.class)); diff --git a/src/test/java/org/opensearch/ad/AnomalyDetectorProfileRunnerTests.java b/src/test/java/org/opensearch/ad/AnomalyDetectorProfileRunnerTests.java index 4036e3665..23229f3b5 100644 --- a/src/test/java/org/opensearch/ad/AnomalyDetectorProfileRunnerTests.java +++ b/src/test/java/org/opensearch/ad/AnomalyDetectorProfileRunnerTests.java @@ -147,11 +147,11 @@ private void setUpClientGet( listener.onFailure(new IndexNotFoundException(CommonName.JOB_INDEX)); break; case DISABLED: - job = TestHelpers.randomAnomalyDetectorJob(false, jobEnabledTime, null); + job = TestHelpers.randomJob(false, jobEnabledTime, null); listener.onResponse(TestHelpers.createGetResponse(job, detector.getId(), CommonName.JOB_INDEX)); break; case ENABLED: - job = TestHelpers.randomAnomalyDetectorJob(true, jobEnabledTime, null); + job = TestHelpers.randomJob(true, jobEnabledTime, null); listener.onResponse(TestHelpers.createGetResponse(job, detector.getId(), CommonName.JOB_INDEX)); break; default: diff --git a/src/test/java/org/opensearch/ad/AnomalyDetectorRestTestCase.java b/src/test/java/org/opensearch/ad/AnomalyDetectorRestTestCase.java index 74505be01..a8db898c7 100644 --- a/src/test/java/org/opensearch/ad/AnomalyDetectorRestTestCase.java +++ b/src/test/java/org/opensearch/ad/AnomalyDetectorRestTestCase.java @@ -485,7 +485,8 @@ public Response createIndexRole(String role, String index) throws IOException { + "\"masked_fields\": [],\n" + "\"allowed_actions\": [\n" + "\"crud\",\n" - + "\"indices:admin/create\"\n" + + "\"indices:admin/create\",\n" + + "\"indices:admin/aliases\"\n" + "]\n" + "}\n" + "],\n" diff --git a/src/test/java/org/opensearch/ad/EntityProfileRunnerTests.java b/src/test/java/org/opensearch/ad/EntityProfileRunnerTests.java index 0ec38eb9a..62ba6a35e 100644 --- a/src/test/java/org/opensearch/ad/EntityProfileRunnerTests.java +++ b/src/test/java/org/opensearch/ad/EntityProfileRunnerTests.java @@ -126,7 +126,7 @@ public void setUp() throws Exception { categoryField = "a"; detector = TestHelpers.randomAnomalyDetectorUsingCategoryFields(detectorId, Arrays.asList(categoryField)); - job = TestHelpers.randomAnomalyDetectorJob(true); + job = TestHelpers.randomJob(true); requiredSamples = 128; client = mock(Client.class); diff --git a/src/test/java/org/opensearch/ad/MultiEntityProfileRunnerTests.java b/src/test/java/org/opensearch/ad/MultiEntityProfileRunnerTests.java index ecf2a91cb..a6d2228f2 100644 --- a/src/test/java/org/opensearch/ad/MultiEntityProfileRunnerTests.java +++ b/src/test/java/org/opensearch/ad/MultiEntityProfileRunnerTests.java @@ -129,7 +129,7 @@ public void setUp() throws Exception { detectorId = "A69pa3UBHuCbh-emo9oR"; detector = TestHelpers.randomAnomalyDetectorUsingCategoryFields(detectorId, Arrays.asList("a")); result = new DetectorInternalState.Builder().lastUpdateTime(Instant.now()); - job = TestHelpers.randomAnomalyDetectorJob(true); + job = TestHelpers.randomJob(true); adTaskManager = mock(ADTaskManager.class); transportService = mock(TransportService.class); doAnswer(invocation -> { diff --git a/src/test/java/org/opensearch/ad/model/AnomalyDetectorJobTests.java b/src/test/java/org/opensearch/ad/model/AnomalyDetectorJobTests.java index df506b010..0996a8d3c 100644 --- a/src/test/java/org/opensearch/ad/model/AnomalyDetectorJobTests.java +++ b/src/test/java/org/opensearch/ad/model/AnomalyDetectorJobTests.java @@ -39,7 +39,7 @@ protected NamedWriteableRegistry writableRegistry() { } public void testParseAnomalyDetectorJob() throws IOException { - Job anomalyDetectorJob = TestHelpers.randomAnomalyDetectorJob(); + Job anomalyDetectorJob = TestHelpers.randomJob(); String anomalyDetectorJobString = TestHelpers .xContentBuilderToString(anomalyDetectorJob.toXContent(TestHelpers.builder(), ToXContent.EMPTY_PARAMS)); anomalyDetectorJobString = anomalyDetectorJobString @@ -50,7 +50,7 @@ public void testParseAnomalyDetectorJob() throws IOException { } public void testSerialization() throws IOException { - Job anomalyDetectorJob = TestHelpers.randomAnomalyDetectorJob(); + Job anomalyDetectorJob = TestHelpers.randomJob(); BytesStreamOutput output = new BytesStreamOutput(); anomalyDetectorJob.writeTo(output); NamedWriteableAwareStreamInput input = new NamedWriteableAwareStreamInput(output.bytes().streamInput(), writableRegistry()); diff --git a/src/test/java/org/opensearch/ad/rest/SecureADRestIT.java b/src/test/java/org/opensearch/ad/rest/SecureADRestIT.java index 63bfcc92c..4a109bbcf 100644 --- a/src/test/java/org/opensearch/ad/rest/SecureADRestIT.java +++ b/src/test/java/org/opensearch/ad/rest/SecureADRestIT.java @@ -409,7 +409,11 @@ public void testCreateAnomalyDetectorWithCustomResultIndex() throws IOException AnomalyDetector detector = cloneDetector(anomalyDetector, resultIndex); // User goat has no permission to create index Exception exception = expectThrows(IOException.class, () -> { createAnomalyDetector(detector, true, goatClient); }); - Assert.assertTrue(exception.getMessage().contains("no permissions for [indices:admin/create]")); + Assert + .assertTrue( + "got " + exception.getMessage(), + exception.getMessage().contains("no permissions for [indices:admin/aliases, indices:admin/create]") + ); // User cat has permission to create index resultIndex = ADCommonName.CUSTOM_RESULT_INDEX_PREFIX + "test2"; diff --git a/src/test/java/org/opensearch/ad/transport/GetAnomalyDetectorResponseTests.java b/src/test/java/org/opensearch/ad/transport/GetAnomalyDetectorResponseTests.java index 236cd2b58..e66dc7cd9 100644 --- a/src/test/java/org/opensearch/ad/transport/GetAnomalyDetectorResponseTests.java +++ b/src/test/java/org/opensearch/ad/transport/GetAnomalyDetectorResponseTests.java @@ -101,7 +101,7 @@ private GetAnomalyDetectorResponse createGetAnomalyDetectorResponse(boolean retu randomLong(), randomLong(), TestHelpers.randomAnomalyDetector(ImmutableList.of(), ImmutableMap.of(), Instant.now().truncatedTo(ChronoUnit.SECONDS)), - TestHelpers.randomAnomalyDetectorJob(), + TestHelpers.randomJob(), returnJob, TestHelpers.randomAdTask(), TestHelpers.randomAdTask(), diff --git a/src/test/java/org/opensearch/ad/transport/GetAnomalyDetectorTransportActionTests.java b/src/test/java/org/opensearch/ad/transport/GetAnomalyDetectorTransportActionTests.java index 1c12aeb08..c41f106cd 100644 --- a/src/test/java/org/opensearch/ad/transport/GetAnomalyDetectorTransportActionTests.java +++ b/src/test/java/org/opensearch/ad/transport/GetAnomalyDetectorTransportActionTests.java @@ -171,7 +171,7 @@ public void testGetAnomalyDetectorRequestNoEntityValue() throws IOException { public void testGetAnomalyDetectorResponse() throws IOException { BytesStreamOutput out = new BytesStreamOutput(); AnomalyDetector detector = TestHelpers.randomAnomalyDetector(ImmutableMap.of("testKey", "testValue"), Instant.now()); - Job adJob = TestHelpers.randomAnomalyDetectorJob(); + Job adJob = TestHelpers.randomJob(); GetAnomalyDetectorResponse response = new GetAnomalyDetectorResponse( 4321, "1234", @@ -205,7 +205,7 @@ public void testGetAnomalyDetectorResponse() throws IOException { public void testGetAnomalyDetectorProfileResponse() throws IOException { BytesStreamOutput out = new BytesStreamOutput(); AnomalyDetector detector = TestHelpers.randomAnomalyDetector(ImmutableMap.of("testKey", "testValue"), Instant.now()); - Job adJob = TestHelpers.randomAnomalyDetectorJob(); + Job adJob = TestHelpers.randomJob(); InitProgressProfile initProgress = new InitProgressProfile("99%", 2L, 2); EntityProfile entityProfile = new EntityProfile.Builder().initProgress(initProgress).build(); GetAnomalyDetectorResponse response = new GetAnomalyDetectorResponse( diff --git a/src/test/java/org/opensearch/forecast/SingleStreamProfileRunnerTests.java b/src/test/java/org/opensearch/forecast/SingleStreamProfileRunnerTests.java new file mode 100644 index 000000000..abe3d1fcf --- /dev/null +++ b/src/test/java/org/opensearch/forecast/SingleStreamProfileRunnerTests.java @@ -0,0 +1,372 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.forecast; + +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.opensearch.Version; +import org.opensearch.action.FailedNodeException; +import org.opensearch.action.get.GetRequest; +import org.opensearch.action.get.GetResponse; +import org.opensearch.action.search.SearchRequest; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.client.Client; +import org.opensearch.cluster.ClusterName; +import org.opensearch.cluster.node.DiscoveryNode; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.transport.TransportAddress; +import org.opensearch.forecast.constant.ForecastCommonName; +import org.opensearch.forecast.indices.ForecastIndex; +import org.opensearch.forecast.model.ForecastResult; +import org.opensearch.forecast.model.ForecastTask; +import org.opensearch.forecast.model.Forecaster; +import org.opensearch.forecast.model.ForecasterProfile; +import org.opensearch.forecast.task.ForecastTaskManager; +import org.opensearch.forecast.transport.ForecastProfileAction; +import org.opensearch.timeseries.AbstractTimeSeriesTest; +import org.opensearch.timeseries.NodeStateManager; +import org.opensearch.timeseries.TestHelpers; +import org.opensearch.timeseries.constant.CommonName; +import org.opensearch.timeseries.model.ConfigProfile; +import org.opensearch.timeseries.model.ConfigState; +import org.opensearch.timeseries.model.Job; +import org.opensearch.timeseries.model.ProfileName; +import org.opensearch.timeseries.transport.ProfileNodeResponse; +import org.opensearch.timeseries.transport.ProfileResponse; +import org.opensearch.timeseries.util.DiscoveryNodeFilterer; +import org.opensearch.timeseries.util.SecurityClientUtil; +import org.opensearch.transport.TransportService; + +public class SingleStreamProfileRunnerTests extends AbstractTimeSeriesTest { + private ForecastProfileRunner runner; + private Client client; + private SecurityClientUtil clientUtil; + private DiscoveryNodeFilterer nodeFilter; + private int requiredSamples; + private Forecaster forecaster; + private String forecasterId; + private Set stateNError; + private String node1; + private String nodeName1; + private DiscoveryNode discoveryNode1; + + private String node2; + private String nodeName2; + private DiscoveryNode discoveryNode2; + + private long modelSize; + private String model1Id; + private String model0Id; + + private Job job; + private TransportService transportService; + private ForecastTaskManager forecastTaskManager; + private ForecastTaskProfileRunner taskProfileRunner; + private ForecastTask task; + + enum InittedEverResultStatus { + INITTED, + NOT_INITTED, + } + + @BeforeClass + public static void setUpBeforeClass() { + setUpThreadPool(SingleStreamProfileRunnerTests.class.getSimpleName()); + } + + @AfterClass + public static void tearDownAfterClass() { + tearDownThreadPool(); + } + + @SuppressWarnings("unchecked") + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + client = mock(Client.class); + taskProfileRunner = mock(ForecastTaskProfileRunner.class); + NodeStateManager nodeStateManager = mock(NodeStateManager.class); + clientUtil = new SecurityClientUtil(nodeStateManager, Settings.EMPTY); + nodeFilter = mock(DiscoveryNodeFilterer.class); + requiredSamples = 128; + + forecasterId = "A69pa3UBHuCbh-emo9oR"; + forecaster = TestHelpers.ForecasterBuilder.newInstance().setConfigId(forecasterId).setCategoryFields(null).build(); + job = TestHelpers.randomJob(true); + forecastTaskManager = mock(ForecastTaskManager.class); + transportService = mock(TransportService.class); + task = TestHelpers.ForecastTaskBuilder.newInstance().build(); + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + Consumer> function = (Consumer>) args[2]; + + function.accept(Optional.of(task)); + return null; + }).when(forecastTaskManager).getAndExecuteOnLatestConfigLevelTask(any(), any(), any(), any(), anyBoolean(), any()); + runner = new ForecastProfileRunner( + client, + clientUtil, + xContentRegistry(), + nodeFilter, + requiredSamples, + transportService, + forecastTaskManager, + taskProfileRunner + ); + + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + GetRequest request = (GetRequest) args[0]; + ActionListener listener = (ActionListener) args[1]; + + String indexName = request.index(); + if (indexName.equals(CommonName.CONFIG_INDEX)) { + listener.onResponse(TestHelpers.createGetResponse(forecaster, forecaster.getId(), CommonName.CONFIG_INDEX)); + } else if (indexName.equals(ForecastIndex.STATE.getIndexName())) { + listener.onResponse(TestHelpers.createGetResponse(task, forecaster.getId(), ForecastIndex.STATE.getIndexName())); + } else if (indexName.equals(CommonName.JOB_INDEX)) { + listener.onResponse(TestHelpers.createGetResponse(job, forecaster.getId(), CommonName.JOB_INDEX)); + } + + return null; + }).when(client).get(any(), any()); + + stateNError = new HashSet(); + stateNError.add(ProfileName.ERROR); + stateNError.add(ProfileName.STATE); + } + + @SuppressWarnings("unchecked") + private void setUpClientExecuteProfileAction(InittedEverResultStatus initted) { + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + ActionListener listener = (ActionListener) args[2]; + + node1 = "node1"; + nodeName1 = "nodename1"; + discoveryNode1 = new DiscoveryNode( + nodeName1, + node1, + new TransportAddress(TransportAddress.META_ADDRESS, 9300), + emptyMap(), + emptySet(), + Version.CURRENT + ); + + node2 = "node2"; + nodeName2 = "nodename2"; + discoveryNode2 = new DiscoveryNode( + nodeName2, + node2, + new TransportAddress(TransportAddress.META_ADDRESS, 9301), + emptyMap(), + emptySet(), + Version.CURRENT + ); + + modelSize = 712480L; + model1Id = "A69pa3UBHuCbh-emo9oR_entity_host1"; + model0Id = "A69pa3UBHuCbh-emo9oR_entity_host0"; + + String clusterName = "test-cluster-name"; + + Map modelSizeMap1 = new HashMap() { + { + put(model1Id, modelSize); + } + }; + + Map modelSizeMap2 = new HashMap() { + { + put(model0Id, modelSize); + } + }; + + // one model in each node; all fully initialized + long updates = requiredSamples - 1; + if (InittedEverResultStatus.INITTED == initted) { + updates = requiredSamples + 1; + } + ProfileNodeResponse profileNodeResponse1 = new ProfileNodeResponse( + discoveryNode1, + modelSizeMap1, + 1L, + updates, + new ArrayList<>(), + modelSizeMap1.size(), + false + ); + ProfileNodeResponse profileNodeResponse2 = new ProfileNodeResponse( + discoveryNode2, + modelSizeMap2, + 1L, + updates, + new ArrayList<>(), + modelSizeMap2.size(), + false + ); + List profileNodeResponses = Arrays.asList(profileNodeResponse1, profileNodeResponse2); + List failures = Collections.emptyList(); + ProfileResponse profileResponse = new ProfileResponse(new ClusterName(clusterName), profileNodeResponses, failures); + + listener.onResponse(profileResponse); + + return null; + }).when(client).execute(any(ForecastProfileAction.class), any(), any()); + + } + + @SuppressWarnings("unchecked") + private void setUpClientSearch(InittedEverResultStatus inittedEverResultStatus) { + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + SearchRequest request = (SearchRequest) args[0]; + ActionListener listener = (ActionListener) args[1]; + + ForecastResult result = null; + if (request.source().query().toString().contains(ForecastResult.VALUE_FIELD)) { + switch (inittedEverResultStatus) { + case INITTED: + result = TestHelpers.ForecastResultBuilder.newInstance().build(); + listener.onResponse(TestHelpers.createSearchResponse(result)); + break; + case NOT_INITTED: + listener.onResponse(TestHelpers.createEmptySearchResponse()); + break; + default: + assertTrue("should not reach here", false); + break; + } + } + + return null; + }).when(client).search(any(), any()); + } + + public void testInit() throws InterruptedException { + setUpClientExecuteProfileAction(InittedEverResultStatus.NOT_INITTED); + setUpClientSearch(InittedEverResultStatus.NOT_INITTED); + + final CountDownLatch inProgressLatch = new CountDownLatch(1); + + ConfigProfile expectedProfile = new ForecasterProfile.Builder().state(ConfigState.INIT).build(); + runner.profile(forecasterId, ActionListener.wrap(response -> { + assertEquals(expectedProfile, response); + inProgressLatch.countDown(); + }, exception -> { + assertTrue("Should not reach here", false); + inProgressLatch.countDown(); + }), stateNError); + assertTrue(inProgressLatch.await(100, TimeUnit.SECONDS)); + } + + public void testRunning() throws InterruptedException { + setUpClientExecuteProfileAction(InittedEverResultStatus.INITTED); + setUpClientSearch(InittedEverResultStatus.INITTED); + + final CountDownLatch inProgressLatch = new CountDownLatch(1); + + ConfigProfile expectedProfile = new ForecasterProfile.Builder().state(ConfigState.RUNNING).build(); + runner.profile(forecasterId, ActionListener.wrap(response -> { + assertEquals(expectedProfile, response); + inProgressLatch.countDown(); + }, exception -> { + assertTrue("Should not reach here", false); + inProgressLatch.countDown(); + }), stateNError); + assertTrue(inProgressLatch.await(100, TimeUnit.SECONDS)); + } + + /** + * Although profile action results indicate not initted, we trust what result index tells us + * @throws InterruptedException if CountDownLatch is interrupted while waiting + */ + public void testResultIndexFinalTruth() throws InterruptedException { + setUpClientExecuteProfileAction(InittedEverResultStatus.NOT_INITTED); + setUpClientSearch(InittedEverResultStatus.INITTED); + + final CountDownLatch inProgressLatch = new CountDownLatch(1); + + ConfigProfile expectedProfile = new ForecasterProfile.Builder().state(ConfigState.RUNNING).build(); + runner.profile(forecasterId, ActionListener.wrap(response -> { + assertEquals(expectedProfile, response); + inProgressLatch.countDown(); + }, exception -> { + assertTrue("Should not reach here", false); + inProgressLatch.countDown(); + }), stateNError); + assertTrue(inProgressLatch.await(100, TimeUnit.SECONDS)); + } + + /** + * Although profile action results indicate not initted, we trust what result index tells us + * @throws InterruptedException if CountDownLatch is interrupted while waiting + * @throws IOException + */ + public void testCustomResultIndexFinalTruth() throws InterruptedException, IOException { + setUpClientExecuteProfileAction(InittedEverResultStatus.NOT_INITTED); + setUpClientSearch(InittedEverResultStatus.INITTED); + + forecaster = TestHelpers.ForecasterBuilder + .newInstance() + .setConfigId(forecasterId) + .setCategoryFields(null) + .setCustomResultIndex(ForecastCommonName.CUSTOM_RESULT_INDEX_PREFIX + "test-index") + .build(); + doAnswer(invocation -> { + Object[] args = invocation.getArguments(); + GetRequest request = (GetRequest) args[0]; + ActionListener listener = (ActionListener) args[1]; + + String indexName = request.index(); + if (indexName.equals(CommonName.CONFIG_INDEX)) { + listener.onResponse(TestHelpers.createGetResponse(forecaster, forecaster.getId(), CommonName.CONFIG_INDEX)); + } else if (indexName.equals(ForecastIndex.STATE.getIndexName())) { + listener.onResponse(TestHelpers.createGetResponse(task, forecaster.getId(), ForecastIndex.STATE.getIndexName())); + } else if (indexName.equals(CommonName.JOB_INDEX)) { + listener.onResponse(TestHelpers.createGetResponse(job, forecaster.getId(), CommonName.JOB_INDEX)); + } + + return null; + }).when(client).get(any(), any()); + + final CountDownLatch inProgressLatch = new CountDownLatch(1); + + ConfigProfile expectedProfile = new ForecasterProfile.Builder().state(ConfigState.RUNNING).build(); + runner.profile(forecasterId, ActionListener.wrap(response -> { + assertEquals(expectedProfile, response); + inProgressLatch.countDown(); + }, exception -> { + assertTrue("Should not reach here", false); + inProgressLatch.countDown(); + }), stateNError); + assertTrue(inProgressLatch.await(100, TimeUnit.SECONDS)); + } +} diff --git a/src/test/java/org/opensearch/search/aggregations/metrics/CardinalityProfileTests.java b/src/test/java/org/opensearch/search/aggregations/metrics/CardinalityProfileTests.java index bb37434f3..6dbd8b5e0 100644 --- a/src/test/java/org/opensearch/search/aggregations/metrics/CardinalityProfileTests.java +++ b/src/test/java/org/opensearch/search/aggregations/metrics/CardinalityProfileTests.java @@ -108,7 +108,7 @@ private void setUpMultiEntityClientGet(DetectorStatus detectorStatus, JobStatus Job job = null; switch (jobStatus) { case ENABLED: - job = TestHelpers.randomAnomalyDetectorJob(true); + job = TestHelpers.randomJob(true); listener.onResponse(TestHelpers.createGetResponse(job, detector.getId(), CommonName.JOB_INDEX)); break; default: diff --git a/src/test/java/org/opensearch/timeseries/NodeStateManagerTests.java b/src/test/java/org/opensearch/timeseries/NodeStateManagerTests.java index 4b91e18b5..73acb5cf2 100644 --- a/src/test/java/org/opensearch/timeseries/NodeStateManagerTests.java +++ b/src/test/java/org/opensearch/timeseries/NodeStateManagerTests.java @@ -141,7 +141,7 @@ public void setUp() throws Exception { ); checkpointResponse = mock(GetResponse.class); - jobToCheck = TestHelpers.randomAnomalyDetectorJob(true, Instant.ofEpochMilli(1602401500000L), null); + jobToCheck = TestHelpers.randomJob(true, Instant.ofEpochMilli(1602401500000L), null); } @Override diff --git a/src/test/java/org/opensearch/timeseries/TestHelpers.java b/src/test/java/org/opensearch/timeseries/TestHelpers.java index d2217e3fe..d3d64bddd 100644 --- a/src/test/java/org/opensearch/timeseries/TestHelpers.java +++ b/src/test/java/org/opensearch/timeseries/TestHelpers.java @@ -23,6 +23,7 @@ import static org.opensearch.test.OpenSearchTestCase.randomBoolean; import static org.opensearch.test.OpenSearchTestCase.randomDouble; import static org.opensearch.test.OpenSearchTestCase.randomDoubleBetween; +import static org.opensearch.test.OpenSearchTestCase.randomFloat; import static org.opensearch.test.OpenSearchTestCase.randomInt; import static org.opensearch.test.OpenSearchTestCase.randomIntBetween; import static org.opensearch.test.OpenSearchTestCase.randomLong; @@ -115,6 +116,7 @@ import org.opensearch.core.xcontent.ToXContentObject; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.core.xcontent.XContentParser; +import org.opensearch.forecast.model.ForecastResult; import org.opensearch.forecast.model.ForecastTask; import org.opensearch.forecast.model.Forecaster; import org.opensearch.index.get.GetResult; @@ -713,7 +715,8 @@ public AnomalyDetector build() { user, resultIndex, imputationOption, - randomIntBetween(1, 10000), + // transform decay has to be [0, 1). So we cannot use 1. + randomIntBetween(2, 10000), randomIntBetween(1, TimeSeriesSettings.MAX_SHINGLE_SIZE * 2), // make history intervals at least TimeSeriesSettings.NUM_MIN_SAMPLES. // Otherwise, tests like EntityColdStarterTests.testTwoSegments may fail @@ -912,7 +915,7 @@ public static AnomalyResult randomAnomalyDetectResult() { } public static AnomalyResult randomAnomalyDetectResult(double score) { - return randomAnomalyDetectResult(randomDouble(), null, null); + return randomAnomalyDetectResult(score, null, null); } public static AnomalyResult randomAnomalyDetectResult(String error) { @@ -1044,11 +1047,11 @@ public static AnomalyResult randomHCADAnomalyDetectResult( ); } - public static Job randomAnomalyDetectorJob() { - return randomAnomalyDetectorJob(true); + public static Job randomJob() { + return randomJob(true); } - public static Job randomAnomalyDetectorJob(boolean enabled, Instant enabledTime, Instant disabledTime) { + public static Job randomJob(boolean enabled, Instant enabledTime, Instant disabledTime) { return new Job( randomAlphaOfLength(10), randomIntervalSchedule(), @@ -1064,12 +1067,8 @@ public static Job randomAnomalyDetectorJob(boolean enabled, Instant enabledTime, ); } - public static Job randomAnomalyDetectorJob(boolean enabled) { - return randomAnomalyDetectorJob( - enabled, - Instant.now().truncatedTo(ChronoUnit.SECONDS), - Instant.now().truncatedTo(ChronoUnit.SECONDS) - ); + public static Job randomJob(boolean enabled) { + return randomJob(enabled, Instant.now().truncatedTo(ChronoUnit.SECONDS), Instant.now().truncatedTo(ChronoUnit.SECONDS)); } public static AnomalyDetectorExecutionInput randomAnomalyDetectorExecutionInput() throws IOException { @@ -1935,9 +1934,7 @@ public static class ForecastTaskBuilder { private DateRange dateRange = new DateRange(Instant.ofEpochMilli(123), Instant.ofEpochMilli(456)); - public ForecastTaskBuilder() throws IOException { - forecaster = TestHelpers.randomForecaster(); - } + public ForecastTaskBuilder() throws IOException {} public static ForecastTaskBuilder newInstance() throws IOException { return new ForecastTaskBuilder(); @@ -1991,4 +1988,58 @@ public ForecastTask build() { .build(); } } + + public static class ForecastResultBuilder { + private String forecasterId = randomAlphaOfLength(5); + private String taskId = randomAlphaOfLength(5); + private Double dataQuality = randomDouble(); + private List featureData = ImmutableList.of(randomFeatureData(), randomFeatureData()); + private Instant dataStartTime = Instant.now().truncatedTo(ChronoUnit.SECONDS); + private Instant dataEndTime = Instant.now().truncatedTo(ChronoUnit.SECONDS); + private Instant executionStartTime = Instant.now().truncatedTo(ChronoUnit.SECONDS); + private Instant executionEndTime = Instant.now().truncatedTo(ChronoUnit.SECONDS); + private String error = ""; + private Optional entity = Optional.empty(); + private User user = randomUser(); + private Integer schemaVersion = randomIntBetween(1, 10); + private String featureId = randomAlphaOfLength(5); + private Float forecastValue = randomFloat(); + private Float lowerBound = randomFloat(); + private Float upperBound = randomFloat(); + private Instant forecastDataStartTime = Instant.now().truncatedTo(ChronoUnit.SECONDS); + private Instant forecastDataEndTime = Instant.now().truncatedTo(ChronoUnit.SECONDS); + private Integer horizonIndex = randomIntBetween(1, 10); + + public ForecastResultBuilder() { + + } + + public static ForecastResultBuilder newInstance() { + return new ForecastResultBuilder(); + } + + public ForecastResult build() { + return new ForecastResult( + forecasterId, + taskId, + dataQuality, + featureData, + dataStartTime, + dataEndTime, + executionStartTime, + executionEndTime, + error, + entity, + user, + schemaVersion, + featureId, + forecastValue, + lowerBound, + upperBound, + forecastDataStartTime, + forecastDataEndTime, + horizonIndex + ); + } + } }