1 | package com.github.dakusui.actionunit.actions; | |
2 | ||
3 | import com.github.dakusui.actionunit.core.Action; | |
4 | import com.github.dakusui.actionunit.exceptions.ActionException; | |
5 | ||
6 | import java.util.Formatter; | |
7 | import java.util.LinkedList; | |
8 | import java.util.List; | |
9 | ||
10 | import static com.github.dakusui.actionunit.core.ActionSupport.nop; | |
11 | import static com.github.dakusui.actionunit.exceptions.ActionException.wrap; | |
12 | import static java.util.Objects.requireNonNull; | |
13 | ||
14 | /** | |
15 | * An action whose success of the "target" is ensured by the "ensurer" actions. | |
16 | * | |
17 | * How it works?:: | |
18 | * Each action returned by {@code Ensured#ensurers()} is performed one by one. | |
19 | * After an entry from {@code ensurers()} is performed successfully, the target action | |
20 | * will be performed ({@code target()}. | |
21 | * If the target is performed successfully, this action finishes immediately and successfully. | |
22 | * If this step is tried for all the ensurers but no attempt finishes successfully, the entire action will fail. | |
23 | * | |
24 | * If an exception thrown by a target or an ensurer is not "recoverable", the entire action will fail immediately. | |
25 | * Whether it is recoverable or not is determined by the return value of a method {@code Ensured#isRecoverable(Throwable)}. | |
26 | * | |
27 | * @see Ensured#ensurers() | |
28 | * @see Ensured#target() | |
29 | * @see Ensured#isRecoverable(Throwable) | |
30 | */ | |
31 | public interface Ensured extends Action { | |
32 | /** | |
33 | * An exception which tells the framework that it should not be recovered by the | |
34 | * {@code Ensured} action mechanism. | |
35 | */ | |
36 | class Abort extends ActionException { | |
37 | public Abort(String message) { | |
38 | super(message); | |
39 | } | |
40 | } | |
41 | ||
42 | /** | |
43 | * An exception which tells the framework that a recovery requested by the | |
44 | * {@code Ensured} action mechanism. | |
45 | */ | |
46 | class RequestRetry extends ActionException { | |
47 | public RequestRetry(String message) { | |
48 | super(message); | |
49 | } | |
50 | } | |
51 | ||
52 | /** | |
53 | * Checks if a given `exception` is recoverable by this object. | |
54 | * | |
55 | * @param exception An exception to be checked. | |
56 | * @return `true` - Can be recovered / `false` - Otherwise. | |
57 | */ | |
58 | default boolean isRecoverable(Throwable exception) { | |
59 |
1
1. isRecoverable : negated conditional → SURVIVED |
if (exception instanceof RequestRetry) |
60 |
1
1. isRecoverable : replaced boolean return with false for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → KILLED |
return true; |
61 |
1
1. isRecoverable : negated conditional → KILLED |
if (exception instanceof Abort) |
62 |
1
1. isRecoverable : replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE |
return false; |
63 |
1
1. isRecoverable : negated conditional → KILLED |
if ("IncompleteExecutionException".equals(exception.getClass().getSimpleName())) |
64 |
1
1. isRecoverable : replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE |
return false; |
65 |
1
1. isRecoverable : negated conditional → SURVIVED |
if ("AssertionFailedError".equals(exception.getClass().getSimpleName())) |
66 |
1
1. isRecoverable : replaced boolean return with false for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE |
return true; |
67 |
2
1. isRecoverable : replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → SURVIVED 2. isRecoverable : negated conditional → KILLED |
return !(exception instanceof Error); |
68 | } | |
69 | ||
70 | /** | |
71 | * Rethrows a given `exception`, when it is not recoverable. | |
72 | * | |
73 | * @param exception An exception to be rethrown. | |
74 | * @param <T> Type of the `exception`. | |
75 | * @return A type placeholder, never be returned. | |
76 | */ | |
77 | default <T extends Throwable> T rethrow(T exception) { | |
78 |
1
1. rethrow : negated conditional → NO_COVERAGE |
if (exception instanceof Error) |
79 | throw (Error) exception; | |
80 |
1
1. rethrow : negated conditional → NO_COVERAGE |
if (exception instanceof RuntimeException) |
81 | throw (RuntimeException) exception; | |
82 | throw new ActionException(exception.getMessage(),exception); | |
83 | } | |
84 | ||
85 | /** | |
86 | * Returns a target action to be ensured its success. | |
87 | * This action will be performed repeatedly until it succeeds. | |
88 | * | |
89 | * @return A target action. | |
90 | * @see Ensured#ensurers() | |
91 | */ | |
92 | Action target(); | |
93 | ||
94 | /** | |
95 | * Returns a list of "ensurer" actions. | |
96 | * | |
97 | * An ensurer is an action that may make preconditions of the "target action". | |
98 | * | |
99 | * @return A list of "ensurer" actions. | |
100 | */ | |
101 | List<Action> ensurers(); | |
102 | ||
103 | @Override | |
104 | default void accept(Visitor visitor) { | |
105 |
1
1. accept : removed call to com/github/dakusui/actionunit/core/Action$Visitor::visit → KILLED |
visitor.visit(this); |
106 | } | |
107 | ||
108 | @Override | |
109 | default void formatTo(Formatter formatter, int flags, int width, int precision) { | |
110 | formatter.format("ensure:%s using", this.target()); | |
111 | } | |
112 | ||
113 | /** | |
114 | * An implementation of `Ensured` action's interface. | |
115 | */ | |
116 | class Impl implements Ensured { | |
117 | private final List<Action> ensurers; | |
118 | private final Action target; | |
119 | ||
120 | @SuppressWarnings("unchecked") | |
121 | public <T extends Throwable, R extends Throwable> Impl(Action target, List<Action> ensurers) { | |
122 | this.target = requireNonNull(target); | |
123 | this.ensurers = requireNonNull(ensurers); | |
124 | } | |
125 | ||
126 | @Override | |
127 | public Action target() { | |
128 |
1
1. target : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Impl::target → KILLED |
return this.target; |
129 | } | |
130 | ||
131 | @Override | |
132 | public List<Action> ensurers() { | |
133 |
1
1. ensurers : replaced return value with Collections.emptyList for com/github/dakusui/actionunit/actions/Ensured$Impl::ensurers → KILLED |
return this.ensurers; |
134 | } | |
135 | } | |
136 | ||
137 | /** | |
138 | * A builder class of `Ensured` action. | |
139 | * | |
140 | * @see Ensured | |
141 | */ | |
142 | class Builder extends Action.Builder<Ensured> { | |
143 | private Action target; | |
144 | private final List<Action> ensurers = new LinkedList<>(); | |
145 | ||
146 | /** | |
147 | * Sets `target` action to this builder. | |
148 | * | |
149 | * @param target A target action. | |
150 | * @return This object. | |
151 | */ | |
152 | public Builder target(Action target) { | |
153 | this.target = requireNonNull(target); | |
154 |
1
1. target : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::target → SURVIVED |
return this; |
155 | } | |
156 | ||
157 | /** | |
158 | * Adds an `ensurer` action to this builder object. | |
159 | * | |
160 | * @param ensurer An ensurer action to be added. | |
161 | * @return This object. | |
162 | */ | |
163 | public Builder with(Action ensurer) { | |
164 | ensurers.add(requireNonNull(ensurer)); | |
165 |
1
1. with : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::with → KILLED |
return this; |
166 | } | |
167 | ||
168 | /** | |
169 | * Adds a "nop" (no operation) action to this builder object as an ensurer. | |
170 | * This method is useful, when the target action may succeed without any preparation. | |
171 | * | |
172 | * @return This object. | |
173 | */ | |
174 | public Builder withNop() { | |
175 |
1
1. withNop : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::withNop → KILLED |
return this.with(nop()); |
176 | } | |
177 | ||
178 | /** | |
179 | * Builds and returns an `Ensured` action object. | |
180 | * | |
181 | * @return An `Ensured` action. | |
182 | */ | |
183 | public Ensured build() { | |
184 |
1
1. build : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::build → KILLED |
return new Impl(this.target, this.ensurers); |
185 | } | |
186 | } | |
187 | } | |
Mutations | ||
59 |
1.1 |
|
60 |
1.1 |
|
61 |
1.1 |
|
62 |
1.1 |
|
63 |
1.1 |
|
64 |
1.1 |
|
65 |
1.1 |
|
66 |
1.1 |
|
67 |
1.1 2.2 |
|
78 |
1.1 |
|
80 |
1.1 |
|
105 |
1.1 |
|
128 |
1.1 |
|
133 |
1.1 |
|
154 |
1.1 |
|
165 |
1.1 |
|
175 |
1.1 |
|
184 |
1.1 |