Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
import com.crowdin.client.core.model.ClientConfig;
import com.crowdin.client.core.model.Credentials;
import com.crowdin.client.core.model.ResponseList;
import com.crowdin.client.core.model.ResponseObject;
import com.crowdin.client.translationstatus.model.Category;
import com.crowdin.client.translationstatus.model.FileBranchProgress;
import com.crowdin.client.translationstatus.model.FileProgressResponseList;
import com.crowdin.client.translationstatus.model.LanguageProgress;
import com.crowdin.client.translationstatus.model.LanguageProgressResponseList;
import com.crowdin.client.translationstatus.model.QaCheck;
import com.crowdin.client.translationstatus.model.QaCheckResponseList;
import com.crowdin.client.translationstatus.model.QaCheckRevalidation;
import com.crowdin.client.translationstatus.model.QaCheckRevalidationRequest;
import com.crowdin.client.translationstatus.model.QaCheckRevalidationResponseObject;
import com.crowdin.client.translationstatus.model.Validation;

import java.util.Map;
Expand Down Expand Up @@ -152,4 +156,46 @@ public ResponseList<QaCheck> listQaCheckIssues(Long projectId, Integer limit, In
QaCheckResponseList qaCheckResponseList = this.httpClient.get(builtUrl, new HttpRequestConfig(queryParams), QaCheckResponseList.class);
return QaCheckResponseList.to(qaCheckResponseList);
}

