/** Like {@link #run} but with the given potentially modified options. */ @Override public PipelineResult run(PipelineOptions options) { checkState( enforcement.isPresent(), "Is your TestPipeline declaration missing a @Rule annotation? Usage: " + "@Rule public final transient TestPipeline pipeline = TestPipeline.create();"); final PipelineResult pipelineResult; try { enforcement.get().beforePipelineExecution(); PipelineOptions updatedOptions = MAPPER.convertValue(MAPPER.valueToTree(options), PipelineOptions.class); updatedOptions .as(TestValueProviderOptions.class) .setProviderRuntimeValues(StaticValueProvider.of(providerRuntimeValues)); pipelineResult = super.run(updatedOptions); verifyPAssertsSucceeded(this, pipelineResult); } catch (RuntimeException exc) { Throwable cause = exc.getCause(); if (cause instanceof AssertionError) { throw (AssertionError) cause; } else { throw exc; } } // If we reach this point, the pipeline has been run and no exceptions have been thrown during // its execution. enforcement.get().afterPipelineExecution(); return pipelineResult; }
/** * Enables the abandoned node detection. Abandoned nodes are <code>PTransforms</code>, <code> * PAsserts</code> included, that were not executed by the pipeline runner. Abandoned nodes are * most likely to occur due to the one of the following scenarios: * * <ul> * <li>Lack of a <code>pipeline.run()</code> statement at the end of a test. * <li>Addition of PTransforms after the pipeline has already run. * </ul> * * Abandoned node detection is automatically enabled when a real pipeline runner (i.e. not a * {@link CrashingRunner}) and/or a {@link NeedsRunner} or a {@link ValidatesRunner} annotation * are detected. */ public TestPipeline enableAbandonedNodeEnforcement(final boolean enable) { enforcement = enable ? Optional.of(new PipelineAbandonedNodeEnforcement(this)) : Optional.of(new PipelineRunEnforcement(this)); return this; }
@Override public void evaluate() throws Throwable { options.as(ApplicationNameOptions.class).setAppName(getAppName(description)); setDeducedEnforcementLevel(); // statement.evaluate() essentially runs the user code contained in the unit test at hand. // Exceptions thrown during the execution of the user's test code will propagate here, // unless the user explicitly handles them with a "catch" clause in his code. If the // exception is handled by a user's "catch" clause, is does not interrupt the flow and // we move on to invoking the configured enforcements. // If the user does not handle a thrown exception, it will propagate here and interrupt // the flow, preventing the enforcement(s) from being activated. // The motivation for this is avoiding enforcements over faulty pipelines. statement.evaluate(); enforcement.get().afterUserCodeFinished(); } };
/** * If enabled, a <code>pipeline.run()</code> statement will be added automatically in case it is * missing in the test. */ public TestPipeline enableAutoRunIfMissing(final boolean enable) { enforcement.get().enableAutoRunIfMissing(enable); return this; }
@Override protected void afterUserCodeFinished() { super.afterUserCodeFinished(); verifyPipelineExecution(); } }
@Override protected void afterPipelineExecution() { runVisitedNodes = recordPipelineNodes(pipeline); super.afterPipelineExecution(); }