From 7b75b3779801f9011c5ba7b2431b86405a6741e6 Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Mon, 12 Jun 2017 11:29:21 +0200 Subject: [PATCH] test: Ported more OldIndexBackwardsCompatibilityIT tests to full cluster restart qa tests. Relates to #24939 --- .../xcontent/support/XContentMapValues.java | 2 +- .../OldIndexBackwardsCompatibilityIT.java | 92 ------- .../upgrades/FullClusterRestartIT.java | 243 ++++++++++++++---- 3 files changed, 201 insertions(+), 136 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java b/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java index 36eacb81f8309..6e9b53a73615c 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java @@ -97,7 +97,7 @@ private static void extractRawValues(List values, List part, String[] pa } } - public static Object extractValue(String path, Map map) { + public static Object extractValue(String path, Map map) { String[] pathElements = path.split("\\."); if (pathElements.length == 0) { return null; diff --git a/core/src/test/java/org/elasticsearch/bwcompat/OldIndexBackwardsCompatibilityIT.java b/core/src/test/java/org/elasticsearch/bwcompat/OldIndexBackwardsCompatibilityIT.java index 21dd76b67e6e5..10cd950fd91c3 100644 --- a/core/src/test/java/org/elasticsearch/bwcompat/OldIndexBackwardsCompatibilityIT.java +++ b/core/src/test/java/org/elasticsearch/bwcompat/OldIndexBackwardsCompatibilityIT.java @@ -228,10 +228,6 @@ void assertOldIndexWorks(String index) throws Exception { // node startup upgradeIndexFolder(); importIndex(indexName); - assertAllSearchWorks(indexName); - assertBasicAggregationWorks(indexName); - assertRealtimeGetWorks(indexName); - assertNewReplicasWork(indexName); assertUpgradeWorks(client(), indexName, version); assertPositionIncrementGapDefaults(indexName, version); assertAliasWithBadName(indexName, version); @@ -239,94 +235,6 @@ void assertOldIndexWorks(String index) throws Exception { unloadIndex(indexName); } - boolean findPayloadBoostInExplanation(Explanation expl) { - if (expl.getDescription().startsWith("payloadBoost=") && expl.getValue() != 1f) { - return true; - } else { - boolean found = false; - for (Explanation sub : expl.getDetails()) { - found |= findPayloadBoostInExplanation(sub); - } - return found; - } - } - - void assertAllSearchWorks(String indexName) { - logger.info("--> testing _all search"); - SearchResponse searchRsp = client().prepareSearch(indexName).get(); - ElasticsearchAssertions.assertNoFailures(searchRsp); - assertThat(searchRsp.getHits().getTotalHits(), greaterThanOrEqualTo(1L)); - SearchHit bestHit = searchRsp.getHits().getAt(0); - - // Make sure there are payloads and they are taken into account for the score - // the 'string' field has a boost of 4 in the mappings so it should get a payload boost - String stringValue = (String) bestHit.getSourceAsMap().get("string"); - assertNotNull(stringValue); - Explanation explanation = client().prepareExplain(indexName, bestHit.getType(), bestHit.getId()) - .setQuery(QueryBuilders.matchQuery("_all", stringValue)).get().getExplanation(); - assertTrue("Could not find payload boost in explanation\n" + explanation, findPayloadBoostInExplanation(explanation)); - - // Make sure the query can run on the whole index - searchRsp = client().prepareSearch(indexName).setQuery(QueryBuilders.matchQuery("_all", stringValue)).setExplain(true).get(); - ElasticsearchAssertions.assertNoFailures(searchRsp); - assertThat(searchRsp.getHits().getTotalHits(), greaterThanOrEqualTo(1L)); - } - - void assertBasicAggregationWorks(String indexName) { - // histogram on a long - SearchResponse searchRsp = client().prepareSearch(indexName).addAggregation(AggregationBuilders.histogram("histo").field - ("long_sort").interval(10)).get(); - ElasticsearchAssertions.assertSearchResponse(searchRsp); - Histogram histo = searchRsp.getAggregations().get("histo"); - assertNotNull(histo); - long totalCount = 0; - for (Histogram.Bucket bucket : histo.getBuckets()) { - totalCount += bucket.getDocCount(); - } - assertEquals(totalCount, searchRsp.getHits().getTotalHits()); - - // terms on a boolean - searchRsp = client().prepareSearch(indexName).addAggregation(AggregationBuilders.terms("bool_terms").field("bool")).get(); - Terms terms = searchRsp.getAggregations().get("bool_terms"); - totalCount = 0; - for (Terms.Bucket bucket : terms.getBuckets()) { - totalCount += bucket.getDocCount(); - } - assertEquals(totalCount, searchRsp.getHits().getTotalHits()); - } - - void assertRealtimeGetWorks(String indexName) { - assertAcked(client().admin().indices().prepareUpdateSettings(indexName).setSettings(Settings.builder() - .put("refresh_interval", -1) - .build())); - SearchRequestBuilder searchReq = client().prepareSearch(indexName).setQuery(QueryBuilders.matchAllQuery()); - SearchHit hit = searchReq.get().getHits().getAt(0); - String docId = hit.getId(); - // foo is new, it is not a field in the generated index - client().prepareUpdate(indexName, "doc", docId).setDoc(Requests.INDEX_CONTENT_TYPE, "foo", "bar").get(); - GetResponse getRsp = client().prepareGet(indexName, "doc", docId).get(); - Map source = getRsp.getSourceAsMap(); - assertThat(source, Matchers.hasKey("foo")); - - assertAcked(client().admin().indices().prepareUpdateSettings(indexName).setSettings(Settings.builder() - .put("refresh_interval", IndexSettings.DEFAULT_REFRESH_INTERVAL) - .build())); - } - - void assertNewReplicasWork(String indexName) throws Exception { - final int numReplicas = 1; - final long startTime = System.currentTimeMillis(); - logger.debug("--> creating [{}] replicas for index [{}]", numReplicas, indexName); - assertAcked(client().admin().indices().prepareUpdateSettings(indexName).setSettings(Settings.builder() - .put("number_of_replicas", numReplicas) - ).execute().actionGet()); - ensureGreen(TimeValue.timeValueMinutes(2), indexName); - logger.debug("--> index [{}] is green, took [{}]", indexName, TimeValue.timeValueMillis(System.currentTimeMillis() - startTime)); - logger.debug("--> recovery status:\n{}", XContentHelper.toString(client().admin().indices().prepareRecoveries(indexName).get())); - - // TODO: do something with the replicas! query? index? - } - void assertPositionIncrementGapDefaults(String indexName, Version version) throws Exception { client().prepareIndex(indexName, "doc", "position_gap_test").setSource("string", Arrays.asList("one", "two three")) .setRefreshPolicy(RefreshPolicy.IMMEDIATE).get(); diff --git a/qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java b/qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java index d7a2a07ed9095..23ea65b193ce2 100644 --- a/qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java +++ b/qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java @@ -36,6 +36,7 @@ import java.io.IOException; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; @@ -46,6 +47,7 @@ import static java.util.Collections.singletonMap; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; /** * Tests to run before and after a full cluster restart. This is run twice, @@ -131,6 +133,80 @@ public void testSearch() throws Exception { count = countOfIndexedRandomDocuments(); } assertBasicSearchWorks(count); + assertAllSearchWorks(count); + assertBasicAggregationWorks(count); + assertRealtimeGetWorks(count); + } + + public void testNewReplicasWork() throws Exception { + if (runningAgainstOldCluster) { + XContentBuilder mappingsAndSettings = jsonBuilder(); + mappingsAndSettings.startObject(); + { + mappingsAndSettings.startObject("settings"); + mappingsAndSettings.field("number_of_shards", 1); + mappingsAndSettings.field("number_of_replicas", 0); + mappingsAndSettings.endObject(); + } + { + mappingsAndSettings.startObject("mappings"); + mappingsAndSettings.startObject("doc"); + mappingsAndSettings.startObject("properties"); + { + mappingsAndSettings.startObject("field"); + mappingsAndSettings.field("type", "text"); + mappingsAndSettings.endObject(); + } + mappingsAndSettings.endObject(); + mappingsAndSettings.endObject(); + mappingsAndSettings.endObject(); + } + mappingsAndSettings.endObject(); + client().performRequest("PUT", "/" + index, Collections.emptyMap(), + new StringEntity(mappingsAndSettings.string(), ContentType.APPLICATION_JSON)); + + int numDocs = randomIntBetween(2000, 3000); + indexRandomDocuments(numDocs, true, false, i -> { + return JsonXContent.contentBuilder().startObject() + .field("field", "value") + .endObject(); + }); + logger.info("Refreshing [{}]", index); + client().performRequest("POST", "/" + index + "/_refresh"); + } else { + final int numReplicas = 1; + final long startTime = System.currentTimeMillis(); + logger.debug("--> creating [{}] replicas for index [{}]", numReplicas, index); + String requestBody = "{ \"index\": { \"number_of_replicas\" : " + numReplicas + " }}"; + Response response = client().performRequest("PUT", "/" + index + "/_settings", Collections.emptyMap(), + new StringEntity(requestBody, ContentType.APPLICATION_JSON)); + assertEquals(200, response.getStatusLine().getStatusCode()); + + Map params = new HashMap<>(); + params.put("timeout", "2m"); + params.put("wait_for_status", "green"); + params.put("wait_for_no_relocating_shards", "true"); + params.put("wait_for_events", "languid"); + Map healthRsp = toMap(client().performRequest("GET", "/_cluster/health/" + index, params)); + assertEquals("green", healthRsp.get("status")); + assertFalse((Boolean) healthRsp.get("timed_out")); + + logger.debug("--> index [{}] is green, took [{}] ms", index, (System.currentTimeMillis() - startTime)); + Map recoverRsp = toMap(client().performRequest("GET", "/" + index + "/_recovery")); + logger.debug("--> recovery status:\n{}", recoverRsp); + + Map responseBody = toMap(client().performRequest("GET", "/" + index + "/_search", + Collections.singletonMap("preference", "_primary"))); + assertNoFailures(responseBody); + int foundHits1 = (int) XContentMapValues.extractValue("hits.total", responseBody); + + responseBody = toMap(client().performRequest("GET", "/" + index + "/_search", + Collections.singletonMap("preference", "_replica"))); + assertNoFailures(responseBody); + int foundHits2 = (int) XContentMapValues.extractValue("hits.total", responseBody); + assertEquals(foundHits1, foundHits2); + // TODO: do something more with the replicas! index? + } } void assertBasicSearchWorks(int count) throws IOException { @@ -165,6 +241,89 @@ void assertBasicSearchWorks(int count) throws IOException { assertEquals(count, numDocs); } + void assertAllSearchWorks(int count) throws IOException { + logger.info("--> testing _all search"); + Map searchRsp = toMap(client().performRequest("GET", "/" + index + "/_search")); + assertNoFailures(searchRsp); + int totalHits = (int) XContentMapValues.extractValue("hits.total", searchRsp); + assertEquals(count, totalHits); + Map bestHit = (Map) ((List)(XContentMapValues.extractValue("hits.hits", searchRsp))).get(0); + + // Make sure there are payloads and they are taken into account for the score + // the 'string' field has a boost of 4 in the mappings so it should get a payload boost + String stringValue = (String) XContentMapValues.extractValue("_source.string", bestHit); + assertNotNull(stringValue); + String type = (String) bestHit.get("_type"); + String id = (String) bestHit.get("_id"); + String requestBody = "{ \"query\": { \"match_all\" : {} }}"; + String explanation = toStr(client().performRequest("GET", "/" + index + "/" + type + "/" + id, + Collections.emptyMap(), new StringEntity(requestBody, ContentType.APPLICATION_JSON))); + assertFalse("Could not find payload boost in explanation\n" + explanation, explanation.contains("payloadBoost")); + + // Make sure the query can run on the whole index + searchRsp = toMap(client().performRequest("GET", "/" + index + "/_search", + Collections.singletonMap("explain", "true"), new StringEntity(requestBody, ContentType.APPLICATION_JSON))); + assertNoFailures(searchRsp); + totalHits = (int) XContentMapValues.extractValue("hits.total", searchRsp); + assertEquals(count, totalHits); + } + + void assertBasicAggregationWorks(int count) throws IOException { + // histogram on a long + String requestBody = "{ \"aggs\": { \"histo\" : {\"histogram\" : {\"field\": \"int\", \"interval\": 10}} }}"; + Map searchRsp = toMap(client().performRequest("GET", "/" + index + "/_search", Collections.emptyMap(), + new StringEntity(requestBody, ContentType.APPLICATION_JSON))); + assertNoFailures(searchRsp); + List histoBuckets = (List) XContentMapValues.extractValue("aggregations.histo.buckets", searchRsp); + long totalCount = 0; + for (Object entry : histoBuckets) { + Map bucket = (Map) entry; + totalCount += (Integer) bucket.get("doc_count"); + } + int totalHits = (int) XContentMapValues.extractValue("hits.total", searchRsp); + assertEquals(totalHits, totalCount); + + // terms on a boolean + requestBody = "{ \"aggs\": { \"bool_terms\" : {\"terms\" : {\"field\": \"bool\"}} }}"; + searchRsp = toMap(client().performRequest("GET", "/" + index + "/_search", Collections.emptyMap(), + new StringEntity(requestBody, ContentType.APPLICATION_JSON))); + List termsBuckets = (List) XContentMapValues.extractValue("aggregations.bool_terms.buckets", searchRsp); + totalCount = 0; + for (Object entry : termsBuckets) { + Map bucket = (Map) entry; + totalCount += (Integer) bucket.get("doc_count"); + } + totalHits = (int) XContentMapValues.extractValue("hits.total", searchRsp); + assertEquals(totalHits, totalCount); + } + + void assertRealtimeGetWorks(int count) throws IOException { + String requestBody = "{ \"index\": { \"refresh_interval\" : -1 }}"; + Response response = client().performRequest("PUT", "/" + index + "/_settings", Collections.emptyMap(), + new StringEntity(requestBody, ContentType.APPLICATION_JSON)); + assertEquals(200, response.getStatusLine().getStatusCode()); + + requestBody = "{ \"query\": { \"match_all\" : {} }}"; + Map searchRsp = toMap(client().performRequest("GET", "/" + index + "/_search", Collections.emptyMap(), + new StringEntity(requestBody, ContentType.APPLICATION_JSON))); + Map hit = (Map) ((List)(XContentMapValues.extractValue("hits.hits", searchRsp))).get(0); + String docId = (String) hit.get("_id"); + + requestBody = "{ \"doc\" : { \"foo\": \"bar\"}}"; + response = client().performRequest("POST", "/" + index + "/doc/" + docId + "/_update", Collections.emptyMap(), + new StringEntity(requestBody, ContentType.APPLICATION_JSON)); + assertEquals(200, response.getStatusLine().getStatusCode()); + + Map getRsp = toMap(client().performRequest("GET", "/" + index + "/doc/" + docId)); + Map source = (Map) getRsp.get("_source"); + assertTrue("doc does not contain 'foo' key: " + source, source.containsKey("foo")); + + requestBody = "{ \"index\": { \"refresh_interval\" : \"1s\" }}"; + response = client().performRequest("PUT", "/" + index + "/_settings", Collections.emptyMap(), + new StringEntity(requestBody, ContentType.APPLICATION_JSON)); + assertEquals(200, response.getStatusLine().getStatusCode()); + } + static Map toMap(Response response) throws IOException { return toMap(EntityUtils.toString(response.getEntity())); } @@ -173,7 +332,11 @@ static Map toMap(String response) throws IOException { return XContentHelper.convertToMap(JsonXContent.jsonXContent, response, false); } - static void assertNoFailures(Map response) { + static String toStr(Response response) throws IOException { + return EntityUtils.toString(response.getEntity()); + } + + static void assertNoFailures(Map response) { int failed = (int) XContentMapValues.extractValue("_shards.failed", response); assertEquals(0, failed); } @@ -190,12 +353,12 @@ public void testSingleDoc() throws IOException { new StringEntity(doc, ContentType.APPLICATION_JSON)); } - assertThat(EntityUtils.toString(client().performRequest("GET", docLocation).getEntity()), containsString(doc)); + assertThat(toStr(client().performRequest("GET", docLocation)), containsString(doc)); } /** * Tests recovery of an index with or without a translog and the - * statistics we gather about that. + * statistics we gather about that. */ public void testRecovery() throws IOException { int count; @@ -222,8 +385,7 @@ public void testRecovery() throws IOException { } // Count the documents in the index to make sure we have as many as we put there - String countResponse = EntityUtils.toString( - client().performRequest("GET", "/" + index + "/_search", singletonMap("size", "0")).getEntity()); + String countResponse = toStr(client().performRequest("GET", "/" + index + "/_search", singletonMap("size", "0"))); assertThat(countResponse, containsString("\"total\":" + count)); if (false == runningAgainstOldCluster) { @@ -232,7 +394,7 @@ public void testRecovery() throws IOException { Map params = new HashMap<>(); params.put("h", "index,shard,type,stage,translog_ops_recovered"); params.put("s", "index,shard,type"); - String recoveryResponse = EntityUtils.toString(client().performRequest("GET", "/_cat/recovery/" + index, params).getEntity()); + String recoveryResponse = toStr(client().performRequest("GET", "/_cat/recovery/" + index, params)); for (String line : recoveryResponse.split("\n")) { // Find the primaries foundPrimary = true; @@ -253,34 +415,33 @@ public void testRecovery() throws IOException { assertTrue("expected to find a primary but didn't\n" + recoveryResponse, foundPrimary); assertEquals("mismatch while checking for translog recovery\n" + recoveryResponse, shouldHaveTranslog, restoredFromTranslog); - String currentLuceneVersion = Version.CURRENT.luceneVersion.toString(); - String bwcLuceneVersion = oldClusterVersion.luceneVersion.toString(); - if (shouldHaveTranslog && false == currentLuceneVersion.equals(bwcLuceneVersion)) { - int numCurrentVersion = 0; - int numBwcVersion = 0; - params.clear(); - params.put("h", "prirep,shard,index,version"); - params.put("s", "prirep,shard,index"); - String segmentsResponse = EntityUtils.toString( - client().performRequest("GET", "/_cat/segments/" + index, params).getEntity()); - for (String line : segmentsResponse.split("\n")) { - if (false == line.startsWith("p")) { - continue; - } - Matcher m = Pattern.compile("(\\d+\\.\\d+\\.\\d+)$").matcher(line); - assertTrue(line, m.find()); - String version = m.group(1); - if (currentLuceneVersion.equals(version)) { - numCurrentVersion++; - } else if (bwcLuceneVersion.equals(version)) { - numBwcVersion++; - } else { - fail("expected version to be one of [" + currentLuceneVersion + "," + bwcLuceneVersion + "] but was " + line); - } + String currentLuceneVersion = Version.CURRENT.luceneVersion.toString(); + String bwcLuceneVersion = oldClusterVersion.luceneVersion.toString(); + if (shouldHaveTranslog && false == currentLuceneVersion.equals(bwcLuceneVersion)) { + int numCurrentVersion = 0; + int numBwcVersion = 0; + params.clear(); + params.put("h", "prirep,shard,index,version"); + params.put("s", "prirep,shard,index"); + String segmentsResponse = toStr( + client().performRequest("GET", "/_cat/segments/" + index, params)); + for (String line : segmentsResponse.split("\n")) { + if (false == line.startsWith("p")) { + continue; + } + Matcher m = Pattern.compile("(\\d+\\.\\d+\\.\\d+)$").matcher(line); + assertTrue(line, m.find()); + String version = m.group(1); + if (currentLuceneVersion.equals(version)) { + numCurrentVersion++; + } else if (bwcLuceneVersion.equals(version)) { + numBwcVersion++; + } else { + fail("expected version to be one of [" + currentLuceneVersion + "," + bwcLuceneVersion + "] but was " + line); } - assertNotEquals("expected at least 1 current segment after translog recovery", 0, numCurrentVersion); - assertNotEquals("expected at least 1 old segment", 0, numBwcVersion); } + assertNotEquals("expected at least 1 current segment after translog recovery", 0, numCurrentVersion); + assertNotEquals("expected at least 1 old segment", 0, numBwcVersion);} } } @@ -317,8 +478,7 @@ public void testSnapshotRestore() throws IOException { } // Count the documents in the index to make sure we have as many as we put there - String countResponse = EntityUtils.toString( - client().performRequest("GET", "/" + index + "/_search", singletonMap("size", "0")).getEntity()); + String countResponse = toStr(client().performRequest("GET", "/" + index + "/_search", singletonMap("size", "0"))); assertThat(countResponse, containsString("\"total\":" + count)); if (false == runningAgainstOldCluster) { @@ -330,8 +490,7 @@ public void testSnapshotRestore() throws IOException { } // Check the metadata, especially the version - String response = EntityUtils.toString( - client().performRequest("GET", "/_snapshot/repo/_all", singletonMap("verbose", "true")).getEntity()); + String response = toStr(client().performRequest("GET", "/_snapshot/repo/_all", singletonMap("verbose", "true"))); Map map = toMap(response); assertEquals(response, singletonList("snap"), XContentMapValues.extractValue("snapshots.snapshot", map)); assertEquals(response, singletonList("SUCCESS"), XContentMapValues.extractValue("snapshots.state", map)); @@ -346,11 +505,10 @@ public void testSnapshotRestore() throws IOException { client().performRequest("POST", "/_snapshot/repo/snap/_restore", singletonMap("wait_for_completion", "true"), new StringEntity(restoreCommand.string(), ContentType.APPLICATION_JSON)); - countResponse = EntityUtils.toString( - client().performRequest("GET", "/restored_" + index + "/_search", singletonMap("size", "0")).getEntity()); - assertThat(countResponse, containsString("\"total\":" + count)); - - } + countResponse = toStr( + client().performRequest("GET", "/restored_" + index + "/_search", singletonMap("size", "0"))); + assertThat(countResponse, containsString("\"total\":" + count)); + } // TODO tests for upgrades after shrink. We've had trouble with shrink in the past. @@ -389,8 +547,7 @@ private void saveInfoDocument(String type, String value) throws IOException { } private String loadInfoDocument(String type) throws IOException { - String doc = EntityUtils.toString( - client().performRequest("GET", "/info/doc/" + index + "_" + type, singletonMap("filter_path", "_source")).getEntity()); + String doc = toStr(client().performRequest("GET", "/info/doc/" + index + "_" + type, singletonMap("filter_path", "_source"))); Matcher m = Pattern.compile("\"value\":\"(.+)\"").matcher(doc); assertTrue(doc, m.find()); return m.group(1);