Skip to content

Commit b6ccdbd

Browse files
authored
Merge pull request #24 from Visual-Regression-Tracker/109-errorHandling-fix
109 error handling fix
2 parents c569c86 + 65e3153 commit b6ccdbd

File tree

3 files changed

+104
-117
lines changed

3 files changed

+104
-117
lines changed

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
group 'io.visual-regression-tracker.sdk-java'
2-
version '4.0.2'
2+
version '4.0.3'
33

44
apply plugin: 'java'
55
apply plugin: 'jacoco'

src/main/java/io/visual_regression_tracker/sdk_java/VisualRegressionTracker.java

+45-44
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,19 @@
1515
import java.util.Optional;
1616

1717
public class VisualRegressionTracker {
18-
private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
19-
String apiKeyHeaderName = "apiKey";
20-
Gson gson = new Gson();
21-
VisualRegressionTrackerConfig visualRegressionTrackerConfig;
22-
String buildId;
23-
String projectId;
24-
OkHttpClient client;
18+
protected static final String apiKeyHeaderName = "apiKey";
19+
protected static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
20+
protected Gson gson;
21+
protected VisualRegressionTrackerConfig visualRegressionTrackerConfig;
22+
protected String buildId;
23+
protected String projectId;
24+
protected OkHttpClient client;
2525

2626
public VisualRegressionTracker(VisualRegressionTrackerConfig visualRegressionTrackerConfig) {
2727
this.visualRegressionTrackerConfig = visualRegressionTrackerConfig;
2828

2929
this.client = new OkHttpClient();
30-
}
31-
32-
protected boolean isStarted() {
33-
return this.buildId != null && this.projectId != null;
30+
this.gson = new Gson();
3431
}
3532

3633
public void start() throws IOException {
@@ -48,20 +45,9 @@ public void start() throws IOException {
4845
.build();
4946

5047
try (Response response = client.newCall(request).execute()) {
51-
if (response.code() == 401) {
52-
throw new TestRunException("Unauthorized");
53-
}
54-
if (response.code() == 403) {
55-
throw new TestRunException("Api key not authenticated");
56-
}
57-
if (response.code() == 404) {
58-
throw new TestRunException("Project not found");
59-
}
60-
61-
String responseBody = Optional.ofNullable(response.body())
62-
.orElseThrow(() -> new TestRunException("Cannot get response body"))
63-
.string();
64-
BuildResponse buildDTO = gson.fromJson(responseBody, BuildResponse.class);
48+
49+
BuildResponse buildDTO = handleResponse(response, BuildResponse.class);
50+
6551
this.buildId = Optional.ofNullable(buildDTO.getId())
6652
.orElseThrow(() -> new TestRunException("Build id is null"));
6753
this.projectId = Optional.ofNullable(buildDTO.getProjectId())
@@ -80,7 +66,32 @@ public void stop() throws IOException {
8066
.patch(RequestBody.create(JSON, ""))
8167
.build();
8268

83-
client.newCall(request).execute();
69+
try (Response response = client.newCall(request).execute()) {
70+
handleResponse(response, Object.class);
71+
}
72+
}
73+
74+
public void track(String name, String imageBase64, TestRunOptions testRunOptions) throws IOException {
75+
TestRunResponse testResultDTO = this.submitTestRun(name, imageBase64, testRunOptions);
76+
77+
TestRunStatus status = Optional.ofNullable(testResultDTO.getStatus())
78+
.orElseThrow(() -> new TestRunException("Status is null"));
79+
80+
if (status.equals(TestRunStatus.NEW)) {
81+
throw new TestRunException("No baseline: ".concat(testResultDTO.getUrl()));
82+
}
83+
84+
if (status.equals(TestRunStatus.UNRESOLVED)) {
85+
throw new TestRunException("Difference found: ".concat(testResultDTO.getUrl()));
86+
}
87+
}
88+
89+
public void track(String name, String imageBase64) throws IOException {
90+
this.track(name, imageBase64, TestRunOptions.builder().build());
91+
}
92+
93+
protected boolean isStarted() {
94+
return this.buildId != null && this.projectId != null;
8495
}
8596

8697
protected TestRunResponse submitTestRun(String name, String imageBase64, TestRunOptions testRunOptions) throws IOException {
@@ -110,29 +121,19 @@ protected TestRunResponse submitTestRun(String name, String imageBase64, TestRun
110121
.build();
111122

112123
try (Response response = client.newCall(request).execute()) {
113-
String responseBody = Optional.ofNullable(response.body())
114-
.orElseThrow(() -> new TestRunException("Cannot get response body"))
115-
.string();
116-
return gson.fromJson(responseBody, TestRunResponse.class);
124+
return handleResponse(response, TestRunResponse.class);
117125
}
118126
}
119127

120-
public void track(String name, String imageBase64, TestRunOptions testRunOptions) throws IOException {
121-
TestRunResponse testResultDTO = this.submitTestRun(name, imageBase64, testRunOptions);
122-
123-
TestRunStatus status = Optional.ofNullable(testResultDTO.getStatus())
124-
.orElseThrow(() -> new TestRunException("Status is null"));
128+
protected <T> T handleResponse(Response response, Class<T> classOfT) throws IOException {
129+
String responseBody = Optional.ofNullable(response.body())
130+
.orElseThrow(() -> new TestRunException("Cannot get response body"))
131+
.string();
125132

126-
if (status.equals(TestRunStatus.NEW)) {
127-
throw new TestRunException("No baseline: ".concat(testResultDTO.getUrl()));
133+
if (!response.isSuccessful()) {
134+
throw new TestRunException(responseBody);
128135
}
129136

130-
if (status.equals(TestRunStatus.UNRESOLVED)) {
131-
throw new TestRunException("Difference found: ".concat(testResultDTO.getUrl()));
132-
}
133-
}
134-
135-
public void track(String name, String imageBase64) throws IOException {
136-
this.track(name, imageBase64, TestRunOptions.builder().build());
137+
return gson.fromJson(responseBody, classOfT);
137138
}
138139
}

src/test/java/io/visual_regression_tracker/sdk_java/VisualRegressionTrackerTest.java

+58-72
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
import io.visual_regression_tracker.sdk_java.response.BuildResponse;
77
import io.visual_regression_tracker.sdk_java.response.TestRunResponse;
88
import lombok.SneakyThrows;
9+
import okhttp3.Protocol;
10+
import okhttp3.Request;
11+
import okhttp3.Response;
12+
import okhttp3.ResponseBody;
913
import okhttp3.mockwebserver.MockResponse;
1014
import okhttp3.mockwebserver.MockWebServer;
1115
import okhttp3.mockwebserver.RecordedRequest;
@@ -48,25 +52,6 @@ public void tearDown() {
4852
server.shutdown();
4953
}
5054

51-
@DataProvider(name = "shouldReturnIsStartedCases")
52-
public Object[][] shouldReturnIsStartedCases() {
53-
return new Object[][]{
54-
{null, null, false},
55-
{null, "some", false},
56-
{"some", null, false},
57-
{"some", "some", true},
58-
};
59-
}
60-
61-
@Test(dataProvider = "shouldReturnIsStartedCases")
62-
public void shouldReturnIsStarted(String buildId, String projectId, boolean expectedResult) {
63-
vrt.buildId = buildId;
64-
vrt.projectId = projectId;
65-
66-
boolean result = vrt.isStarted();
67-
MatcherAssert.assertThat(result, CoreMatchers.is(expectedResult));
68-
}
69-
7055
@Test
7156
public void shouldStartBuild() throws IOException, InterruptedException {
7257
String buildId = "123123";
@@ -86,57 +71,12 @@ public void shouldStartBuild() throws IOException, InterruptedException {
8671
vrt.start();
8772

8873
RecordedRequest request = server.takeRequest();
89-
MatcherAssert.assertThat(request.getHeader(vrt.apiKeyHeaderName), CoreMatchers.is(config.getApiKey()));
74+
MatcherAssert.assertThat(request.getHeader(VisualRegressionTracker.apiKeyHeaderName), CoreMatchers.is(config.getApiKey()));
9075
MatcherAssert.assertThat(request.getBody().readUtf8(), CoreMatchers.is(gson.toJson(buildRequest)));
9176
MatcherAssert.assertThat(vrt.buildId, CoreMatchers.is(buildId));
9277
MatcherAssert.assertThat(vrt.projectId, CoreMatchers.is(projectId));
9378
}
9479

95-
@Test
96-
public void shouldThrowExceptionIfProjectNotFound() throws IOException {
97-
server.enqueue(new MockResponse()
98-
.setResponseCode(404)
99-
.setBody("{\r\n \"statusCode\": 404,\r\n \"message\": \"Project not found\"\r\n}"));
100-
101-
String exceptionMessage = "";
102-
try {
103-
vrt.start();
104-
} catch (TestRunException ex) {
105-
exceptionMessage = ex.getMessage();
106-
}
107-
MatcherAssert.assertThat(exceptionMessage, CoreMatchers.is("Project not found"));
108-
}
109-
110-
@Test
111-
public void shouldThrowExceptionIfUnauthorized() throws IOException {
112-
server.enqueue(new MockResponse()
113-
.setResponseCode(401)
114-
.setBody("{\r\n \"statusCode\": 401,\r\n \"message\": \"Unauthorized\"\r\n}"));
115-
116-
String exceptionMessage = "";
117-
try {
118-
vrt.start();
119-
} catch (TestRunException ex) {
120-
exceptionMessage = ex.getMessage();
121-
}
122-
MatcherAssert.assertThat(exceptionMessage, CoreMatchers.is("Unauthorized"));
123-
}
124-
125-
@Test
126-
public void shouldThrowExceptionIfForbidden() throws IOException {
127-
server.enqueue(new MockResponse()
128-
.setResponseCode(403)
129-
.setBody("{\r\n \"statusCode\": 403,\r\n \"message\": \"Forbidden\"\r\n}"));
130-
131-
String exceptionMessage = "";
132-
try {
133-
vrt.start();
134-
} catch (TestRunException ex) {
135-
exceptionMessage = ex.getMessage();
136-
}
137-
MatcherAssert.assertThat(exceptionMessage, CoreMatchers.is("Api key not authenticated"));
138-
}
139-
14080
@Test
14181
public void shouldStopBuild() throws IOException, InterruptedException {
14282
String buildId = "123123";
@@ -154,7 +94,7 @@ public void shouldStopBuild() throws IOException, InterruptedException {
15494

15595
RecordedRequest request = server.takeRequest();
15696
MatcherAssert.assertThat(request.getMethod(), CoreMatchers.is("PATCH"));
157-
MatcherAssert.assertThat(request.getHeader(vrt.apiKeyHeaderName), CoreMatchers.is(config.getApiKey()));
97+
MatcherAssert.assertThat(request.getHeader(VisualRegressionTracker.apiKeyHeaderName), CoreMatchers.is(config.getApiKey()));
15898
MatcherAssert.assertThat(Objects.requireNonNull(request.getRequestUrl()).encodedPath(), CoreMatchers.containsString(buildId));
15999
}
160100

@@ -204,13 +144,13 @@ public void shouldSubmitTestRun() throws IOException, InterruptedException {
204144
TestRunResponse result = vrt.submitTestRun(name, imageBase64, testRunOptions);
205145

206146
RecordedRequest request = server.takeRequest();
207-
MatcherAssert.assertThat(request.getHeader(vrt.apiKeyHeaderName), CoreMatchers.is(config.getApiKey()));
147+
MatcherAssert.assertThat(request.getHeader(VisualRegressionTracker.apiKeyHeaderName), CoreMatchers.is(config.getApiKey()));
208148
MatcherAssert.assertThat(request.getBody().readUtf8(), CoreMatchers.is(gson.toJson(testRunRequest)));
209149
MatcherAssert.assertThat(gson.toJson(result), CoreMatchers.is(gson.toJson(testRunResponse)));
210150
}
211151

212152
@Test
213-
public void shouldNotSubmitTestRunIfNotStarted() throws IOException {
153+
public void submitTestRunShouldThrowIfNotStarted() throws IOException {
214154
VisualRegressionTracker vrtMocked = Mockito.mock(VisualRegressionTracker.class);
215155
Mockito.when(vrtMocked.isStarted()).thenReturn(false);
216156

@@ -224,8 +164,8 @@ public void shouldNotSubmitTestRunIfNotStarted() throws IOException {
224164
MatcherAssert.assertThat(exceptionMessage, CoreMatchers.is("Visual Regression Tracker has not been started"));
225165
}
226166

227-
@DataProvider(name = "shouldTrackThrowExceptionCases")
228-
public Object[][] shouldTrackThrowExceptionCases() {
167+
@DataProvider(name = "trackShouldThrowExceptionCases")
168+
public Object[][] trackShouldThrowExceptionCases() {
229169
return new Object[][]{
230170
{
231171
TestRunResponse.builder()
@@ -244,8 +184,8 @@ public Object[][] shouldTrackThrowExceptionCases() {
244184
};
245185
}
246186

247-
@Test(dataProvider = "shouldTrackThrowExceptionCases")
248-
public void shouldTrackThrowException(TestRunResponse testRunResponse, String expectedExceptionMessage) throws IOException {
187+
@Test(dataProvider = "trackShouldThrowExceptionCases")
188+
public void trackShouldThrowException(TestRunResponse testRunResponse, String expectedExceptionMessage) throws IOException {
249189
VisualRegressionTracker vrtMocked = Mockito.mock(VisualRegressionTracker.class);
250190
Mockito.when(vrtMocked.submitTestRun(Mockito.anyString(), Mockito.anyString(), Mockito.any())).thenReturn(testRunResponse);
251191

@@ -289,4 +229,50 @@ public void shouldTrackOverload() throws IOException {
289229

290230
Mockito.verify(vrtMocked, Mockito.times(1)).track(Mockito.anyString(), Mockito.anyString(), Mockito.any(TestRunOptions.class));
291231
}
232+
233+
@DataProvider(name = "shouldReturnIsStartedCases")
234+
public Object[][] shouldReturnIsStartedCases() {
235+
return new Object[][]{
236+
{null, null, false},
237+
{null, "some", false},
238+
{"some", null, false},
239+
{"some", "some", true},
240+
};
241+
}
242+
243+
@Test(dataProvider = "shouldReturnIsStartedCases")
244+
public void shouldReturnIsStarted(String buildId, String projectId, boolean expectedResult) {
245+
vrt.buildId = buildId;
246+
vrt.projectId = projectId;
247+
248+
boolean result = vrt.isStarted();
249+
250+
MatcherAssert.assertThat(result, CoreMatchers.is(expectedResult));
251+
}
252+
253+
@Test
254+
public void handleRequestShouldThrowIfNotSuccess() throws IOException {
255+
String error = "{\n" +
256+
" \"statusCode\": 404,\n" +
257+
" \"message\": \"Project not found\"\n" +
258+
"}";
259+
Request mockRequest = new Request.Builder()
260+
.url(config.getApiUrl())
261+
.build();
262+
263+
String exceptionMessage = "";
264+
try {
265+
vrt.handleResponse(new Response.Builder()
266+
.request(mockRequest)
267+
.protocol(Protocol.HTTP_2)
268+
.code(401)
269+
.message("Not found")
270+
.body(ResponseBody.create(error, VisualRegressionTracker.JSON))
271+
.build(), Object.class);
272+
} catch (TestRunException ex) {
273+
exceptionMessage = ex.getMessage();
274+
}
275+
276+
MatcherAssert.assertThat(exceptionMessage, CoreMatchers.is(error));
277+
}
292278
}

0 commit comments

Comments
 (0)