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.assertNotNull;
6   import static org.junit.jupiter.api.Assertions.assertTrue;
7   
8   import java.nio.file.Files;
9   import java.nio.file.Path;
10  import java.util.UUID;
11  
12  import org.apache.solr.client.solrj.SolrClient;
13  import org.apache.solr.client.solrj.SolrQuery;
14  import org.apache.solr.client.solrj.response.QueryResponse;
15  import org.apache.solr.common.SolrDocument;
16  import org.junit.jupiter.api.BeforeAll;
17  import org.junit.jupiter.api.MethodOrderer;
18  import org.junit.jupiter.api.Order;
19  import org.junit.jupiter.api.Test;
20  import org.junit.jupiter.api.TestMethodOrder;
21  import org.junitpioneer.jupiter.SetEnvironmentVariable;
22  
23  import com.acumenvelocity.ath.common.Const;
24  import com.acumenvelocity.ath.common.JacksonUtil;
25  import com.acumenvelocity.ath.common.SolrUtil;
26  import com.acumenvelocity.ath.model.x.LayeredTextX;
27  import com.acumenvelocity.ath.solr.AthIndex;
28  import com.fasterxml.jackson.databind.JsonNode;
29  import com.fasterxml.jackson.databind.node.ObjectNode;
30  
31  @SetEnvironmentVariable(key = "ATH_SOLR_URL", value = "http://localhost:8983/solr")
32  @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
33  public class TestTranslationMemories_IT extends BaseIntegrationTest {
34  
35    private static UUID testTmId;
36    private static UUID testUserId;
37    private static UUID testSegmentId;
38  
39    @BeforeAll
40    public void setUp() throws Exception {
41      String solrUrl = System.getenv("ATH_SOLR_URL");
42      System.out.println("ATH_SOLR_URL from System.getenv: " + solrUrl);
43      
44      if (solrUrl == null) {
45        throw new IllegalStateException("ATH_SOLR_URL is not set");
46      }
47      
48      testTmId = UUID.randomUUID();
49      testUserId = UUID.randomUUID();
50      testSegmentId = UUID.randomUUID();
51  
52      AthIndex.init();
53    }
54  
55    @Test
56    @Order(1)
57    public void testCreateTranslationMemory() throws Exception {
58      Path tmxFile = createTestTmxFile();
59  
60      MultipartRequestBody body = new MultipartRequestBody();
61      body.addPart("tm_id", testTmId.toString());
62      body.addFilePart("tm_file", "test.tmx", tmxFile, "application/xml");
63      body.addPart("tm_file_name", "test.tmx");
64      body.addPart("src_lang", "en");
65      body.addPart("trg_lang", "fr");
66      body.addPart("user_id", testUserId.toString());
67  
68      HttpResponse response = sendMultipartRequest("/resources/translation-memory", body);
69  
70      assertEquals(201, response.getStatusCode(), "Expected HTTP 201");
71  
72      JsonNode json = parseJson(response.getBody());
73      assertEquals(201, json.get("code").asInt());
74  
75      // Verify segments in ATH_TM_SEGMENTS
76      SolrClient solrClient = getSolrClient();
77      SolrQuery segmentQuery = new SolrQuery("tmId:\"" + testTmId + "\"");
78      QueryResponse segResponse = solrClient.query(Const.SOLR_CORE_ATH_TM_SEGMENTS, segmentQuery);
79      assertEquals(2, segResponse.getResults().getNumFound(),
80          "Expected two segments in ATH_TM_SEGMENTS core");
81      assertEquals("en", segResponse.getResults().get(0).getFieldValue(Const.ATH_PROP_SRC_LANG));
82      assertEquals("fr", segResponse.getResults().get(0).getFieldValue(Const.ATH_PROP_TRG_LANG));
83  
84      // Verify TM metadata in ATH_TMS
85      SolrQuery tmQuery = new SolrQuery("tmId:\"" + testTmId + "\"");
86      tmQuery.setFields(
87          Const.ATH_PROP_SOLR_ID,
88          Const.ATH_PROP_TM_ID,
89          Const.ATH_PROP_TM_FILE_NAME,
90          Const.ATH_PROP_SRC_LANG,
91          Const.ATH_PROP_TRG_LANG,
92          Const.ATH_PROP_CREATED_BY,
93          Const.ATH_PROP_CREATED_AT,
94          Const.ATH_PROP_UPDATED_BY,
95          Const.ATH_PROP_UPDATED_AT);
96      QueryResponse tmResponse = solrClient.query(Const.SOLR_CORE_ATH_TMS, tmQuery);
97      assertEquals(1, tmResponse.getResults().getNumFound(), "Expected one document in ATH_TMS core");
98      SolrDocument tmDoc = tmResponse.getResults().get(0);
99      assertEquals(testTmId.toString(), tmDoc.getFieldValue(Const.ATH_PROP_TM_ID));
100     assertEquals("test.tmx", tmDoc.getFieldValue(Const.ATH_PROP_TM_FILE_NAME));
101     assertEquals("en", tmDoc.getFieldValue(Const.ATH_PROP_SRC_LANG));
102     assertEquals("fr", tmDoc.getFieldValue(Const.ATH_PROP_TRG_LANG));
103     assertEquals(testUserId.toString(), tmDoc.getFieldValue(Const.ATH_PROP_CREATED_BY));
104     assertEquals(testUserId.toString(), tmDoc.getFieldValue(Const.ATH_PROP_UPDATED_BY));
105     assertNotNull(tmDoc.getFieldValue(Const.ATH_PROP_CREATED_AT), "created_at should not be null");
106     assertNotNull(tmDoc.getFieldValue(Const.ATH_PROP_UPDATED_AT), "updated_at should not be null");
107 
108     // Verify segments count dynamically
109     long segmentsCount = SolrUtil.getNumDocuments(Const.SOLR_CORE_ATH_TM_SEGMENTS,
110         "tmId:\"" + testTmId + "\"");
111     assertEquals(2, segmentsCount, "Expected two segments in dynamic count");
112 
113     System.out.println("Created TM with ID: " + testTmId);
114   }
115 
116   @Test
117   @Order(2)
118   public void testGetTranslationMemories() throws Exception {
119     HttpResponse response = sendGetRequest("/resources/translation-memory");
120 
121     assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
122 
123     JsonNode json = parseJson(response.getBody());
124     assertTrue(json.has("translation_memories"),
125         "Response should have 'translation_memories' field");
126 
127     JsonNode tms = json.get("translation_memories");
128     assertTrue(tms.isArray(), "Translation memories should be an array");
129     assertTrue(tms.size() > 0, "Should have at least one TM");
130 
131     System.out.println("Found " + tms.size() + " translation memories");
132   }
133 
134   @Test
135   @Order(3)
136   public void testGetTranslationMemoryInfo() throws Exception {
137     HttpResponse response = sendGetRequest("/resources/translation-memory/" + testTmId + "/info");
138 
139     assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
140 
141     JsonNode json = parseJson(response.getBody());
142     assertTrue(json.has("translation_memory_info"),
143         "Response should have 'translation_memory_info' field");
144 
145     JsonNode tmInfo = json.get("translation_memory_info");
146     assertEquals(testTmId.toString(), tmInfo.get("tm_id").asText());
147     assertTrue(tmInfo.has("tm_file_name"));
148     assertEquals("en", tmInfo.get("src_lang").asText());
149     assertEquals("fr", tmInfo.get("trg_lang").asText());
150     assertTrue(tmInfo.has("segments_count"));
151     assertEquals(2, tmInfo.get("segments_count").asLong());
152 
153     System.out.println("TM segments count: " + tmInfo.get("segments_count").asLong());
154   }
155 
156   @Test
157   @Order(4)
158   public void testGetTranslationMemorySegments() throws Exception {
159     HttpResponse response = sendGetRequest(
160         "/resources/translation-memory/" + testTmId + "/segment");
161 
162     assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
163 
164     JsonNode json = parseJson(response.getBody());
165     assertTrue(json.has("tm_segments"), "Response should have 'tm_segments' field");
166 
167     JsonNode segments = json.get("tm_segments");
168     assertTrue(segments.isArray(), "Segments should be an array");
169     assertEquals(2, segments.size());
170 
171     System.out.println("Found " + segments.size() + " TM segments");
172   }
173 
174   @Test
175   @Order(5)
176   public void testCreateTranslationMemorySegment() throws Exception {
177     ObjectNode requestBody = objectMapper.createObjectNode();
178     requestBody.put("tm_seg_id", testSegmentId.toString());
179 
180     ObjectNode source = objectMapper.createObjectNode();
181     source.put("language", "en");
182     source.put("text", "Test source text");
183     source.set("codes", objectMapper.createArrayNode());
184     requestBody.set("source", source);
185 
186     ObjectNode target = objectMapper.createObjectNode();
187     target.put("language", "fr");
188     target.put("text", "Texte source de test");
189     target.set("codes", objectMapper.createArrayNode());
190     requestBody.set("target", target);
191 
192     requestBody.put("user_id", testUserId.toString());
193 
194     HttpResponse response = sendPostRequest(
195         "/resources/translation-memory/" + testTmId + "/segment", toJson(requestBody));
196 
197     assertEquals(201, response.getStatusCode(), "Expected HTTP 201");
198 
199     // Verify segment in ATH_TM_SEGMENTS
200     SolrClient solrClient = getSolrClient();
201     SolrQuery query = new SolrQuery(
202         "tmSegId:\"" + testSegmentId + "\" AND tmId:\"" + testTmId + "\"");
203     QueryResponse segResponse = solrClient.query(Const.SOLR_CORE_ATH_TM_SEGMENTS, query);
204     assertEquals(1, segResponse.getResults().size(),
205         "Expected one segment in ATH_TM_SEGMENTS core");
206 
207     System.out.println("Created TM segment with ID: " + testSegmentId);
208   }
209 
210   @Test
211   @Order(6)
212   public void testGetTranslationMemorySegment() throws Exception {
213     HttpResponse response = sendGetRequest(
214         "/resources/translation-memory/" + testTmId + "/segment/" + testSegmentId);
215 
216     assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
217 
218     JsonNode json = parseJson(response.getBody());
219     assertTrue(json.has("tm_segment"), "Response should have 'tm_segment' field");
220 
221     JsonNode segment = json.get("tm_segment");
222     assertEquals(testSegmentId.toString(), segment.get("tm_seg_id").asText());
223     assertEquals(testTmId.toString(), segment.get("tm_id").asText());
224   }
225 
226   @Test
227   @Order(7)
228   public void testUpdateTranslationMemorySegment() throws Exception {
229     ObjectNode requestBody = objectMapper.createObjectNode();
230     requestBody.put("tm_seg_id", testSegmentId.toString());
231 
232     ObjectNode target = objectMapper.createObjectNode();
233     target.put("language", "fr");
234     target.put("text", "Texte source de test modifié");
235     target.set("codes", objectMapper.createArrayNode());
236     requestBody.set("target", target);
237 
238     requestBody.put("user_id", testUserId.toString());
239 
240     HttpResponse response = sendPutRequest(
241         "/resources/translation-memory/" + testTmId + "/segment/" + testSegmentId,
242         toJson(requestBody));
243 
244     assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
245 
246     // Verify updated segment in ATH_TM_SEGMENTS
247     SolrClient solrClient = getSolrClient();
248     SolrQuery query = new SolrQuery(
249         "tmSegId:\"" + testSegmentId + "\" AND tmId:\"" + testTmId + "\"");
250     QueryResponse segResponse = solrClient.query(Const.SOLR_CORE_ATH_TM_SEGMENTS, query);
251     assertEquals(1, segResponse.getResults().size(),
252         "Expected one segment in ATH_TM_SEGMENTS core");
253     String targetJson = segResponse.getResults().get(0).getFieldValue("targetJson").toString();
254     LayeredTextX targetLt = JacksonUtil.fromJson(targetJson, LayeredTextX.class);
255     assertEquals("Texte source de test modifié", targetLt.getText());
256 
257     System.out.println("Updated TM segment");
258   }
259 
260   @Test
261   @Order(8)
262   public void testExportTranslationMemory() throws Exception {
263     HttpResponse response = sendGetRequest("/resources/translation-memory/" + testTmId);
264 
265     assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
266     assertFalse(response.getBody().isEmpty(), "Response body should not be empty");
267 
268     System.out.println("Exported TM successfully");
269   }
270 
271   @Test
272   @Order(9)
273   public void testUpdateTranslationMemory() throws Exception {
274     Path tmxFile = createTestTmxFile();
275     UUID newUserId = UUID.randomUUID(); // New user for update
276 
277     // Create multipart request body
278     MultipartRequestBody body = new MultipartRequestBody();
279     body.addFilePart("tm_file", "update.tmx", tmxFile, "application/xml");
280     body.addPart("tm_file_name", "update.tmx");
281     body.addPart("user_id", newUserId.toString());    
282 
283     HttpResponse response = sendPutMultipartRequest(
284         "/resources/translation-memory/" + testTmId, body);
285 
286     assertEquals(200, response.getStatusCode(), "Expected HTTP 200");
287 
288     JsonNode json = parseJson(response.getBody());
289     assertEquals(200, json.get("code").asInt(), "Expected response code 200");
290     
291     // Verify segments in ATH_TM_SEGMENTS
292     SolrClient solrClient = getSolrClient();
293     SolrQuery segmentQuery = new SolrQuery("tmId:\"" + testTmId + "\"");
294     QueryResponse segResponse = solrClient.query(Const.SOLR_CORE_ATH_TM_SEGMENTS, segmentQuery);
295     assertEquals(3, segResponse.getResults().getNumFound(), "Expected three segments after update (one was already there)");
296 
297     // Verify TM metadata in ATH_TMS
298     SolrQuery tmQuery = new SolrQuery("tmId:\"" + testTmId + "\"");
299     tmQuery.setFields(
300         Const.ATH_PROP_SOLR_ID,
301         Const.ATH_PROP_TM_ID,
302         Const.ATH_PROP_TM_FILE_NAME,
303         Const.ATH_PROP_SRC_LANG,
304         Const.ATH_PROP_TRG_LANG,
305         Const.ATH_PROP_CREATED_BY,
306         Const.ATH_PROP_CREATED_AT,
307         Const.ATH_PROP_UPDATED_BY,
308         Const.ATH_PROP_UPDATED_AT);
309     QueryResponse tmResponse = solrClient.query(Const.SOLR_CORE_ATH_TMS, tmQuery);
310     assertEquals(1, tmResponse.getResults().getNumFound(), "Expected one document in ATH_TMS core");
311     SolrDocument tmDoc = tmResponse.getResults().get(0);
312     assertEquals(testTmId.toString(), tmDoc.getFieldValue(Const.ATH_PROP_TM_ID));
313     assertEquals("update.tmx", tmDoc.getFieldValue(Const.ATH_PROP_TM_FILE_NAME));
314     assertNotNull(tmDoc.getFieldValue(Const.ATH_PROP_SRC_LANG), "src_lang should not be null");
315     assertNotNull(tmDoc.getFieldValue(Const.ATH_PROP_TRG_LANG), "trg_lang should not be null");
316     assertNotNull(tmDoc.getFieldValue(Const.ATH_PROP_CREATED_BY), "created_by should not be null");
317     assertNotNull(tmDoc.getFieldValue(Const.ATH_PROP_CREATED_AT), "created_at should not be null");
318     assertNotNull(tmDoc.getFieldValue(Const.ATH_PROP_UPDATED_AT), "updated_at should not be null");
319 
320     // Verify updated_by
321     UUID updatedBy = UUID.fromString(SolrUtil.safeGetField(tmDoc, Const.ATH_PROP_UPDATED_BY, null));
322     
323     assertTrue(newUserId.equals(updatedBy), "Expected updated_by to equal new user ID");
324 
325     // Verify segments count dynamically
326     long segmentsCount = SolrUtil.getNumDocuments(Const.SOLR_CORE_ATH_TM_SEGMENTS,
327         "tmId:\"" + testTmId + "\"");
328     assertEquals(3, segmentsCount, "Expected three segments in dynamic count");
329 
330     System.out.println("Updated TM with ID: " + testTmId);
331   }
332 
333   @Test
334   @Order(10)
335   public void testDeleteTranslationMemorySegment() throws Exception {
336     HttpResponse response = sendDeleteRequest(
337         "/resources/translation-memory/" + testTmId + "/segment/" + testSegmentId);
338 
339     assertEquals(204, response.getStatusCode(), "Expected HTTP 204");
340 
341     // Verify segment deletion
342     SolrClient solrClient = getSolrClient();
343     SolrQuery query = new SolrQuery(
344         "tmSegId:\"" + testSegmentId + "\" AND tmId:\"" + testTmId + "\"");
345     QueryResponse segResponse = solrClient.query(Const.SOLR_CORE_ATH_TM_SEGMENTS, query);
346     assertEquals(0, segResponse.getResults().getNumFound(),
347         "Segment should be deleted from ATH_TM_SEGMENTS core");
348 
349     System.out.println("Deleted TM segment");
350   }
351 
352   @Test
353   @Order(11)
354   public void testDeleteTranslationMemory() throws Exception {
355     HttpResponse response = sendDeleteRequest("/resources/translation-memory/" + testTmId);
356 
357     assertEquals(204, response.getStatusCode(), "Expected HTTP 204");
358 
359     // Verify deletion
360     SolrClient solrClient = getSolrClient();
361     SolrQuery query = new SolrQuery("tmId:\"" + testTmId + "\"");
362     QueryResponse segResponse = solrClient.query(Const.SOLR_CORE_ATH_TM_SEGMENTS, query);
363     assertEquals(0, segResponse.getResults().getNumFound(),
364         "Segments should be deleted from ATH_TM_SEGMENTS core");
365 
366     System.out.println("Deleted TM");
367   }
368 
369   private Path createTestTmxFile() throws Exception {
370     String tmxContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
371         "<tmx version=\"1.4\">\n" +
372         "  <header creationtool=\"test\" creationtoolversion=\"1.0\" " +
373         "datatype=\"plaintext\" segtype=\"sentence\" " +
374         "adminlang=\"en\" srclang=\"en\"/>\n" +
375         "  <body>\n" +
376         "    <tu>\n" +
377         "      <tuv xml:lang=\"en\"><seg>Hello world</seg></tuv>\n" +
378         "      <tuv xml:lang=\"fr\"><seg>Bonjour le monde</seg></tuv>\n" +
379         "    </tu>\n" +
380         "    <tu>\n" +
381         "      <tuv xml:lang=\"en\"><seg>Goodbye</seg></tuv>\n" +
382         "      <tuv xml:lang=\"fr\"><seg>Au revoir</seg></tuv>\n" +
383         "    </tu>\n" +
384         "  </body>\n" +
385         "</tmx>";
386 
387     Path tmxFile = Files.createTempFile("test", ".tmx");
388     Files.write(tmxFile, tmxContent.getBytes(java.nio.charset.StandardCharsets.UTF_8));
389     tmxFile.toFile().deleteOnExit();
390 
391     return tmxFile;
392   }
393 
394   private SolrClient getSolrClient() {
395     return AthIndex.getSolr().getClient();
396   }
397 }