Skip to content

Commit bc574c9

Browse files
ES-10063: Add multi-project IT for indices stats API (#127926)
This API already works correctly. This change just adds a test. ES-10063 #comment Added a test which shows that indices stats already works correctly in #127926
1 parent 8761067 commit bc574c9

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.action.admin.indices.stats;
11+
12+
import org.elasticsearch.client.Request;
13+
import org.elasticsearch.client.ResponseException;
14+
import org.elasticsearch.common.Strings;
15+
import org.elasticsearch.common.settings.SecureString;
16+
import org.elasticsearch.common.settings.Settings;
17+
import org.elasticsearch.common.util.concurrent.ThreadContext;
18+
import org.elasticsearch.multiproject.MultiProjectRestTestCase;
19+
import org.elasticsearch.test.cluster.ElasticsearchCluster;
20+
import org.elasticsearch.test.cluster.local.distribution.DistributionType;
21+
import org.elasticsearch.test.rest.ObjectPath;
22+
import org.junit.ClassRule;
23+
24+
import java.io.IOException;
25+
import java.util.Map;
26+
27+
import static org.hamcrest.Matchers.containsInAnyOrder;
28+
import static org.hamcrest.Matchers.equalTo;
29+
30+
public class IndicesStatsMultiProjectIT extends MultiProjectRestTestCase {
31+
32+
private static final String PASSWORD = "hunter2";
33+
34+
@ClassRule
35+
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
36+
.nodes(1)
37+
.distribution(DistributionType.INTEG_TEST)
38+
.module("test-multi-project")
39+
.setting("test.multi_project.enabled", "true")
40+
.setting("xpack.security.enabled", "true")
41+
.user("admin", PASSWORD)
42+
.build();
43+
44+
@Override
45+
protected String getTestRestCluster() {
46+
return cluster.getHttpAddresses();
47+
}
48+
49+
@Override
50+
protected Settings restClientSettings() {
51+
final String token = basicAuthHeaderValue("admin", new SecureString(PASSWORD.toCharArray()));
52+
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
53+
}
54+
55+
public void testIndicesStats() throws IOException {
56+
// Create two projects. We will use the default project as the third project in this test.
57+
createProject("project-1");
58+
createProject("project-2");
59+
60+
// Create and write data into a number of indices.
61+
// Some of the index names are used only in one project, some in two projects, some in all three.
62+
int numDocs1Only = createPopulatedIndex("project-1", "my-index-project-1-only");
63+
int numDocs2Only = createPopulatedIndex("project-2", "my-index-project-2-only");
64+
int numDocsDefaultOnly = createPopulatedIndex("default", "my-index-default-project-only");
65+
int numDocs1Of1And2 = createPopulatedIndex("project-1", "my-index-projects-1-and-2");
66+
int numDocs2Of1And2 = createPopulatedIndex("project-2", "my-index-projects-1-and-2");
67+
int numDocs2Of2AndDefault = createPopulatedIndex("project-2", "my-index-projects-2-and-default");
68+
int numDocsDefaultOf2AndDefault = createPopulatedIndex("default", "my-index-projects-2-and-default");
69+
int numDocs1All = createPopulatedIndex("project-1", "my-index-all-projects");
70+
int numDocs2All = createPopulatedIndex("project-2", "my-index-all-projects");
71+
int numDocsDefaultAll = createPopulatedIndex("default", "my-index-all-projects");
72+
73+
// Check indices stats for project 1.
74+
ObjectPath statsForProject1 = getAsObjectPathInProject("/_stats", "project-1");
75+
assertThat(statsForProject1.evaluate("_all.total.docs.count"), equalTo(numDocs1Only + numDocs1Of1And2 + numDocs1All));
76+
assertThat(
77+
statsForProject1.<Map<String, Object>>evaluate("indices").keySet(),
78+
containsInAnyOrder("my-index-project-1-only", "my-index-projects-1-and-2", "my-index-all-projects")
79+
);
80+
assertThat(statsForProject1.evaluate("indices.my-index-project-1-only.total.docs.count"), equalTo(numDocs1Only));
81+
assertThat(statsForProject1.evaluate("indices.my-index-projects-1-and-2.total.docs.count"), equalTo(numDocs1Of1And2));
82+
assertThat(statsForProject1.evaluate("indices.my-index-all-projects.total.docs.count"), equalTo(numDocs1All));
83+
84+
// Check indices stats for project 2.
85+
ObjectPath statsForProject2 = getAsObjectPathInProject("/_stats", "project-2");
86+
assertThat(
87+
statsForProject2.evaluate("_all.total.docs.count"),
88+
equalTo(numDocs2Only + numDocs2Of1And2 + numDocs2Of2AndDefault + numDocs2All)
89+
);
90+
assertThat(
91+
statsForProject2.<Map<String, Object>>evaluate("indices").keySet(),
92+
containsInAnyOrder(
93+
"my-index-project-2-only",
94+
"my-index-projects-1-and-2",
95+
"my-index-projects-2-and-default",
96+
"my-index-all-projects"
97+
)
98+
);
99+
assertThat(statsForProject2.evaluate("indices.my-index-all-projects.total.docs.count"), equalTo(numDocs2All));
100+
101+
// Check indices stats for default project.
102+
ObjectPath statsForDefaultProject = getAsObjectPathInDefaultProject("/_stats");
103+
assertThat(
104+
statsForDefaultProject.evaluate("_all.total.docs.count"),
105+
equalTo(numDocsDefaultOnly + numDocsDefaultOf2AndDefault + numDocsDefaultAll)
106+
);
107+
assertThat(
108+
statsForDefaultProject.<Map<String, Object>>evaluate("indices").keySet(),
109+
containsInAnyOrder("my-index-default-project-only", "my-index-projects-2-and-default", "my-index-all-projects")
110+
);
111+
assertThat(statsForDefaultProject.evaluate("indices.my-index-all-projects.total.docs.count"), equalTo(numDocsDefaultAll));
112+
113+
// Check single-index stats for each project.
114+
assertThat(
115+
getAsObjectPathInProject("/my-index-all-projects/_stats", "project-1").evaluate("_all.total.docs.count"),
116+
equalTo(numDocs1All)
117+
);
118+
assertThat(
119+
getAsObjectPathInProject("/my-index-all-projects/_stats", "project-2").evaluate("_all.total.docs.count"),
120+
equalTo(numDocs2All)
121+
);
122+
assertThat(
123+
getAsObjectPathInDefaultProject("/my-index-all-projects/_stats").evaluate("_all.total.docs.count"),
124+
equalTo(numDocsDefaultAll)
125+
);
126+
127+
// Check that getting single-index stats for an index that does not exist in a project returns a 404.
128+
ResponseException exception = assertThrows(
129+
ResponseException.class,
130+
() -> client().performRequest(setRequestProjectId(new Request("GET", "/my-index-project-1-only/_stats"), "project-2"))
131+
);
132+
assertThat(exception.getResponse().getStatusLine().getStatusCode(), equalTo(404));
133+
134+
// Check using a wildcard gets the matching indices for that project.
135+
ObjectPath statsWithWildcardForProject1 = getAsObjectPathInProject("/my-index-project*/_stats", "project-1");
136+
assertThat(statsWithWildcardForProject1.evaluate("_all.total.docs.count"), equalTo(numDocs1Only + numDocs1Of1And2));
137+
assertThat(
138+
statsWithWildcardForProject1.<Map<String, Object>>evaluate("indices").keySet(),
139+
containsInAnyOrder("my-index-project-1-only", "my-index-projects-1-and-2")
140+
);
141+
}
142+
143+
private int createPopulatedIndex(String projectId, String indexName) throws IOException {
144+
createIndex(req -> {
145+
setRequestProjectId(req, projectId);
146+
return client().performRequest(req);
147+
}, indexName, null, null, null);
148+
int numDocs = randomIntBetween(5, 10);
149+
for (int i = 0; i < numDocs; i++) {
150+
Request request = new Request("POST", "/" + indexName + "/_doc");
151+
request.setJsonEntity(Strings.format("{ \"num\": %d, \"str\": \"%s\" }", randomInt(), randomAlphaOfLengthBetween(5, 10)));
152+
setRequestProjectId(request, projectId);
153+
client().performRequest(request);
154+
}
155+
client().performRequest(setRequestProjectId(new Request("POST", "/" + indexName + "/_refresh"), projectId));
156+
return numDocs;
157+
}
158+
159+
private static ObjectPath getAsObjectPathInProject(String endpoint, String projectId) throws IOException {
160+
return new ObjectPath(responseAsOrderedMap(client().performRequest(setRequestProjectId(new Request("GET", endpoint), projectId))));
161+
}
162+
163+
private static ObjectPath getAsObjectPathInDefaultProject(String endpoint) throws IOException {
164+
return new ObjectPath(getAsMap(endpoint));
165+
}
166+
}

0 commit comments

Comments
 (0)