1111import static com .google .common .truth .Truth .assertThat ;
1212import static com .google .common .truth .TruthJUnit .assume ;
1313import static org .junit .Assert .assertThrows ;
14+ import static org .sosy_lab .java_smt .SolverContextFactory .Solvers .BOOLECTOR ;
1415
16+ import com .google .common .collect .ImmutableList ;
1517import java .util .ArrayList ;
1618import java .util .List ;
1719import java .util .Random ;
1820import java .util .function .Supplier ;
1921import org .junit .Before ;
22+ import org .junit .Ignore ;
2023import org .junit .Test ;
2124import org .junit .runner .RunWith ;
2225import org .junit .runners .Parameterized ;
2528import org .sosy_lab .java_smt .SolverContextFactory .Solvers ;
2629import org .sosy_lab .java_smt .api .BasicProverEnvironment ;
2730import org .sosy_lab .java_smt .api .BooleanFormula ;
31+ import org .sosy_lab .java_smt .api .SolverContext .ProverOptions ;
2832import org .sosy_lab .java_smt .api .SolverException ;
2933import org .sosy_lab .java_smt .api .Tactic ;
3034import org .sosy_lab .java_smt .solvers .opensmt .Logics ;
@@ -140,21 +144,14 @@ public void testProverInterruptWithSubsequentNewProverUsageInt()
140144 public void testContextInterruptWithSubsequentNewProverUsageBv ()
141145 throws InterruptedException , SolverException {
142146 requireBitvectors ();
143- requireIsolatedProverShutdown ();
144147
145148 testBasicContextTimeoutBv (() -> context .newProverEnvironment ());
146149 assertThat (shutdownManager .getNotifier ().shouldShutdown ()).isTrue ();
147150
148151 HardBitvectorFormulaGenerator gen = new HardBitvectorFormulaGenerator (bvmgr , bmgr );
149152 try (BasicProverEnvironment <?> pe = context .newProverEnvironment ()) {
150- pe .push (gen .generate (8 ));
153+ assertThrows ( InterruptedException . class , () -> pe .push (gen .generate (8 ) ));
151154 assertThrows (InterruptedException .class , pe ::isUnsat );
152-
153- } catch (InterruptedException expected ) {
154- // We don't really know where an exception is coming from currently.
155- // TODO: define where and how exceptions are thrown if we build a new prover but shutdown
156- // has been requested.
157- assertThat (expected ).isNotNull ();
158155 }
159156 }
160157
@@ -163,7 +160,6 @@ public void testContextInterruptWithSubsequentNewProverUsageBv()
163160 public void testContextInterruptWithSubsequentNewProverUsageInt ()
164161 throws InterruptedException , SolverException {
165162 requireIntegers ();
166- requireIsolatedProverShutdown ();
167163
168164 testBasicContextTimeoutInt (() -> context .newProverEnvironment ());
169165 assertThat (shutdownManager .getNotifier ().shouldShutdown ()).isTrue ();
@@ -181,6 +177,122 @@ public void testContextInterruptWithSubsequentNewProverUsageInt()
181177 }
182178 }
183179
180+ // Test shutdown of context-wide shutdown manager. No prover should be usable afterward!
181+ // This test re-uses provers that already existed before the shutdown.
182+ @ Test (timeout = TIMEOUT_MILLISECONDS )
183+ public void testContextInterruptWithSubsequentProverUsageBv () throws InterruptedException {
184+ requireBitvectors ();
185+ assume ()
186+ .withMessage ("Boolector does not support multiple provers" )
187+ .that (solverToUse ())
188+ .isNotEqualTo (BOOLECTOR );
189+
190+ HardBitvectorFormulaGenerator gen = new HardBitvectorFormulaGenerator (bvmgr , bmgr );
191+ try (BasicProverEnvironment <?> pe1 = context .newProverEnvironment ()) {
192+ try (BasicProverEnvironment <?> pe2 = context .newProverEnvironment ()) {
193+ pe2 .push (gen .generate (8 ));
194+
195+ testBasicContextTimeoutBv (() -> context .newProverEnvironment ());
196+ assertThat (shutdownManager .getNotifier ().shouldShutdown ()).isTrue ();
197+ try {
198+ assertThat (pe1 .getShutdownManagerForProver ().getNotifier ().shouldShutdown ()).isTrue ();
199+ assertThat (pe2 .getShutdownManagerForProver ().getNotifier ().shouldShutdown ()).isTrue ();
200+ } catch (UnsupportedOperationException mayBeThrown ) {
201+ // Do nothing, we can't check for solvers that don't support this
202+ }
203+
204+ assertThrows (InterruptedException .class , () -> pe1 .push (gen .generate (8 )));
205+ assertThrows (InterruptedException .class , pe2 ::isUnsat );
206+ }
207+ }
208+ }
209+
210+ // Test shutdown of context-wide shutdown manager. No prover should be usable afterward!
211+ // This test re-uses provers that already existed before the shutdown.
212+ @ Test (timeout = TIMEOUT_MILLISECONDS )
213+ public void testContextInterruptWithSubsequentProverUsageInt () throws InterruptedException {
214+ requireIntegers ();
215+
216+ HardIntegerFormulaGenerator gen = new HardIntegerFormulaGenerator (imgr , bmgr );
217+ try (BasicProverEnvironment <?> pe1 = context .newProverEnvironment ()) {
218+ try (BasicProverEnvironment <?> pe2 = context .newProverEnvironment ()) {
219+ pe2 .push (gen .generate (8 ));
220+
221+ testBasicContextTimeoutInt (() -> context .newProverEnvironment ());
222+ assertThat (shutdownManager .getNotifier ().shouldShutdown ()).isTrue ();
223+ try {
224+ assertThat (pe1 .getShutdownManagerForProver ().getNotifier ().shouldShutdown ()).isTrue ();
225+ assertThat (pe2 .getShutdownManagerForProver ().getNotifier ().shouldShutdown ()).isTrue ();
226+ } catch (UnsupportedOperationException mayBeThrown ) {
227+ // Do nothing, we can't check for solvers that don't support this
228+ }
229+
230+ assertThrows (InterruptedException .class , () -> pe1 .push (gen .generate (8 )));
231+ assertThrows (InterruptedException .class , pe2 ::isUnsat );
232+ }
233+ }
234+ }
235+
236+ // Test shutdown of prover and subsequent feature usage.
237+ @ Ignore
238+ @ Test (timeout = TIMEOUT_MILLISECONDS )
239+ public void testProverInterruptWithSubsequentFeatureUsageBv () throws InterruptedException {
240+ requireBitvectors ();
241+ requireIsolatedProverShutdown ();
242+
243+ HardBitvectorFormulaGenerator gen = new HardBitvectorFormulaGenerator (bvmgr , bmgr );
244+ try (BasicProverEnvironment <?> pe1 = context .newProverEnvironment ()) {
245+ try (BasicProverEnvironment <?> pe2 = context .newProverEnvironment ()) {
246+ pe2 .push (gen .generate (8 ));
247+
248+ testBasicProverTimeoutWithFeatureUsageBv (() -> context .newProverEnvironment ());
249+ assertThat (shutdownManager .getNotifier ().shouldShutdown ()).isTrue ();
250+ try {
251+ assertThat (pe1 .getShutdownManagerForProver ().getNotifier ().shouldShutdown ()).isTrue ();
252+ assertThat (pe2 .getShutdownManagerForProver ().getNotifier ().shouldShutdown ()).isTrue ();
253+ } catch (UnsupportedOperationException mayBeThrown ) {
254+ // Do nothing, we can't check for solvers that don't support this
255+ }
256+
257+ assertThrows (InterruptedException .class , () -> pe1 .push (gen .generate (8 )));
258+ assertThrows (InterruptedException .class , pe2 ::isUnsat );
259+ }
260+ }
261+ }
262+
263+ // Test shutdown of prover and subsequent feature usage.
264+ @ Ignore
265+ @ Test (timeout = TIMEOUT_MILLISECONDS )
266+ public void testContextInterruptWithSubsequentFeatureUsageInt () throws InterruptedException {
267+ requireIntegers ();
268+ requireIsolatedProverShutdown ();
269+
270+ HardIntegerFormulaGenerator gen = new HardIntegerFormulaGenerator (imgr , bmgr );
271+ try (BasicProverEnvironment <?> pe1 = context .newProverEnvironment ()) {
272+ try (BasicProverEnvironment <?> pe2 = context .newProverEnvironment ()) {
273+ pe2 .push (gen .generate (8 ));
274+
275+ testBasicProverTimeoutWithFeatureUsageInt (
276+ () ->
277+ context .newProverEnvironment (
278+ ProverOptions .GENERATE_UNSAT_CORE ,
279+ ProverOptions .GENERATE_MODELS ,
280+ ProverOptions .GENERATE_ALL_SAT ,
281+ ProverOptions .GENERATE_UNSAT_CORE_OVER_ASSUMPTIONS ));
282+ assertThat (shutdownManager .getNotifier ().shouldShutdown ()).isTrue ();
283+ try {
284+ assertThat (pe1 .getShutdownManagerForProver ().getNotifier ().shouldShutdown ()).isTrue ();
285+ assertThat (pe2 .getShutdownManagerForProver ().getNotifier ().shouldShutdown ()).isTrue ();
286+ } catch (UnsupportedOperationException mayBeThrown ) {
287+ // Do nothing, we can't check for solvers that don't support this
288+ }
289+
290+ assertThrows (InterruptedException .class , () -> pe1 .push (gen .generate (8 )));
291+ assertThrows (InterruptedException .class , pe2 ::isUnsat );
292+ }
293+ }
294+ }
295+
184296 @ Test (timeout = TIMEOUT_MILLISECONDS )
185297 public void testInterpolationProverTimeout () throws InterruptedException {
186298 requireInterpolation ();
@@ -227,6 +339,26 @@ private void testBasicProverTimeoutBv(Supplier<BasicProverEnvironment<?>> prover
227339 testBasicProverBasedTimeout (proverConstructor , gen .generate (200 ));
228340 }
229341
342+ /**
343+ * Shuts down the shutdown manager of the prover. Throws an exception for non-supporting solvers.
344+ * Will try to use all available features of the solver afterward. (Model, UnsatCore etc.)
345+ */
346+ private void testBasicProverTimeoutWithFeatureUsageInt (
347+ Supplier <BasicProverEnvironment <?>> proverConstructor ) throws InterruptedException {
348+ HardIntegerFormulaGenerator gen = new HardIntegerFormulaGenerator (imgr , bmgr );
349+ testProverBasedTimeoutWithFeatures (proverConstructor , gen .generate (200 ));
350+ }
351+
352+ /**
353+ * Shuts down the shutdown manager of the prover. Throws an exception for non-supporting solvers.
354+ * Will try to use all available features of the solver afterward. (Model, UnsatCore etc.)
355+ */
356+ private void testBasicProverTimeoutWithFeatureUsageBv (
357+ Supplier <BasicProverEnvironment <?>> proverConstructor ) throws InterruptedException {
358+ HardBitvectorFormulaGenerator gen = new HardBitvectorFormulaGenerator (bvmgr , bmgr );
359+ testProverBasedTimeoutWithFeatures (proverConstructor , gen .generate (200 ));
360+ }
361+
230362 @ SuppressWarnings ("CheckReturnValue" )
231363 private void testBasicContextBasedTimeout (
232364 Supplier <BasicProverEnvironment <?>> proverConstructor , BooleanFormula instance )
@@ -269,4 +401,35 @@ private void testBasicProverBasedTimeout(
269401 assertThrows (InterruptedException .class , pe ::isUnsat );
270402 }
271403 }
404+
405+ private void testProverBasedTimeoutWithFeatures (
406+ Supplier <BasicProverEnvironment <?>> proverConstructor , BooleanFormula instance )
407+ throws InterruptedException {
408+
409+ // TODO: maybe add a test that solves something correctly before interrupting?
410+
411+ try (BasicProverEnvironment <?> pe = proverConstructor .get ()) {
412+ Thread t =
413+ new Thread (
414+ () -> {
415+ try {
416+ Thread .sleep (delay );
417+ pe .getShutdownManagerForProver ().requestShutdown ("Shutdown Request" );
418+ } catch (InterruptedException exception ) {
419+ throw new UnsupportedOperationException ("Unexpected interrupt" , exception );
420+ }
421+ });
422+ pe .push (instance );
423+ t .start ();
424+ assertThrows (InterruptedException .class , pe ::isUnsat );
425+ assertThrows (InterruptedException .class , pe ::getModel );
426+ assertThrows (InterruptedException .class , pe ::getUnsatCore );
427+ assertThrows (
428+ InterruptedException .class , () -> pe .isUnsatWithAssumptions (ImmutableList .of (instance )));
429+ assertThrows (InterruptedException .class , () -> pe .addConstraint (instance ));
430+ assertThrows (InterruptedException .class , () -> pe .push (instance ));
431+ assertThrows (InterruptedException .class , pe ::push );
432+ assertThrows (InterruptedException .class , pe ::pop );
433+ }
434+ }
272435}
0 commit comments