Skip to content

Commit

Permalink
Merged latest changed from the source branch
Browse files Browse the repository at this point in the history
  • Loading branch information
baubakg committed Sep 27, 2024
2 parents 4da4ee4 + 1e5d9aa commit 3d4098a
Show file tree
Hide file tree
Showing 13 changed files with 2,974 additions and 48 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -636,9 +636,10 @@ For now, we have not come around to deciding how retry should work in the case o

## Release Notes

### 8.11.2
### 8.11.3 in Progress
* **(new feature)** [#178 Allowing the injection in any step of a scenario](https://github.com/adobe/phased-testing/issues/178). We can now inject an event into a step in an arbitrary phased test. This is done by setting the syetm property PHASED.EVENTS.TARGET. This way you can inject the event into that step.
* **(new feature)** [#198 Adding Post Step Event actions](https://github.com/adobe/phased-testing/issues/198). We allow you to define a 'tearDownEvent' tool to allow you to put the system back to a normal state after the event has finished. Please refer to the chapter [Performing Event Cleanup Actions](#performing-event-cleanup-actions).
* [#202 Error Handling during Event Execution](https://github.com/adobe/phased-testing/issues/202). Exceptions in events were either not communicated or they caused unexpected behavior. We now return the exceptions thrown by the event.

### 8.11.1
* Renaming ConfigValueHandler to ConfigValueHandlerPhased
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2,290 changes: 2,289 additions & 1 deletion diagrams/PhasedDiagrams.drawio

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@

import com.adobe.campaign.tests.integro.phased.exceptions.PhasedTestingEventException;

import java.util.concurrent.Future;

public abstract class NonInterruptiveEvent implements Runnable {

Future<?> threadFuture = null;

/**
* Starts the non-interruptive event
*/
Expand All @@ -39,19 +43,14 @@ public enum states {DEFINED , STARTED, FAILURE, FINISHED};

@Override
public void run() {
state = startEvent() ? states.STARTED : states.FAILURE;

if (state.equals(states.FAILURE)) {
throw new PhasedTestingEventException("There was a problem starting this event.");
try {
startEvent();
state = states.STARTED;
} catch (Exception e) {
state = states.FAILURE;
throw new PhasedTestingEventException("There was a problem starting this event.", e);
}

waitTillFinished();

if (!isFinished()) {
throw new PhasedTestingEventException("This event did not finish as expected.");
}
state=states.FINISHED;
Thread.currentThread().interrupt();
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@

import com.adobe.campaign.tests.integro.phased.exceptions.PhasedTestConfigurationException;
import com.adobe.campaign.tests.integro.phased.exceptions.PhasedTestException;
import com.adobe.campaign.tests.integro.phased.exceptions.PhasedTestingEventException;
import com.adobe.campaign.tests.integro.phased.utils.ClassPathParser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.testng.ITestResult;

import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

Expand Down Expand Up @@ -148,15 +150,31 @@ protected static NonInterruptiveEvent startEvent(String in_event, String in_onAc
NonInterruptiveEvent nie = instantiateClassFromString(in_event);
logEvent(EventMode.START, in_event, in_onAccountOfStep);
events.put(in_onAccountOfStep, nie);
eventExecutor.submit(nie);
nie.threadFuture = eventExecutor.submit(nie);
while (nie.getState().equals(NonInterruptiveEvent.states.DEFINED)) {
try {
//log.debug("Waiting for event to start");
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}

if (nie.getState().equals(NonInterruptiveEvent.states.FAILURE)) {
log.error("Event Exception : The event {} for step {} caused an exception during start.", in_event, in_onAccountOfStep);
try {
nie.threadFuture.get();
} catch (InterruptedException | ExecutionException ex) {
ex.getCause().printStackTrace();
}
}

//NON_INTERRUPTIVE 23
if (Phases.NON_INTERRUPTIVE.fetchType().startsWith("2")) {
log.info("Forcing Event End {} BEFORE step {} has started.", in_event, in_onAccountOfStep);
performWaitTilFinish(in_event, in_onAccountOfStep, nie);
}
return nie;
}

Expand Down Expand Up @@ -205,13 +223,50 @@ protected static NonInterruptiveEvent finishEvent(String in_event, String in_onA
throw new PhasedTestConfigurationException("Class " + in_event + " not found.", e);
}

l_activeEvent.waitTillFinished();
//if (Phases.NON_INTERRUPTIVE.fetchType().startsWith("3")) {
// log.info("Forcing Event End {} AFTER step {} has finished.", in_event, in_onAccountOfStep);
performWaitTilFinish(in_event, in_onAccountOfStep, l_activeEvent);
//}

if (!l_activeEvent.isFinished()) {
throw new PhasedTestingEventException("This event did not finish as expected.");
}

l_activeEvent.state = NonInterruptiveEvent.states.FINISHED;
log.info("Event {} for step {} has finished.", in_event, in_onAccountOfStep);

if (!l_activeEvent.threadFuture.isDone()) {
log.error("The event {} for step {} did not finish as expected. Cancelling the event.", in_event, in_onAccountOfStep);
l_activeEvent.threadFuture.cancel(true);
}

logEvent(EventMode.END, in_event, in_onAccountOfStep);
l_activeEvent.tearDownEvent();
performTearDown(in_event, in_onAccountOfStep, l_activeEvent);
return l_activeEvent;
}

private static void performWaitTilFinish(String in_event, String in_onAccountOfStep, NonInterruptiveEvent nie) {
try {
nie.waitTillFinished();
} catch (Exception e) {
log.error("The waitTillFinished method for event {} caused an exception in the context of step {}.",
in_event, in_onAccountOfStep);
e.printStackTrace();
nie.threadFuture.cancel(true);
}
}

private static void performTearDown(String in_event, String in_onAccountOfStep, NonInterruptiveEvent l_activeEvent) {
try {
l_activeEvent.tearDownEvent();
} catch (Exception e) {
log.error("The tearDownEvent method for event {} caused an exception of type {} in the context of step {}.",
in_event, e.getCause(), in_onAccountOfStep);
e.printStackTrace();
l_activeEvent.threadFuture.cancel(true);
}
}

public static List<PhasedEventLogEntry> getEventLogs() {
return eventLogs;
}
Expand Down
106 changes: 74 additions & 32 deletions src/main/java/com/adobe/campaign/tests/integro/phased/Phases.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,98 +11,140 @@
*/
package com.adobe.campaign.tests.integro.phased;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public enum Phases {
PRODUCER(true), CONSUMER(true), NON_PHASED(false), ASYNCHRONOUS(false);
PRODUCER(true, new ArrayList<>()),
CONSUMER(true, new ArrayList<>()),
NON_PHASED(false, new ArrayList<>()),
ASYNCHRONOUS(false, new ArrayList<>()) {
public boolean isSelected() {
return this.equals(getCurrentPhase()) || Phases.NON_INTERRUPTIVE.equals(getCurrentPhase());
};
},
NON_INTERRUPTIVE(false, Arrays.asList( "23", "33" )) {
public boolean isSelected() {
return this.equals(getCurrentPhase()) || Phases.ASYNCHRONOUS.equals(getCurrentPhase());
};
},
INTERRUPTIVE(false, Arrays.asList( "PRODUCER", "CONSUMER" )) {
public boolean isSelected() {
return this.equals(getCurrentPhase()) || Phases.PRODUCER.equals(getCurrentPhase())
|| Phases.CONSUMER.equals(getCurrentPhase());
};
};

boolean hasSplittingEvent;
List<String> phaseTypes;

Phases(boolean in_isInPhase) {
Phases(boolean in_isInPhase, List<String> in_phaseTypes) {
hasSplittingEvent = in_isInPhase;
phaseTypes = in_phaseTypes;
}

/**
* Returns the Phased Test state in which the current test session is being
* executed
*
* Returns the Phased Test state in which the current test session is being executed
* <p>
* Author : gandomi
*
* @return The phase which is currently being executed
*
*/
public static Phases getCurrentPhase() {
return fetchCorrespondingPhase(ConfigValueHandlerPhased.PROP_SELECTED_PHASE.fetchValue());
}

/**
* We find a corresponding PhasedTest state given a string. If none are
* found we return INACTIVE
*
* We find a corresponding PhasedTest state given a string. If none are found we return INACTIVE
* <p>
* Author : gandomi
*
* @param in_stateValue
* Returns a Phase given a string representation of its value
* @return A state corresponding to the given Phased State, if none found we
* return inactive
*
* @param in_stateValue Returns a Phase given a string representation of its value
* @return A state corresponding to the given Phased State, if none found we return inactive
*/
public static Phases fetchCorrespondingPhase(String in_stateValue) {
for (Phases lt_ptState : Phases.values()) {
if (lt_ptState.toString().equalsIgnoreCase(in_stateValue)) {
if (in_stateValue.toUpperCase().startsWith(lt_ptState.toString().toUpperCase())) {
return lt_ptState;
}
}
return NON_PHASED;
}

/**
* Checks if the current entry is active. I.e. either producer or consumer
* Provides an array of Phases that contain a splitting Event aka PhasedEvent
* <p>
* Author : gandomi
*
* @return An array of Phases that have a Splitting Event
*/
public static Phases[] fetchPhasesWithEvents() {
return Arrays.stream(Phases.values())
.filter(p -> p.hasSplittingEvent)
.toArray(Phases[]::new);
}

public boolean isTypeValid() {
String l_currentType = fetchType();
if (phaseTypes.isEmpty()) {
return l_currentType.isEmpty();
}
return phaseTypes.contains(l_currentType);
}

/**
* Checks if the current entry is active. I.e. either producer or consumer
* <p>
* Author : gandomi
*
* @return true if we are the active state
*
*/
public boolean isSelected() {
return this.equals(getCurrentPhase());
}

/**
* Lets us know if the current phase will include a splitting event
*
* <p>
* Author : gandomi
*
* @return True if the the phase could have a splitting event.
*
*/
public boolean hasSplittingEvent() {
return this.hasSplittingEvent;
}

/**
* Activates the given phase
*
* <p>
* Author : gandomi
*
*
*/
void activate() {
ConfigValueHandlerPhased.PROP_SELECTED_PHASE.activate(this.name());
}

/**
* Provides an array of Phases that contain a plittingEvent aka PhasedEvent
*
* Author : gandomi
*
* @return An array of Phases that have a Splitting Event
*
* Activates the given phase with the given type
* @param in_phaseType
*/
public static Phases[] fetchPhasesWithEvents() {
return Arrays.stream(Phases.values())
.filter(p -> p.hasSplittingEvent)
.toArray(Phases[]::new);
public void activate(String in_phaseType) {
if (!phaseTypes.contains(in_phaseType)) {
throw new IllegalArgumentException("The given phase type is not valid for this mode.");
}

ConfigValueHandlerPhased.PROP_SELECTED_PHASE.activate(this.name() + "(" + in_phaseType + ")");
}

public String fetchType() {
String l_value = ConfigValueHandlerPhased.PROP_SELECTED_PHASE.fetchValue();
int l_startIndex = l_value.indexOf("(");
int l_endIndex = l_value.indexOf(")");

if (l_startIndex != -1 && l_endIndex != -1) {
return l_value.substring(l_startIndex + 1, l_endIndex);
}
return "";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ public class PhasedTestingEventException extends RuntimeException {
public PhasedTestingEventException(String message) {
super(message);
}

public PhasedTestingEventException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/
package com.adobe.campaign.tests.integro.phased;

import com.adobe.campaign.tests.integro.phased.utils.GeneralTestUtils;
import org.hamcrest.Matchers;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
Expand Down Expand Up @@ -99,5 +100,56 @@ public void testPhasesFetchWithEvents() {
}


@Test
public void testNonInterruptivePhase() {
Phases.ASYNCHRONOUS.activate();

assertThat("This should be the same as Non-interruptive", Phases.NON_INTERRUPTIVE.isSelected());
assertThat("This should be the same as Non-interruptive", Phases.ASYNCHRONOUS.isSelected());

Phases.NON_INTERRUPTIVE.activate();

assertThat("This should be the same as Non-interruptive", Phases.NON_INTERRUPTIVE.isSelected());
assertThat("This should be the same as Non-interruptive", Phases.ASYNCHRONOUS.isSelected());

//ConfigValueHandlerPhased.PROP_SELECTED_PHASE.activate(Phases.NON_INTERRUPTIVE.name()+"23");

}

@Test
public void testNonInterruptivePhaseWithEvents() {
//assertThat("We should be able to extract the phase value from the string", GeneralTestUtils);

String l_selectedPhase = Phases.NON_INTERRUPTIVE.name() + "(23)";
assertThat("We should detect the correct phase",Phases.fetchCorrespondingPhase(l_selectedPhase), Matchers.equalTo(Phases.NON_INTERRUPTIVE));

ConfigValueHandlerPhased.PROP_SELECTED_PHASE.activate(l_selectedPhase);

assertThat("This should be the same as Non-interruptive", Phases.NON_INTERRUPTIVE.isSelected());
assertThat("This should be the same as Non-interruptive", Phases.NON_INTERRUPTIVE.fetchType(), Matchers.equalTo("23"));
assertThat("We should detect that the given value is corrects",Phases.getCurrentPhase().isTypeValid());


ConfigValueHandlerPhased.PROP_SELECTED_PHASE.activate(Phases.NON_INTERRUPTIVE.name());
assertThat("This should be the same as Non-interruptive", Phases.NON_INTERRUPTIVE.fetchType(), Matchers.equalTo(""));
assertThat("We should not accept an empty type",!Phases.getCurrentPhase().isTypeValid());


ConfigValueHandlerPhased.PROP_SELECTED_PHASE.activate(Phases.NON_INTERRUPTIVE.name());
assertThat("This should be the same as Non-interruptive", Phases.NON_INTERRUPTIVE.fetchType(), Matchers.equalTo(""));

ConfigValueHandlerPhased.PROP_SELECTED_PHASE.activate(Phases.INTERRUPTIVE.name()+"(jhfdhj)");
assertThat("We should detect that given type is incorrect",!Phases.getCurrentPhase().isTypeValid());

Phases.NON_PHASED.activate();
assertThat("This should be the same as Non-phased", Phases.getCurrentPhase().fetchType(), Matchers.equalTo(""));
assertThat("We should accept an empty type",Phases.getCurrentPhase().isTypeValid());

Phases.NON_INTERRUPTIVE.activate("33");
assertThat("This should be the same as Non-interruptive", Phases.getCurrentPhase().fetchType(), Matchers.equalTo("33"));

}



}
Loading

0 comments on commit 3d4098a

Please sign in to comment.