Skip to content

Commit 911fa96

Browse files
authored
[ML] Yaml test that runs inference as a non-admin user (#128363) (#128395)
1 parent 7ff1f7f commit 911fa96

File tree

4 files changed

+240
-0
lines changed

4 files changed

+240
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apply plugin: 'elasticsearch.internal-yaml-rest-test'
2+
3+
dependencies {
4+
testImplementation(testArtifact(project(xpackModule('core'))))
5+
testImplementation(testArtifact(project(':server')))
6+
testImplementation(project(':x-pack:plugin:inference:qa:test-service-plugin'))
7+
testImplementation project(':modules:reindex')
8+
testImplementation project(':modules:mapper-extras')
9+
clusterPlugins project(':x-pack:plugin:inference:qa:test-service-plugin')
10+
}
11+
12+
tasks.named('yamlRestTest') {
13+
usesDefaultDistribution("to be triaged")
14+
}
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.inference;
9+
10+
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
11+
12+
import org.elasticsearch.client.Request;
13+
import org.elasticsearch.common.Strings;
14+
import org.elasticsearch.common.settings.SecureString;
15+
import org.elasticsearch.common.settings.Settings;
16+
import org.elasticsearch.common.util.concurrent.ThreadContext;
17+
import org.elasticsearch.test.cluster.ElasticsearchCluster;
18+
import org.elasticsearch.test.cluster.local.distribution.DistributionType;
19+
import org.elasticsearch.test.cluster.util.resource.Resource;
20+
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
21+
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
22+
import org.junit.After;
23+
import org.junit.ClassRule;
24+
25+
import java.io.IOException;
26+
import java.util.List;
27+
import java.util.Map;
28+
29+
public class InferenceWithSecurityRestIT extends ESClientYamlSuiteTestCase {
30+
31+
private static final String TEST_ADMIN_USERNAME = "x_pack_rest_user";
32+
private static final String TEST_ADMIN_PASSWORD = "x-pack-test-password";
33+
34+
private static final String INFERENCE_USERNAME = "inference_user";
35+
private static final String INFERENCE_PASSWORD = "inference_user_password";
36+
37+
@ClassRule
38+
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
39+
.systemProperty("tests.seed", System.getProperty("tests.seed"))
40+
.setting("xpack.security.enabled", "true")
41+
.setting("xpack.license.self_generated.type", "trial")
42+
.rolesFile(Resource.fromClasspath("roles.yml"))
43+
.user(TEST_ADMIN_USERNAME, TEST_ADMIN_PASSWORD) // admin user for setup and teardown
44+
.user(INFERENCE_USERNAME, INFERENCE_PASSWORD, "monitor_only_user", false)
45+
.plugin("inference-service-test")
46+
.distribution(DistributionType.DEFAULT)
47+
.build();
48+
49+
public InferenceWithSecurityRestIT(final ClientYamlTestCandidate testCandidate) {
50+
super(testCandidate);
51+
}
52+
53+
@Override
54+
protected Settings restClientSettings() {
55+
String token = basicAuthHeaderValue(INFERENCE_USERNAME, new SecureString(INFERENCE_PASSWORD.toCharArray()));
56+
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
57+
}
58+
59+
@Override
60+
protected Settings restAdminSettings() {
61+
String token = basicAuthHeaderValue(TEST_ADMIN_USERNAME, new SecureString(TEST_ADMIN_PASSWORD.toCharArray()));
62+
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
63+
}
64+
65+
@Override
66+
protected String getTestRestCluster() {
67+
return cluster.getHttpAddresses();
68+
}
69+
70+
@ParametersFactory
71+
public static Iterable<Object[]> parameters() throws Exception {
72+
return ESClientYamlSuiteTestCase.createParameters();
73+
}
74+
75+
@After
76+
public void cleanup() throws Exception {
77+
for (var model : getAllModels()) {
78+
var inferenceId = model.get("inference_id");
79+
try {
80+
var endpoint = Strings.format("_inference/%s?force", inferenceId);
81+
adminClient().performRequest(new Request("DELETE", endpoint));
82+
} catch (Exception ex) {
83+
logger.warn(() -> "failed to delete inference endpoint " + inferenceId, ex);
84+
}
85+
}
86+
}
87+
88+
@SuppressWarnings("unchecked")
89+
static List<Map<String, Object>> getAllModels() throws IOException {
90+
var request = new Request("GET", "_inference/_all");
91+
var response = client().performRequest(request);
92+
return (List<Map<String, Object>>) entityAsMap(response).get("endpoints");
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
setup:
2+
- skip:
3+
features:
4+
- close_to
5+
- requires:
6+
test_runner_features: "close_to"
7+
8+
- do:
9+
inference.put:
10+
task_type: rerank
11+
inference_id: my-rerank-model
12+
body: >
13+
{
14+
"service": "test_reranking_service",
15+
"service_settings": {
16+
"model_id": "my_model",
17+
"api_key": "abc64"
18+
},
19+
"task_settings": {
20+
}
21+
}
22+
23+
- do:
24+
indices.create:
25+
index: test-index
26+
body:
27+
mappings:
28+
properties:
29+
text:
30+
type: text
31+
topic:
32+
type: keyword
33+
subtopic:
34+
type: keyword
35+
inference_text_field:
36+
type: text
37+
38+
- do:
39+
index:
40+
index: test-index
41+
id: doc_2
42+
body:
43+
text: "The phases of the Moon come from the position of the Moon relative to the Earth and Sun."
44+
topic: [ "science" ]
45+
subtopic: [ "astronomy" ]
46+
inference_text_field: "0"
47+
refresh: true
48+
49+
- do:
50+
index:
51+
index: test-index
52+
id: doc_3
53+
body:
54+
text: "Sun Moon Lake is a lake in Nantou County, Taiwan. It is the largest lake in Taiwan."
55+
topic: [ "geography" ]
56+
inference_text_field: "1"
57+
refresh: true
58+
59+
- do:
60+
index:
61+
index: test-index
62+
id: doc_1
63+
body:
64+
text: "As seen from Earth, a solar eclipse happens when the Moon is directly between the Earth and the Sun."
65+
topic: [ "science" ]
66+
subtopic: [ "technology" ]
67+
inference_text_field: "-1"
68+
refresh: true
69+
70+
---
71+
"Simple text similarity rank retriever":
72+
73+
- requires:
74+
cluster_features: "test_reranking_service.parse_text_as_score"
75+
reason: test_reranking_service can now parse provided input as score to provide deterministic ranks
76+
77+
- do:
78+
search:
79+
index: test-index
80+
body:
81+
track_total_hits: true
82+
fields: [ "text", "topic" ]
83+
retriever:
84+
text_similarity_reranker:
85+
retriever:
86+
# this one returns docs 1 and 2
87+
standard:
88+
query:
89+
bool: {
90+
should: [
91+
{
92+
constant_score: {
93+
filter: {
94+
term: {
95+
subtopic: "technology"
96+
}
97+
},
98+
boost: 10
99+
}
100+
},
101+
{
102+
constant_score: {
103+
filter: {
104+
term: {
105+
subtopic: "astronomy"
106+
}
107+
},
108+
boost: 1
109+
}
110+
}
111+
]
112+
}
113+
rank_window_size: 10
114+
inference_id: my-rerank-model
115+
inference_text: "How often does the moon hide the sun?"
116+
field: inference_text_field
117+
size: 10
118+
119+
- match: { hits.total.value: 2 }
120+
- length: { hits.hits: 2 }
121+
122+
- match: { hits.hits.0._id: "doc_2" }
123+
- match: { hits.hits.1._id: "doc_1" }
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
monitor_only_user:
2+
cluster:
3+
- monitor
4+
- manage_inference
5+
indices:
6+
- names: [ 'test-index*' ]
7+
privileges:
8+
- all

0 commit comments

Comments
 (0)