Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Add integration test for the /override API (#195)
Browse files Browse the repository at this point in the history
* Add integration test for the /override API

* Fix logger usage

* Remove unnecessary call to cleanUpCluster()
  • Loading branch information
ktkrg authored Sep 28, 2020
1 parent 1113ccd commit dff2562
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 67 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ dependencies {
testCompile group: 'org.powermock', name: 'powermock-reflect', version: '2.0.0'
testCompile group: 'net.bytebuddy', name: 'byte-buddy', version: '1.9.3'
testCompile group: 'org.objenesis', name: 'objenesis', version: '3.0.1'
testCompile group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
}

dependencyLicenses {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package com.amazon.opendistro.elasticsearch.performanceanalyzer;

import com.amazon.opendistro.elasticsearch.performanceanalyzer.config.overrides.ConfigOverrides;
import com.amazon.opendistro.elasticsearch.performanceanalyzer.util.WaitFor;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.http.HttpStatus;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.junit.Assert;
import org.junit.Test;

import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class ConfigOverridesIT extends PerformanceAnalyzerIntegTestBase {
private static final String CONFIG_OVERRIDES_ENDPOINT = PERFORMANCE_ANALYZER_BASE_ENDPOINT + "/override/cluster/config";

private static final List<String> EMPTY_LIST = Collections.emptyList();
public static final String HOT_SHARD_RCA = "HotShardRca";
public static final String HOT_NODE_CLUSTER_RCA = "HotNodeClusterRca";

@Test
public void testSimpleOverride() throws Exception {
ensurePaAndRcaEnabled();
final ConfigOverrides overrides = getOverrides(Arrays.asList(HOT_SHARD_RCA, HOT_NODE_CLUSTER_RCA),
EMPTY_LIST, EMPTY_LIST, EMPTY_LIST, EMPTY_LIST, EMPTY_LIST);
final Request postRequest = new Request(METHOD_POST, CONFIG_OVERRIDES_ENDPOINT);
postRequest.setJsonEntity(mapper.writeValueAsString(overrides));

try {
final Response response = client().performRequest(postRequest);
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
} catch (Exception e) {
logger.error("Encountered exception", e);
fail("Failed to set overrides");
}

WaitFor.waitFor(() -> {
try {
Map<String, Object> responseEntity = getAsMap(CONFIG_OVERRIDES_ENDPOINT);
String serializedOverrides = (String) responseEntity.get("overrides");
final ConfigOverrides computedOverrides = mapper.readValue(serializedOverrides, ConfigOverrides.class);
return areEqual(overrides, computedOverrides);
} catch (Exception e) {
logger.error("Encountered exception", e);
return false;
}
}, 2, TimeUnit.MINUTES);
}

@Test
public void testCompositeOverrides() throws Exception {
ensurePaAndRcaEnabled();

final ConfigOverrides initialOverrides = getOverrides(Arrays.asList(HOT_SHARD_RCA, HOT_NODE_CLUSTER_RCA), EMPTY_LIST,
EMPTY_LIST, EMPTY_LIST, EMPTY_LIST, EMPTY_LIST);

final Request postRequest = new Request(METHOD_POST, CONFIG_OVERRIDES_ENDPOINT);
postRequest.setJsonEntity(mapper.writeValueAsString(initialOverrides));

try {
final Response response = client().performRequest(postRequest);
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
} catch (Exception e) {
logger.error("Encountered exception:", e);
fail("Failed to set overrides");
}

WaitFor.waitFor(() -> {
final Request getRequest = new Request(METHOD_GET, CONFIG_OVERRIDES_ENDPOINT);
try {
final Response response = client().performRequest(getRequest);
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
JsonObject jsonResponse = (JsonObject) JsonParser.parseReader(new InputStreamReader(response.getEntity().getContent()));
String serializedOverrides = jsonResponse.get("overrides").getAsString();
final ConfigOverrides computedOverrides = mapper.readValue(serializedOverrides, ConfigOverrides.class);
return areEqual(initialOverrides, computedOverrides);
} catch (Exception e) {
logger.error("Encountered exception", e);
return false;
}
}, 2, TimeUnit.MINUTES);

final ConfigOverrides adjustedOverrides = getOverrides(EMPTY_LIST, EMPTY_LIST, EMPTY_LIST,
Collections.singletonList(HOT_NODE_CLUSTER_RCA), EMPTY_LIST, EMPTY_LIST);

final Request postRequestAdjusted = new Request(METHOD_POST, CONFIG_OVERRIDES_ENDPOINT);
postRequestAdjusted.setJsonEntity(mapper.writeValueAsString(adjustedOverrides));

try {
final Response response = client().performRequest(postRequestAdjusted);
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
} catch (Exception e) {
logger.error("Encountered exception", e);
fail("Failed to set adjusted overrides");
}

final ConfigOverrides expectedOverrides = getOverrides(Collections.singletonList(HOT_SHARD_RCA), EMPTY_LIST, EMPTY_LIST,
Collections.singletonList(HOT_NODE_CLUSTER_RCA), EMPTY_LIST, EMPTY_LIST);

WaitFor.waitFor(() -> {
final Request getRequest = new Request(METHOD_GET, CONFIG_OVERRIDES_ENDPOINT);
try {
final Response response = client().performRequest(getRequest);
Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
JsonObject jsonResponse = (JsonObject) JsonParser.parseReader(new InputStreamReader(response.getEntity().getContent()));
String serializedOverrides = jsonResponse.get("overrides").getAsString();
final ConfigOverrides computedOverrides = mapper.readValue(serializedOverrides, ConfigOverrides.class);
return areEqual(expectedOverrides, computedOverrides);
} catch (Exception e) {
logger.error("Encountered exception", e);
}
return false;
}, 2, TimeUnit.MINUTES);
}

private boolean areEqual(final ConfigOverrides first, final ConfigOverrides second) {
return areEqual(first.getEnable(), second.getEnable()) && areEqual(first.getDisable(), second.getDisable());
}

private boolean areEqual(final ConfigOverrides.Overrides first, final ConfigOverrides.Overrides second) {
if (first != null) {
assertNotNull(second);

return areEqual(first.getRcas(), second.getRcas()) &&
areEqual(first.getDeciders(), second.getDeciders()) &&
areEqual(first.getActions(), second.getActions());
} else {
assertNull(second);
}

return true;
}

private boolean areEqual(final List<String> first, final List<String> second) {
if (first != null) {
assertNotNull(second);
Set<String> firstSet = new HashSet<>(first);
Set<String> secondSet = new HashSet<>(second);

return firstSet.equals(secondSet);
} else {
assertNull(second);
}

return true;
}

private ConfigOverrides getOverrides(List<String> enableRcas, List<String> enableDeciders,
List<String> enableActions, List<String> disableRcas,
List<String> disableDeciders, List<String> disableActions) {
final ConfigOverrides overrides = new ConfigOverrides();
final ConfigOverrides.Overrides enableOverrides = new ConfigOverrides.Overrides();
final ConfigOverrides.Overrides disableOverrides = new ConfigOverrides.Overrides();

enableOverrides.setRcas(enableRcas);
enableOverrides.setDeciders(enableDeciders);
enableOverrides.setActions(enableActions);

disableOverrides.setRcas(disableRcas);
disableOverrides.setDeciders(disableDeciders);
disableOverrides.setActions(disableActions);

overrides.setEnable(enableOverrides);
overrides.setDisable(disableOverrides);

return overrides;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
import com.amazon.opendistro.elasticsearch.performanceanalyzer.config.setting.handler.PerformanceAnalyzerClusterSettingHandler;
import com.amazon.opendistro.elasticsearch.performanceanalyzer.util.WaitFor;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Objects;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpStatus;
Expand All @@ -35,22 +31,25 @@
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Iterator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class PerformanceAnalyzerIT extends ESRestTestCase {
private static final Logger LOG = LogManager.getLogger(PerformanceAnalyzerIT.class);
public abstract class PerformanceAnalyzerIntegTestBase extends ESRestTestCase {
private static final Logger LOG = LogManager.getLogger(PerformanceAnalyzerIntegTestBase.class);
protected static final String PERFORMANCE_ANALYZER_BASE_ENDPOINT = "/_opendistro/_performanceanalyzer";
private int paPort;
private static final ObjectMapper mapper = new ObjectMapper();
protected static final ObjectMapper mapper = new ObjectMapper();
// TODO this must be initialized at construction time to avoid NPEs, we should find a way for subclasses to override this
private ITConfig config = new ITConfig();
private static RestClient paClient;
protected ITConfig config = new ITConfig();
protected static RestClient paClient;
protected static final String METHOD_GET = "GET";
protected static final String METHOD_POST = "POST";

// Don't wipe the cluster after test completion
@Override
Expand Down Expand Up @@ -150,17 +149,21 @@ protected void configureHttpsClient(RestClientBuilder builder, Settings settings
}
}

@Before
public void setupIT() throws Exception {
protected List<HttpHost> getHosts(int port) {
String cluster = config.getRestEndpoint();
paPort = config.getPaPort();
logger.info("Cluster is {}", cluster);
if (cluster == null) {
throw new RuntimeException("Must specify [tests.rest.cluster] system property with a comma delimited list of [host:port] "
+ "to which to send REST requests");
}
List<HttpHost> hosts = Collections.singletonList(
new HttpHost(cluster.substring(0, cluster.lastIndexOf(":")), paPort, "http"));
return Collections.singletonList(
new HttpHost(cluster.substring(0, cluster.lastIndexOf(":")), port, "http"));
}

@Before
public void setupIT() throws Exception {
paPort = config.getPaPort();
List<HttpHost> hosts = getHosts(paPort);
logger.info("initializing PerformanceAnalyzer client against {}", hosts);
paClient = buildBasicClient(restClientSettings(), hosts.toArray(new HttpHost[0]));
}
Expand All @@ -179,10 +182,10 @@ public Response enableComponent(Component component) throws Exception {
String endpoint;
switch (component) {
case PA:
endpoint = "_opendistro/_performanceanalyzer/cluster/config";
endpoint = PERFORMANCE_ANALYZER_BASE_ENDPOINT + "/cluster/config";
break;
case RCA:
endpoint = "_opendistro/_performanceanalyzer/rca/cluster/config";
endpoint = PERFORMANCE_ANALYZER_BASE_ENDPOINT + "/rca/cluster/config";
break;
default:
throw new IllegalArgumentException("Unrecognized component value " + component.toString());
Expand Down Expand Up @@ -212,7 +215,7 @@ public void ensurePaAndRcaEnabled() throws Exception {

// Sanity check that PA and RCA are enabled on the cluster
Response resp = client().performRequest(
new Request("GET", "_opendistro/_performanceanalyzer/cluster/config"));
new Request("GET", PERFORMANCE_ANALYZER_BASE_ENDPOINT + "/cluster/config"));
Map<String, Object> respMap = mapper
.readValue(EntityUtils.toString(resp.getEntity(), "UTF-8"),
new TypeReference<Map<String, Object>>() {
Expand All @@ -223,53 +226,6 @@ public void ensurePaAndRcaEnabled() throws Exception {
PerformanceAnalyzerClusterSettingHandler.checkBit(state, PerformanceAnalyzerFeatureBits.RCA_BIT.ordinal()));
}

@Test
public void checkMetrics() throws Exception {
ensurePaAndRcaEnabled();
final String[] jsonString = new String[1];
WaitFor.waitFor(() -> {
Request request = new Request("GET",
"/_opendistro/_performanceanalyzer/metrics/?metrics=Disk_Utilization&agg=max&dim=&nodes=all");
Response resp = paClient.performRequest(request);
Assert.assertEquals(HttpStatus.SC_OK, resp.getStatusLine().getStatusCode());
jsonString[0] = EntityUtils.toString(resp.getEntity());
JsonNode root = mapper.readTree(jsonString[0]);
for (Iterator<JsonNode> it = root.elements(); it.hasNext(); ) {
JsonNode entry = it.next();
JsonNode data = entry.get(TestUtils.DATA);
if (data.get(TestUtils.FIELDS) == null) {
return false;
}
}
return jsonString[0] != null && !jsonString[0].isEmpty();
}, 1, TimeUnit.MINUTES);
logger.info("jsonString is {}", jsonString[0]);
JsonNode root = mapper.readTree(jsonString[0]);
root.forEach( entry -> {
JsonNode data = entry.get(TestUtils.DATA);
Assert.assertEquals(1, data.get(TestUtils.FIELDS).size());
JsonNode field = data.get(TestUtils.FIELDS).get(0);
Assert.assertEquals(TestUtils.M_DISKUTIL, field.get(TestUtils.FIELD_NAME).asText());
Assert.assertEquals(TestUtils.DOUBLE_TYPE, field.get(TestUtils.FIELD_TYPE).asText());
JsonNode records = data.get(TestUtils.RECORDS);
Assert.assertEquals(1, records.size());
records.get(0).forEach(record -> Assert.assertTrue(record.asDouble() >= 0));
});
}

@Test
public void testRcaIsRunning() throws Exception {
ensurePaAndRcaEnabled();
WaitFor.waitFor(() -> {
Request request = new Request("GET", "/_opendistro/_performanceanalyzer/rca");
try {
Response resp = paClient.performRequest(request);
return Objects.equals(HttpStatus.SC_OK, resp.getStatusLine().getStatusCode());
} catch (Exception e) { // 404, RCA context hasn't been set up yet
return false;
}
}, 2, TimeUnit.MINUTES);
}

@After
public void closePaClient() throws Exception {
Expand All @@ -278,7 +234,7 @@ public void closePaClient() throws Exception {
LOG.debug("AfterClass has run");
}

private static class TestUtils {
protected static class TestUtils {
public static final String DATA = "data";
public static final String RECORDS = "records";

Expand Down
Loading

0 comments on commit dff2562

Please sign in to comment.