/**
* @param projectId project identifier
* @param revalidationId qa checks revalidation identifier
* @return status of qa checks revalidation job
* @see <ul>
* <li><a href="https://support.crowdin.com/developer/api/v2/#operation/api.projects.qa-checks.revalidate.get" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://support.crowdin.com/developer/enterprise/api/v2/#operation/api.projects.qa-checks.revalidate.get" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public ResponseObject<QaCheckRevalidation> getQaChecksRevalidationStatus(Long projectId, String revalidationId) throws HttpException, HttpBadRequestException {
QaCheckRevalidationResponseObject qaCheckRevalidationResponseObject = this.httpClient.get(this.url + "/projects/" + projectId + "/qa-checks/revalidate/" + revalidationId, new HttpRequestConfig(), QaCheckRevalidationResponseObject.class);

return ResponseObject.of(qaCheckRevalidationResponseObject.getData());
}

/**
* @param projectId project identifier
* @param request QaCheckRevalidationRequest
* @return QaCheckRevalidation
* @see <ul>
* <li><a href="https://support.crowdin.com/developer/api/v2/#operation/api.projects.qa-checks.revalidate.post" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://support.crowdin.com/developer/enterprise/api/v2/#operation/api.projects.qa-checks.revalidate.post" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public ResponseObject<QaCheckRevalidation> revalidateQaChecks(Long projectId, QaCheckRevalidationRequest request) throws HttpException, HttpBadRequestException {
QaCheckRevalidationResponseObject qaCheckRevalidationResponseObject = this.httpClient.post(this.url + "/projects/" + projectId + "/qa-checks/revalidate", request, new HttpRequestConfig(), QaCheckRevalidationResponseObject.class);

return ResponseObject.of(qaCheckRevalidationResponseObject.getData());
}

/**
* @param projectId project identifier
* @param revalidationId qa checks revalidation identifier
* @see <ul>
* <li><a href="https://support.crowdin.com/developer/api/v2/#operation/api.projects.qa-checks.revalidate.delete" target="_blank"><b>API Documentation</b></a></li>
* <li><a href="https://support.crowdin.com/developer/enterprise/api/v2/#operation/api.projects.qa-checks.revalidate.delete" target="_blank"><b>Enterprise API Documentation</b></a></li>
* </ul>
*/
public void cancelQaChecksRevalidation(Long projectId, String revalidationId) throws HttpException, HttpBadRequestException {
this.httpClient.delete(this.url + "/projects/" + projectId + "/qa-checks/revalidate/" + revalidationId, new HttpRequestConfig(), Void.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.crowdin.client.translationstatus.model;

import lombok.Data;

import java.util.Date;
import java.util.List;

@Data
public class QaCheckRevalidation {
private String identifier;
private String status;
private Long progress;
private Attributes attributes;
private Date createdAt;
private Date updatedAt;
private Date startedAt;
private Date finishedAt;

@Data
public static class Attributes {
private List<String> languageIds;
private List<String> qaCheckCategories;
private Boolean failedOnly;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.crowdin.client.translationstatus.model;

import lombok.Data;

import java.util.List;

@Data
public class QaCheckRevalidationRequest {

private List<String> qaCheckCategories;
private List<String> languageIds;
private Boolean failedOnly;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.crowdin.client.translationstatus.model;

import lombok.Data;

@Data
public class QaCheckRevalidationResponseObject {

private QaCheckRevalidation data;
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
package com.crowdin.client.translationstatus;

import com.crowdin.client.core.model.ResponseList;
import com.crowdin.client.core.model.ResponseObject;
import com.crowdin.client.framework.RequestMock;
import com.crowdin.client.framework.TestClient;
import com.crowdin.client.translationstatus.model.FileBranchProgress;
import com.crowdin.client.translationstatus.model.LanguageProgress;
import com.crowdin.client.translationstatus.model.QaCheck;
import com.crowdin.client.translationstatus.model.QaCheckRevalidation;
import com.crowdin.client.translationstatus.model.QaCheckRevalidationRequest;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class TranslationStatusApiTest extends TestClient {

private final Long projectId = 2L;
private final String revalidationId = "b5215a34-1305-4b21-8054-fc2eb252842f";
private final Long branchId = 3L;
private final Long directoryId = 4L;
private final Long fileId = 5L;
Expand All @@ -30,7 +39,10 @@ public List<RequestMock> getMocks() {
RequestMock.build(this.url + "/projects/" + projectId + "/files/" + fileId + "/languages/progress", HttpGet.METHOD_NAME, "api/translationstatus/fileProgress.json"),
RequestMock.build(this.url + "/projects/" + projectId + "/languages/" + languageId + "/progress", HttpGet.METHOD_NAME, "api/translationstatus/languageProgress.json"),
RequestMock.build(this.url + "/projects/" + projectId + "/languages/progress", HttpGet.METHOD_NAME, "api/translationstatus/projectProgress.json"),
RequestMock.build(this.url + "/projects/" + projectId + "/qa-checks", HttpGet.METHOD_NAME, "api/translationstatus/listQaChecks.json")
RequestMock.build(this.url + "/projects/" + projectId + "/qa-checks", HttpGet.METHOD_NAME, "api/translationstatus/listQaChecks.json"),
RequestMock.build(this.url + "/projects/" + projectId + "/qa-checks/revalidate/" + revalidationId, HttpGet.METHOD_NAME, "api/translationstatus/qaChecksRevalidation.json"),
RequestMock.build(this.url + "/projects/" + projectId + "/qa-checks/revalidate", HttpPost.METHOD_NAME, "api/translationstatus/qaChecksRevalidationRequest.json","api/translationstatus/qaChecksRevalidation.json"),
RequestMock.build(this.url + "/projects/" + projectId + "/qa-checks/revalidate/" + revalidationId, HttpDelete.METHOD_NAME)
);
}

Expand Down Expand Up @@ -80,4 +92,37 @@ public void listQaCheckIssuesTest() {
assertEquals(qaCheckResponseList.getData().size(), 1);
assertEquals(qaCheckResponseList.getData().get(0).getData().getLanguageId(), languageId);
}

@Test
public void getQaChecksRevalidationStatusTest() {
ResponseObject<QaCheckRevalidation> qaCheckRevalidationResponseObject = this.getTranslationStatusApi().getQaChecksRevalidationStatus(projectId, revalidationId);
assertEquals(qaCheckRevalidationResponseObject.getData().getStatus(), "created");
assertEquals(qaCheckRevalidationResponseObject.getData().getProgress(), 0L);
assertEquals(qaCheckRevalidationResponseObject.getData().getAttributes().getLanguageIds(), Arrays.asList("uk", "fr"));
assertEquals(qaCheckRevalidationResponseObject.getData().getAttributes().getFailedOnly(), false);
Date createdDate = new Date(2025 - 1900, Calendar.SEPTEMBER, 23, 11, 51, 8);
assertEquals(qaCheckRevalidationResponseObject.getData().getCreatedAt(), createdDate);
Comment on lines +103 to +104
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests build the expected timestamp using the deprecated Date(int,int,...) constructor, which uses the JVM default time zone. Since the JSON timestamps are +00:00, this assertion will be flaky on non-UTC environments. Prefer asserting via Instant.parse(...) / OffsetDateTime.parse(...) (or compare getCreatedAt().toInstant() to an Instant) to make the test time-zone independent.

Copilot uses AI. Check for mistakes.
}

@Test
public void revalidateQaChecksTest() {
QaCheckRevalidationRequest request = new QaCheckRevalidationRequest();
request.setLanguageIds(Arrays.asList("uk", "fr"));
request.setQaCheckCategories(Collections.singletonList("ai"));
request.setFailedOnly(true);
ResponseObject<QaCheckRevalidation> qaCheckRevalidationResponseObject = this.getTranslationStatusApi().revalidateQaChecks(projectId, request);
assertEquals(qaCheckRevalidationResponseObject.getData().getIdentifier(), revalidationId);
assertEquals(qaCheckRevalidationResponseObject.getData().getStatus(), "created");
assertEquals(qaCheckRevalidationResponseObject.getData().getProgress(), 0L);
assertEquals(qaCheckRevalidationResponseObject.getData().getAttributes().getLanguageIds(), Arrays.asList("uk", "fr"));
assertEquals(qaCheckRevalidationResponseObject.getData().getAttributes().getQaCheckCategories(), Collections.singletonList("ai"));
assertEquals(qaCheckRevalidationResponseObject.getData().getAttributes().getFailedOnly(), false);
Date createdDate = new Date(2025 - 1900, Calendar.SEPTEMBER, 23, 11, 51, 8);
assertEquals(qaCheckRevalidationResponseObject.getData().getCreatedAt(), createdDate);
Comment on lines +120 to +121
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: constructing the expected timestamp via the deprecated Date(int,int,...) constructor depends on the default time zone and will be flaky vs the +00:00 JSON timestamps. Prefer comparing instants (e.g., getCreatedAt().toInstant()) against a parsed ISO-8601 value.

Copilot uses AI. Check for mistakes.
}

@Test
public void cancelQaChecksRevalidationTest() {
this.getTranslationStatusApi().cancelQaChecksRevalidation(projectId, revalidationId);
}
}
21 changes: 21 additions & 0 deletions src/test/resources/api/translationstatus/qaChecksRevalidation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"data": {
"identifier": "b5215a34-1305-4b21-8054-fc2eb252842f",
"status": "created",
"progress": 0,
"attributes": {
"languageIds": [
"uk",
"fr"
],
"qaCheckCategories": [
"ai"
],
"failedOnly": false
},
"createdAt": "2025-09-23T11:51:08+00:00",
"updatedAt": "2025-09-23T11:51:08+00:00",
"startedAt": "2025-09-23T11:51:08+00:00",
"finishedAt": null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"qaCheckCategories": [
"ai"
],
"languageIds": [
"uk",
"fr"
],
"failedOnly": true
}