aboutsummaryrefslogtreecommitdiffstats
path: root/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java')
-rw-r--r--language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java151
1 files changed, 151 insertions, 0 deletions
diff --git a/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java b/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java
new file mode 100644
index 00000000..6ad82d7f
--- /dev/null
+++ b/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java
@@ -0,0 +1,151 @@
1package tools.refinery.language.web.xtext.servlet;
2
3import static org.hamcrest.MatcherAssert.assertThat;
4import static org.hamcrest.Matchers.equalTo;
5import static org.hamcrest.Matchers.hasProperty;
6import static org.hamcrest.Matchers.instanceOf;
7import static org.junit.jupiter.api.Assertions.fail;
8import static org.mockito.Mockito.mock;
9import static org.mockito.Mockito.times;
10import static org.mockito.Mockito.verify;
11
12import java.io.IOException;
13import java.util.List;
14import java.util.Map;
15import java.util.UUID;
16
17import org.eclipse.xtext.resource.IResourceServiceProvider;
18import org.eclipse.xtext.testing.InjectWith;
19import org.eclipse.xtext.testing.extensions.InjectionExtension;
20import org.eclipse.xtext.web.server.ServiceConflictResult;
21import org.eclipse.xtext.web.server.model.DocumentStateResult;
22import org.eclipse.xtext.web.server.validation.ValidationResult;
23import org.hamcrest.Matcher;
24import org.junit.jupiter.api.BeforeEach;
25import org.junit.jupiter.api.Test;
26import org.junit.jupiter.api.extension.ExtendWith;
27import org.mockito.ArgumentCaptor;
28import org.mockito.junit.jupiter.MockitoExtension;
29
30import com.google.inject.Inject;
31
32@ExtendWith(MockitoExtension.class)
33@ExtendWith(InjectionExtension.class)
34@InjectWith(ProblemWebInjectorProvider.class)
35class TransactionExecutorTest {
36 private static final String RESOURCE_NAME = "test.problem";
37
38 private static final String INVALID_STATE_ID = "<invalid_state>";
39
40 private static final String TEST_PROBLEM = """
41 class Person {
42 Person friend[0..*] opposite friend
43 }
44
45 friend(a, b).
46 """;
47
48 private static final Map<String, String> UPDATE_FULL_TEXT_PARAMS = Map.of("serviceType", "update", "fullText",
49 TEST_PROBLEM);
50
51 private static final Map<String, String> VALIDATE_PARAMS = Map.of("serviceType", "validate");
52
53 @Inject
54 private IResourceServiceProvider.Registry resourceServiceProviderRegistry;
55
56 private TransactionExecutor transactionExecutor;
57
58 @BeforeEach
59 void beforeEach() {
60 transactionExecutor = new TransactionExecutor(new SimpleSession(), resourceServiceProviderRegistry);
61 }
62
63 @Test
64 void emptyBatchTest() {
65 performBatchRequest(null);
66 }
67
68 @Test
69 void fullTextUpdateTest() {
70 var response = performSingleRequest(null, UPDATE_FULL_TEXT_PARAMS);
71 assertThat(response, hasResponseData(instanceOf(DocumentStateResult.class)));
72 }
73
74 @Test
75 void validationAfterFullTextUpdateInSameBatchTest() {
76 var response = performBatchRequest(null, UPDATE_FULL_TEXT_PARAMS, VALIDATE_PARAMS).get(1);
77 assertThat(response, hasResponseData(instanceOf(ValidationResult.class)));
78 }
79
80 @Test
81 void validationAfterFullTextUpdateInDifferentBatchTest() {
82 var stateId = updateFullText();
83 var validateResponse = performSingleRequest(stateId, VALIDATE_PARAMS);
84 assertThat(validateResponse, hasResponseData(instanceOf(ValidationResult.class)));
85 }
86
87 @Test
88 void conflictTest() {
89 updateFullText();
90 var response = performSingleRequest(INVALID_STATE_ID, VALIDATE_PARAMS);
91 assertThat(response, hasResponseData(instanceOf(ServiceConflictResult.class)));
92 }
93
94 @Test
95 void transactionCancelledDueToConflictTest() {
96 updateFullText();
97 var response = performBatchRequest(INVALID_STATE_ID, VALIDATE_PARAMS, VALIDATE_PARAMS).get(1);
98 assertThat(response, hasErrorKind(equalTo(XtextWebSocketErrorKind.TRANSACTION_CANCELLED)));
99 }
100
101 @SafeVarargs
102 private List<XtextWebSocketResponse> performBatchRequest(String requiredStateId, Map<String, String>... params) {
103 var id = UUID.randomUUID().toString();
104 var request = new XtextWebSocketRequest(id, RESOURCE_NAME, null, requiredStateId, List.of(params));
105
106 var responseHandler = mock(ResponseHandler.class);
107 try {
108 transactionExecutor.handleRequest(request, responseHandler);
109 } catch (IOException e) {
110 fail("Unexpected IOException", e);
111 }
112
113 var captor = ArgumentCaptor.forClass(XtextWebSocketResponse.class);
114 int nParams = params.length;
115 try {
116 verify(responseHandler, times(nParams)).onResponse(captor.capture());
117 } catch (IOException e) {
118 throw new RuntimeException("Mockito threw unexcepted exception", e);
119 }
120 var allResponses = captor.getAllValues();
121 for (int i = 0; i < nParams; i++) {
122 var response = allResponses.get(i);
123 assertThat(response, hasProperty("id", equalTo(id)));
124 assertThat(response, hasProperty("index", equalTo(i)));
125 }
126 return allResponses;
127 }
128
129 private XtextWebSocketResponse performSingleRequest(String requiredStateId, Map<String, String> param) {
130 return performBatchRequest(requiredStateId, param).get(0);
131 }
132
133 private String updateFullText() {
134 var updateResponse = (XtextWebSocketOkResponse) performSingleRequest(null, UPDATE_FULL_TEXT_PARAMS);
135 var documentStateResult = (DocumentStateResult) updateResponse.getResponseData();
136 var stateId = documentStateResult.getStateId();
137 if (INVALID_STATE_ID.equals(stateId)) {
138 throw new RuntimeException("Service returned unexpected stateId: " + stateId);
139 }
140 return stateId;
141 }
142
143 private static Matcher<XtextWebSocketResponse> hasResponseData(Matcher<?> responseDataMatcher) {
144 return hasProperty("responseData", responseDataMatcher);
145 }
146
147 private static Matcher<XtextWebSocketResponse> hasErrorKind(
148 Matcher<? extends XtextWebSocketErrorKind> errorKindMatcher) {
149 return hasProperty("errorKind", errorKindMatcher);
150 }
151}