Skip to content

Commit e11ef3e

Browse files
authored
[app-builder] fix: avoid NullPointerException for unknown HTTP status codes (#595) (#596)
1 parent 915c97e commit e11ef3e

File tree

8 files changed

+311
-4
lines changed

8 files changed

+311
-4
lines changed

app-builder/plugins/data-mate-knowledge/src/main/java/modelengine/fit/jade/datamate/knowledge/external/DataMateKnowledgeBaseManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,9 @@ public DataMateRetrievalResult retrieve(String apiKey, DataMateRetrievalParam pa
136136

137137
private KnowledgeException handleException(HttpClientResponseException ex) {
138138
int statusCode = ex.statusCode();
139-
log.error(this.exceptionMap.get(statusCode).getMsg(), ex);
140-
return new KnowledgeException(this.exceptionMap.get(statusCode), ex, ex.getSimpleMessage());
139+
KnowledgeManagerRetCode retCode = this.exceptionMap.getOrDefault(statusCode, INTERNAL_SERVICE_ERROR);
140+
log.error(retCode.getMsg(), ex);
141+
return new KnowledgeException(retCode, ex, ex.getSimpleMessage());
141142
}
142143

143144
private HttpClassicClient getHttpClient() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
package modelengine.fit.jade.datamate.knowledge;
8+
9+
import modelengine.fit.http.client.HttpClassicClientResponse;
10+
import modelengine.fitframework.annotation.Fit;
11+
import modelengine.fitframework.test.annotation.MvcTest;
12+
import modelengine.fitframework.test.domain.mvc.MockMvc;
13+
import modelengine.fit.jade.datamate.knowledge.dto.DataMateKnowledgeListQueryParam;
14+
import modelengine.fit.jade.datamate.knowledge.dto.DataMateRetrievalParam;
15+
import modelengine.fit.jade.datamate.knowledge.entity.DataMateKnowledgeEntity;
16+
import modelengine.fit.jade.datamate.knowledge.entity.DataMateKnowledgeListEntity;
17+
import modelengine.fit.jade.datamate.knowledge.entity.DataMateRetrievalChunksEntity;
18+
import modelengine.fit.jade.datamate.knowledge.entity.DataMateRetrievalResult;
19+
import modelengine.fit.jade.datamate.knowledge.external.DataMateKnowledgeBaseManager;
20+
import modelengine.jade.knowledge.exception.KnowledgeException;
21+
22+
import org.junit.jupiter.api.AfterEach;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.DisplayName;
25+
import org.junit.jupiter.api.Test;
26+
27+
import static org.assertj.core.api.Assertions.assertThat;
28+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
29+
30+
import java.io.IOException;
31+
import java.lang.reflect.Field;
32+
import java.util.HashMap;
33+
import java.util.Map;
34+
35+
/**
36+
* 表示 {@link DataMateKnowledgeBaseManager} 的测试集。
37+
*
38+
* @author songyongtan
39+
* @since 2026-02-11
40+
*/
41+
@MvcTest(classes = {MockedDataMateKnowledgeBaseInnerController.class, DataMateKnowledgeBaseManager.class})
42+
public class DataMateKnowledgeBaseManagerTest {
43+
private String apiKey = "123";
44+
45+
@Fit
46+
DataMateKnowledgeBaseManager manager;
47+
48+
@Fit
49+
private MockMvc mockMvc;
50+
51+
private HttpClassicClientResponse<?> response;
52+
53+
@BeforeEach
54+
void setUp() throws Exception {
55+
Field dataMateUrls = manager.getClass().getDeclaredField("dataMateUrls");
56+
dataMateUrls.setAccessible(true);
57+
Map<String, String> urls = new HashMap<>();
58+
urls.put("list", "http://localhost:" + mockMvc.getPort() + "/v2/knowledgeBase");
59+
urls.put("retrieve", "http://localhost:" + mockMvc.getPort() + "/v2/knowledgebases/query");
60+
dataMateUrls.set(manager, urls);
61+
}
62+
63+
@AfterEach
64+
void teardown() throws IOException {
65+
if (this.response != null) {
66+
this.response.close();
67+
}
68+
}
69+
70+
@Test
71+
@DisplayName("查询知识库列表成功")
72+
public void shouldOkWhenListRepo() {
73+
DataMateKnowledgeListQueryParam param = DataMateKnowledgeListQueryParam.builder().name("ok").build();
74+
DataMateKnowledgeListEntity entity = this.manager.listRepos(apiKey, param);
75+
assertThat(entity.getContent().size()).isEqualTo(2);
76+
assertThat(entity.getContent().get(0)).extracting(DataMateKnowledgeEntity::getId,
77+
DataMateKnowledgeEntity::getName,
78+
DataMateKnowledgeEntity::getDescription).containsExactly("1", "test1", "test1知识库");
79+
assertThat(entity.getContent().get(1)).extracting(DataMateKnowledgeEntity::getId,
80+
DataMateKnowledgeEntity::getName,
81+
DataMateKnowledgeEntity::getDescription).containsExactly("2", "test2", "test2知识库");
82+
}
83+
84+
@Test
85+
@DisplayName("查询知识库列表失败,抛出异常")
86+
public void shouldFailWhenListRepoThrowException() {
87+
DataMateKnowledgeListQueryParam param = DataMateKnowledgeListQueryParam.builder().name("error").build();
88+
assertThatThrownBy(() -> this.manager.listRepos(apiKey, param)).isInstanceOf(KnowledgeException.class)
89+
.extracting("code")
90+
.isEqualTo(130703005);
91+
}
92+
93+
@Test
94+
@DisplayName("检索知识库成功")
95+
public void shouldOkWhenRetrieve() {
96+
DataMateRetrievalParam param = DataMateRetrievalParam.builder().query("ok").build();
97+
DataMateRetrievalResult result = this.manager.retrieve(apiKey, param);
98+
assertThat(result.getData().size()).isEqualTo(3);
99+
assertThat(result.getData().get(0).chunkId()).isEqualTo("chunk1");
100+
assertThat(result.getData().get(0).content()).isEqualTo("content1");
101+
}
102+
103+
@Test
104+
@DisplayName("检索知识库失败,抛出异常")
105+
public void shouldFailWhenRetrieveThrowException() {
106+
DataMateRetrievalParam param = DataMateRetrievalParam.builder().query("error").build();
107+
assertThatThrownBy(() -> this.manager.retrieve(apiKey, param)).isInstanceOf(KnowledgeException.class)
108+
.extracting("code")
109+
.isEqualTo(130703005);
110+
}
111+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
package modelengine.fit.jade.datamate.knowledge;
8+
9+
import static modelengine.fitframework.util.IoUtils.content;
10+
11+
import modelengine.fit.http.annotation.PostMapping;
12+
import modelengine.fit.http.annotation.RequestBody;
13+
import modelengine.fit.http.annotation.RequestMapping;
14+
import modelengine.fit.http.client.HttpClientException;
15+
import modelengine.fitframework.annotation.Component;
16+
import modelengine.fitframework.serialization.ObjectSerializer;
17+
import modelengine.fit.jade.datamate.knowledge.entity.DataMateResponse;
18+
19+
import java.io.IOException;
20+
import java.util.Map;
21+
22+
/**
23+
* 表示 DataMate 内部接口的打桩实现。
24+
*
25+
* @author songyongtan
26+
* @since 2026-02-11
27+
*/
28+
@Component
29+
@RequestMapping(path = "/v2", group = "DataMate知识库内部接口打桩")
30+
public class MockedDataMateKnowledgeBaseInnerController {
31+
private final ObjectSerializer serializer;
32+
33+
public MockedDataMateKnowledgeBaseInnerController(ObjectSerializer serializer) {
34+
this.serializer = serializer;
35+
}
36+
37+
@PostMapping(path = "/knowledgeBase")
38+
public Map<String, Object> listRepos(@RequestBody MockedDataMateKnowledgeListQueryParam param) throws IOException {
39+
if (param.getName().equals("error")) {
40+
throw new HttpClientException("error");
41+
}
42+
String resourceName = "/listRepoResult.json";
43+
String jsonContent = content(DataMateResponse.class, resourceName);
44+
return serializer.deserialize(jsonContent, Map.class);
45+
}
46+
47+
@PostMapping(path = "/knowledgebases/query")
48+
public Map<String, Object> retrieve(@RequestBody MockedDataMateRetrievalParam param) throws IOException {
49+
if (param.getQuery().equals("error")) {
50+
throw new HttpClientException("error");
51+
}
52+
String resourceName = "/retrieveResult.json";
53+
String jsonContent = content(DataMateResponse.class, resourceName);
54+
return serializer.deserialize(jsonContent, Map.class);
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*/
6+
7+
package modelengine.fit.jade.datamate.knowledge;
8+
9+
import lombok.Data;
10+
import modelengine.fitframework.serialization.annotation.SerializeStrategy;
11+
12+
/**
13+
* 表示 {@link modelengine.fit.jade.datamate.knowledge.dto.DataMateKnowledgeListQueryParam} 类的测试类实现。
14+
*
15+
* @author songyongtan
16+
* @since 2026-02-11
17+
*/
18+
@Data
19+
@SerializeStrategy(include = SerializeStrategy.Include.NON_NULL)
20+
public class MockedDataMateKnowledgeListQueryParam {
21+
/**
22+
* 页码,从0开始。
23+
*/
24+
private Integer page;
25+
26+
/**
27+
* 每页大小。
28+
*/
29+
private Integer size;
30+
31+
/**
32+
* 知识库名称过滤。
33+
*/
34+
private String name;
35+
36+
/**
37+
* 知识库描述过滤。
38+
*/
39+
private String description;
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*/
6+
7+
package modelengine.fit.jade.datamate.knowledge;
8+
9+
import lombok.Data;
10+
import modelengine.fitframework.annotation.Property;
11+
12+
import java.util.List;
13+
14+
/**
15+
* 表示 {@link modelengine.fit.jade.datamate.knowledge.dto.DataMateRetrievalParam} 类的测试类实现。
16+
*
17+
* @author songyongtan
18+
* @since 2026-02-11
19+
*/
20+
@Data
21+
public class MockedDataMateRetrievalParam {
22+
/**
23+
* 检索 query。
24+
*/
25+
private String query;
26+
/**
27+
* 返回前多少的条目。
28+
*/
29+
@Property(description = "topK", name = "topK")
30+
private Integer topK;
31+
/**
32+
* 相关性阈值。
33+
*/
34+
@Property(description = "threshold", name = "threshold")
35+
private Double threshold;
36+
/**
37+
* 指定知识库的id集合。
38+
*/
39+
@Property(description = "knowledgeBaseIds", name = "knowledgeBaseIds")
40+
private List<String> knowledgeBaseIds;
41+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"data": {
3+
"page": 0,
4+
"size": 2,
5+
"totalElements": 2,
6+
"totalPages": 1,
7+
"content": [
8+
{
9+
"id": "1",
10+
"name": "test1",
11+
"description": "test1知识库",
12+
"createdAt": "2025-04-22T14:27:17Z"
13+
},
14+
{
15+
"id": "2",
16+
"name": "test2",
17+
"description": "test2知识库",
18+
"createdAt": "2023-10-25T08:06:19Z"
19+
}
20+
]
21+
},
22+
"code": "0",
23+
"message": "success"
24+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"data": [
3+
{
4+
"entity": {
5+
"id": "chunk1",
6+
"text": "content1",
7+
"metadata": "{}"
8+
},
9+
"score": 0.9,
10+
"primaryKey": "id"
11+
},
12+
{
13+
"entity": {
14+
"id": "chunk2",
15+
"text": "content2",
16+
"metadata": "{}"
17+
},
18+
"score": 0.8,
19+
"primaryKey": "id"
20+
},
21+
{
22+
"entity": {
23+
"id": "chunk3",
24+
"text": "content3",
25+
"metadata": "{}"
26+
},
27+
"score": 0.7,
28+
"primaryKey": "id"
29+
}
30+
],
31+
"code": "0",
32+
"message": "success"
33+
}

app-builder/plugins/qianfan-knowledge/src/main/java/modelengine/jade/knowledge/external/QianfanKnowledgeBaseManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,9 @@ public QianfanRetrievalResult retrieve(String apiKey, QianfanRetrievalParam para
119119

120120
private KnowledgeException handleException(HttpClientResponseException ex) {
121121
int statusCode = ex.statusCode();
122-
log.error(this.exceptionMap.get(statusCode).getMsg(), ex);
123-
return new KnowledgeException(this.exceptionMap.get(statusCode), ex.getSimpleMessage());
122+
KnowledgeManagerRetCode retCode = this.exceptionMap.getOrDefault(statusCode, INTERNAL_SERVICE_ERROR);
123+
log.error(retCode.getMsg(), ex);
124+
return new KnowledgeException(retCode, ex.getSimpleMessage());
124125
}
125126

126127
private HttpClassicClient getHttpClient() {

0 commit comments

Comments
 (0)