View Javadoc
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      // Wait for import to complete
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     // Store first segment ID for later tests
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     // Verify segment in ATH_DOC_SEGMENTS
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     // Wait for export to complete
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     // Create a new document
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     // Try to download before export
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     // Wait for re-import to complete
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 }