1 package com.acumenvelocity.ath.integration;
2
3 import static org.junit.jupiter.api.Assertions.assertEquals;
4 import static org.junit.jupiter.api.Assertions.assertFalse;
5 import static org.junit.jupiter.api.Assertions.assertTrue;
6
7 import java.nio.file.Files;
8 import java.nio.file.Path;
9 import java.util.UUID;
10
11 import org.apache.solr.client.solrj.SolrClient;
12 import org.apache.solr.client.solrj.SolrQuery;
13 import org.apache.solr.client.solrj.response.QueryResponse;
14 import org.junit.jupiter.api.BeforeAll;
15 import org.junit.jupiter.api.MethodOrderer;
16 import org.junit.jupiter.api.Order;
17 import org.junit.jupiter.api.Test;
18 import org.junit.jupiter.api.TestMethodOrder;
19
20 import com.acumenvelocity.ath.common.Const;
21 import com.acumenvelocity.ath.solr.AthIndex;
22 import com.fasterxml.jackson.databind.JsonNode;
23 import com.fasterxml.jackson.databind.node.ObjectNode;
24
25 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
26 public class TestDocuments_IT extends BaseIntegrationTest {
27
28 private static UUID testDocId;
29 private static UUID testUserId;
30 private static UUID testSegmentId;
31 private static String testStorageName;
32 private static String testOutStorageName;
33
34 @BeforeAll
35 public void setUp() throws Exception {
36 String solrUrl = System.getenv("ATH_SOLR_URL");
37 System.out.println("ATH_SOLR_URL from System.getenv: " + solrUrl);
38
39 if (solrUrl == null) {
40 throw new IllegalStateException("ATH_SOLR_URL is not set");
41 }
42
43 testDocId = UUID.randomUUID();
44 testUserId = UUID.randomUUID();
45 testSegmentId = UUID.randomUUID();
46 testStorageName = "test-doc-" + testDocId + ".txt";
47 testOutStorageName = "test-doc-out-" + testDocId + ".txt";
48
49 AthIndex.init();
50 }
51
52 @Test
53 @Order(1)
54 public void testImportDocument() throws Exception {
55 Path testFile = createTestDocument();
56
57 MultipartRequestBody body = new MultipartRequestBody();
58 body.addPart("doc_id", testDocId.toString());
59 body.addFilePart("doc_file", "test.txt", testFile, "text/plain");
60 body.addPart("doc_file_name", "test.txt");
61 body.addPart("doc_storage_name", testStorageName);
62 body.addPart("doc_file_encoding", "UTF-8");
63 body.addPart("src_lang", "en");
64 body.addPart("trg_lang", "fr");
65 body.addPart("user_id", testUserId.toString());
66
67 HttpResponse response = sendMultipartRequest("/document", body);
68
69 assertEquals(202, response.getStatusCode(), "Expected HTTP 202 Accepted");
70
71 JsonNode json = parseJson(response.getBody());
72 assertEquals("IMPORTING", json.get("status").asText());
73 assertEquals(testDocId.toString(), json.get("doc_id").asText());
74 assertTrue(json.has("status_url"));
75
76
77 String statusUrl = json.get("status_url").asText();
78 waitForAsyncOperation(statusUrl, 60);
79
80 System.out.println("Imported document with ID: " + testDocId);
81 }
82
83 @Test
84 @Order(2)
85 public void testGetDocuments() throws Exception {
86 HttpResponse response = sendGetRequest("/document");
87
88 assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
89
90 JsonNode json = parseJson(response.getBody());
91 assertTrue(json.has("documents"), "Response should have 'documents' field");
92
93 JsonNode docs = json.get("documents");
94 assertTrue(docs.isArray(), "Documents should be an array");
95 assertTrue(docs.size() > 0, "Should have at least one document");
96
97 System.out.println("Found " + docs.size() + " documents");
98 }
99
100 @Test
101 @Order(3)
102 public void testGetDocumentStatus() throws Exception {
103 HttpResponse response = sendGetRequest("/document/" + testDocId + "/status");
104
105 assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
106
107 JsonNode json = parseJson(response.getBody());
108 assertEquals("IMPORT_COMPLETED", json.get("status").asText());
109 assertEquals(testDocId.toString(), json.get("doc_id").asText());
110 assertTrue(json.has("completed_at"));
111 assertTrue(json.has("export_url"));
112
113 System.out.println("Document import completed");
114 }
115
116 @Test
117 @Order(4)
118 public void testGetDocumentSegments() throws Exception {
119 HttpResponse response = sendGetRequest("/document/" + testDocId + "/segment");
120
121 assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
122
123 JsonNode json = parseJson(response.getBody());
124 assertTrue(json.has("document_segments"), "Response should have 'document_segments' field");
125
126 JsonNode segments = json.get("document_segments");
127 assertTrue(segments.isArray(), "Segments should be an array");
128 assertTrue(segments.size() > 0, "Should have at least one segment");
129
130
131 if (segments.size() > 0) {
132 testSegmentId = UUID.fromString(segments.get(0).get("doc_seg_id").asText());
133 }
134
135 System.out.println("Found " + segments.size() + " document segments");
136 }
137
138 @Test
139 @Order(5)
140 public void testGetDocumentSegment() throws Exception {
141 HttpResponse response = sendGetRequest(
142 "/document/" + testDocId + "/segment/" + testSegmentId);
143
144 assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
145
146 JsonNode json = parseJson(response.getBody());
147 assertTrue(json.has("document_segment"), "Response should have 'document_segment' field");
148
149 JsonNode segment = json.get("document_segment");
150 assertEquals(testSegmentId.toString(), segment.get("doc_seg_id").asText());
151 assertEquals(testDocId.toString(), segment.get("doc_id").asText());
152 assertTrue(segment.has("source"));
153 assertTrue(segment.has("target"));
154 assertTrue(segment.has("position"));
155 assertTrue(segment.has("origin"));
156 }
157
158 @Test
159 @Order(6)
160 public void testUpdateDocumentSegment() throws Exception {
161 ObjectNode requestBody = objectMapper.createObjectNode();
162
163 ObjectNode target = objectMapper.createObjectNode();
164 target.put("language", "fr");
165 target.put("text", "Ceci est un texte de test modifié");
166 target.set("codes", objectMapper.createArrayNode());
167 requestBody.set("target", target);
168
169 requestBody.put("origin", "HT");
170 requestBody.put("user_id", testUserId.toString());
171
172 HttpResponse response = sendPutRequest(
173 "/document/" + testDocId + "/segment/" + testSegmentId,
174 toJson(requestBody));
175
176 assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
177 System.out.println("Updated document segment");
178 }
179
180 @Test
181 @Order(7)
182 public void testCreateDocumentSegment() throws Exception {
183 ObjectNode requestBody = objectMapper.createObjectNode();
184
185 ObjectNode source = objectMapper.createObjectNode();
186 source.put("language", "en");
187 source.put("text", "New segment source");
188 source.set("codes", objectMapper.createArrayNode());
189 source.put("textWithCodes", "New segment source");
190 requestBody.set("source", source);
191
192 ObjectNode target = objectMapper.createObjectNode();
193 target.put("language", "fr");
194 target.put("text", "Nouvelle source de segment");
195 target.set("codes", objectMapper.createArrayNode());
196 target.put("textWithCodes", "Nouvelle source de segment");
197 requestBody.set("target", target);
198
199 requestBody.put("position", 999);
200 requestBody.put("origin", "HT");
201 requestBody.put("user_id", testUserId.toString());
202
203 HttpResponse response = sendPostRequest(
204 "/document/" + testDocId + "/segment",
205 toJson(requestBody));
206
207 assertEquals(201, response.getStatusCode(), "Expected HTTP 201");
208
209
210 SolrClient solrClient = getSolrClient();
211
212 SolrQuery query = new SolrQuery(
213 "docSegId:\"" + testSegmentId + "\" AND docId:\"" + testDocId + "\"");
214
215 QueryResponse segResponse = solrClient.query(Const.SOLR_CORE_ATH_DOC_SEGMENTS, query);
216
217 assertEquals(1, segResponse.getResults().size(),
218 "Expected one segment in ATH_DOC_SEGMENTS core");
219
220 System.out.println("Created new document segment with ID: " + testSegmentId);
221 }
222
223 @Test
224 @Order(8)
225 public void testExportDocument() throws Exception {
226 ObjectNode requestBody = objectMapper.createObjectNode();
227 requestBody.put("doc_out_storage_name", testOutStorageName);
228 requestBody.put("user_id", testUserId.toString());
229
230 HttpResponse response = sendPostRequest(
231 "/document/" + testDocId + "/export",
232 toJson(requestBody));
233
234 assertEquals(202, response.getStatusCode(), "Expected HTTP 202 Accepted");
235
236 JsonNode json = parseJson(response.getBody());
237 assertEquals("EXPORTING", json.get("status").asText());
238
239
240 String statusUrl = json.get("status_url").asText();
241 waitForAsyncOperation(statusUrl, 60);
242
243 System.out.println("Document export initiated");
244 }
245
246 @Test
247 @Order(9)
248 public void testDownloadDocument() throws Exception {
249 HttpResponse response = sendGetRequest("/document/" + testDocId);
250
251 assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
252 assertFalse(response.getBody().isEmpty(), "Downloaded document should not be empty");
253
254 System.out.println("Downloaded translated document");
255 }
256
257 @Test
258 @Order(10)
259 public void testDownloadDocumentBeforeExport() throws Exception {
260
261 UUID newDocId = UUID.randomUUID();
262 Path testFile = createTestDocument();
263
264 MultipartRequestBody body = new MultipartRequestBody();
265 body.addPart("doc_id", newDocId.toString());
266 body.addFilePart("doc_file", "test2.txt", testFile, "text/plain");
267 body.addPart("doc_file_name", "test2.txt");
268 body.addPart("doc_storage_name", "test-doc-" + newDocId + ".txt");
269 body.addPart("doc_file_encoding", "UTF-8");
270 body.addPart("src_lang", "en");
271 body.addPart("trg_lang", "fr");
272 body.addPart("user_id", testUserId.toString());
273
274 sendMultipartRequest("/document", body);
275 waitForAsyncOperation("/document/" + newDocId + "/status", 60);
276
277
278 HttpResponse response = sendGetRequest("/document/" + newDocId);
279
280 assertEquals(409, response.getStatusCode(), "Expected HTTP 409 Conflict");
281
282 JsonNode json = parseJson(response.getBody());
283 assertEquals("Document not ready for download", json.get("error").asText());
284 assertEquals("IMPORT_COMPLETED", json.get("status").asText());
285
286 System.out.println("Correctly prevented download before export");
287 }
288
289 @Test
290 @Order(11)
291 public void testDeleteDocumentSegment() throws Exception {
292 HttpResponse response = sendDeleteRequest(
293 "/document/" + testDocId + "/segment/" + testSegmentId);
294
295 assertEquals(204, response.getStatusCode(), "Expected HTTP 204");
296
297 System.out.println("Deleted document segment");
298 }
299
300 @Test
301 @Order(12)
302 public void testReimportDocument() throws Exception {
303 ObjectNode requestBody = objectMapper.createObjectNode();
304 requestBody.put("user_id", testUserId.toString());
305
306 HttpResponse response = sendPutRequest(
307 "/document/" + testDocId,
308 toJson(requestBody));
309
310 assertEquals(202, response.getStatusCode(), "Expected HTTP 202 Accepted");
311
312 JsonNode json = parseJson(response.getBody());
313 assertEquals("IMPORTING", json.get("status").asText());
314
315
316 String statusUrl = json.get("status_url").asText();
317 waitForAsyncOperation(statusUrl, 60);
318
319 System.out.println("Re-imported document");
320 }
321
322 @Test
323 @Order(13)
324 public void testDeleteDocument() throws Exception {
325 HttpResponse response = sendDeleteRequest("/document/" + testDocId);
326
327 assertEquals(204, response.getStatusCode(), "Expected HTTP 204");
328
329 System.out.println("Deleted document");
330 }
331
332 private Path createTestDocument() throws Exception {
333 String content = "This is a test document.\n" +
334 "It has multiple lines.\n" +
335 "Each line will be segmented.";
336
337 Path file = Files.createTempFile("test-doc", ".txt");
338 Files.write(file, content.getBytes(java.nio.charset.StandardCharsets.UTF_8));
339 file.toFile().deleteOnExit();
340
341 return file;
342 }
343
344 private SolrClient getSolrClient() {
345 return AthIndex.getSolr().getClient();
346 }
347 }