21
21
import static org .junit .jupiter .api .Assertions .assertDoesNotThrow ;
22
22
import static org .junit .jupiter .api .Assertions .assertEquals ;
23
23
import static org .junit .jupiter .api .Assertions .assertThrows ;
24
- import static org .junit .jupiter .params .provider .Arguments .arguments ;
25
24
26
25
import java .util .Iterator ;
27
26
import java .util .List ;
28
27
import java .util .Set ;
29
28
import java .util .TreeSet ;
30
- import java .util .function .Consumer ;
31
29
import java .util .stream .Collectors ;
32
- import java .util .stream .Stream ;
33
30
34
31
import org .apache .accumulo .core .client .Accumulo ;
35
32
import org .apache .accumulo .core .client .BatchWriter ;
42
39
import org .apache .accumulo .core .fate .FateInstanceType ;
43
40
import org .apache .accumulo .core .fate .FateStore ;
44
41
import org .apache .accumulo .core .fate .ReadOnlyFateStore ;
45
- import org .apache .accumulo .core .fate .StackOverflowException ;
46
42
import org .apache .accumulo .core .fate .accumulo .AccumuloStore ;
47
43
import org .apache .accumulo .core .fate .accumulo .schema .FateSchema ;
48
44
import org .apache .accumulo .harness .SharedMiniClusterBase ;
49
45
import org .apache .accumulo .test .fate .FateIT ;
50
46
import org .apache .hadoop .io .Text ;
51
47
import org .junit .jupiter .api .AfterAll ;
48
+ import org .junit .jupiter .api .AfterEach ;
52
49
import org .junit .jupiter .api .BeforeAll ;
50
+ import org .junit .jupiter .api .BeforeEach ;
51
+ import org .junit .jupiter .api .Nested ;
53
52
import org .junit .jupiter .api .Test ;
54
53
import org .junit .jupiter .api .function .Executable ;
55
- import org .junit .jupiter .params .ParameterizedTest ;
56
- import org .junit .jupiter .params .provider .Arguments ;
57
- import org .junit .jupiter .params .provider .MethodSource ;
58
54
import org .slf4j .Logger ;
59
55
import org .slf4j .LoggerFactory ;
60
56
@@ -121,64 +117,76 @@ public void testCreateWithCollisionAndExceedRetryLimit() throws Exception {
121
117
}
122
118
}
123
119
124
- /**
125
- * Test that an operation only works with the expected statuses present for the transaction.
126
- */
127
- @ ParameterizedTest (name = "{index} => Operation: {0}" )
128
- @ MethodSource ("operationStatusPairs" )
129
- public void testStatuses (String description ,
130
- Consumer <FateStore .FateTxStore <FateIT .TestEnv >> operationConsumer ,
131
- Set <ReadOnlyFateStore .TStatus > acceptableStatuses ) throws Exception {
132
- try (ClientContext client =
133
- (ClientContext ) Accumulo .newClient ().from (getClientProps ()).build ()) {
134
- final String tableName = getUniqueNames (1 )[0 ];
135
- try {
136
- client .tableOperations ().create (tableName );
137
- FateId fateId = FateId .from (fateInstanceType , 1L );
138
- TestAccumuloStore store = new TestAccumuloStore (client , tableName , List .of (fateId ));
139
- store .create ();
140
- FateStore .FateTxStore <FateIT .TestEnv > txStore = store .reserve (fateId );
141
-
142
- // for each TStatus, set the status and verify that the operation only works if it is in the
143
- // expected set of statuses
144
- for (ReadOnlyFateStore .TStatus status : ReadOnlyFateStore .TStatus .values ()) {
145
- injectStatus (client , tableName , fateId , status );
146
- assertEquals (status , store .getStatus (fateId ));
147
- Executable testOp = () -> operationConsumer .accept (txStore );
148
- if (!acceptableStatuses .contains (status )) {
149
- assertThrows (IllegalStateException .class , testOp ,
150
- "Expected " + description + " to fail with status " + status + " but it did not" );
151
- } else {
152
- assertDoesNotThrow (testOp , "Expected " + description + " to succeed with status "
153
- + status + " but it did not" );
154
- }
120
+ @ Nested
121
+ class TestStatusEnforcement {
122
+
123
+ String tableName ;
124
+ ClientContext client ;
125
+ FateId fateId ;
126
+ TestAccumuloStore store ;
127
+ FateStore .FateTxStore <FateIT .TestEnv > txStore ;
128
+
129
+ @ BeforeEach
130
+ public void setup () throws Exception {
131
+ client = (ClientContext ) Accumulo .newClient ().from (getClientProps ()).build ();
132
+ tableName = getUniqueNames (1 )[0 ];
133
+ client .tableOperations ().create (tableName );
134
+ fateId = FateId .from (fateInstanceType , 1L );
135
+ store = new TestAccumuloStore (client , tableName , List .of (fateId ));
136
+ store .create ();
137
+ txStore = store .reserve (fateId );
138
+ }
139
+
140
+ @ AfterEach
141
+ public void teardown () throws Exception {
142
+ client .close ();
143
+ }
144
+
145
+ private void testOperationWithStatuses (Runnable beforeOperation , Executable operation ,
146
+ Set <ReadOnlyFateStore .TStatus > acceptableStatuses ) throws Exception {
147
+ for (ReadOnlyFateStore .TStatus status : ReadOnlyFateStore .TStatus .values ()) {
148
+ // Run any needed setup for the operation before each iteration
149
+ beforeOperation .run ();
150
+
151
+ injectStatus (client , tableName , fateId , status );
152
+ assertEquals (status , store .getStatus (fateId ));
153
+ if (!acceptableStatuses .contains (status )) {
154
+ assertThrows (IllegalStateException .class , operation ,
155
+ "Expected operation to fail with status " + status + " but it did not" );
156
+ } else {
157
+ assertDoesNotThrow (operation ,
158
+ "Expected operation to succeed with status " + status + " but it did not" );
155
159
}
156
- } finally {
160
+ }
161
+ }
162
+
163
+ @ Test
164
+ public void push () throws Exception {
165
+ testOperationWithStatuses (() -> {}, // No special setup needed for push
166
+ () -> txStore .push (new FateIT .TestRepo ("testOp" )),
167
+ Set .of (ReadOnlyFateStore .TStatus .IN_PROGRESS , ReadOnlyFateStore .TStatus .NEW ));
168
+ }
169
+
170
+ @ Test
171
+ public void pop () throws Exception {
172
+ testOperationWithStatuses (() -> {
173
+ // Setup for pop: Ensure there something to pop by first pushing
157
174
try {
158
- client .tableOperations ().delete (tableName );
159
- } catch (TableNotFoundException e ) {
160
- // ignore
175
+ injectStatus (client , tableName , fateId , ReadOnlyFateStore .TStatus .NEW );
176
+ txStore .push (new FateIT .TestRepo ("testOp" ));
177
+ } catch (Exception e ) {
178
+ throw new RuntimeException ("Failed to setup for pop" , e );
161
179
}
162
- }
180
+ }, txStore :: pop , Set . of ( ReadOnlyFateStore . TStatus . FAILED_IN_PROGRESS ));
163
181
}
164
- }
165
182
166
- public static Stream <Arguments > operationStatusPairs () {
167
- return Stream
168
- .of (arguments ("push()" , (Consumer <FateStore .FateTxStore <FateIT .TestEnv >>) txStore -> {
169
- try {
170
- txStore .push (new FateIT .TestRepo ("testOp" ));
171
- } catch (StackOverflowException e ) {
172
- throw new RuntimeException (e );
173
- }
174
- }, Set .of (ReadOnlyFateStore .TStatus .IN_PROGRESS , ReadOnlyFateStore .TStatus .NEW )),
175
- arguments ("pop()" ,
176
- (Consumer <FateStore .FateTxStore <FateIT .TestEnv >>) FateStore .FateTxStore ::pop ,
177
- Set .of (ReadOnlyFateStore .TStatus .FAILED_IN_PROGRESS )),
178
- arguments ("delete()" ,
179
- (Consumer <FateStore .FateTxStore <FateIT .TestEnv >>) FateStore .FateTxStore ::delete ,
180
- Set .of (ReadOnlyFateStore .TStatus .NEW , ReadOnlyFateStore .TStatus .SUBMITTED ,
181
- ReadOnlyFateStore .TStatus .SUCCESSFUL , ReadOnlyFateStore .TStatus .FAILED )));
183
+ @ Test
184
+ public void delete () throws Exception {
185
+ testOperationWithStatuses (() -> {}, // No special setup needed for delete
186
+ txStore ::delete ,
187
+ Set .of (ReadOnlyFateStore .TStatus .NEW , ReadOnlyFateStore .TStatus .SUBMITTED ,
188
+ ReadOnlyFateStore .TStatus .SUCCESSFUL , ReadOnlyFateStore .TStatus .FAILED ));
189
+ }
182
190
}
183
191
184
192
/**
@@ -194,4 +202,5 @@ private void injectStatus(ClientContext client, String table, FateId fateId,
194
202
throw new RuntimeException (e );
195
203
}
196
204
}
205
+
197
206
}
0 commit comments