Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple exec configs breaks report #75

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Requirements
* Glossary changes - got rid of the noise when extracting substeps tag info. Enabled the migration to new qualified custom glossary tags 'org.substeps.step.example' and 'org.substeps.step.section'
* some sonar suggested fixes
* If a -Denvironment= variable is set, pass through to the forked VM process. Can be overriden from the parent process using the vmArgs parameter in config if required.
* Multiple execution configs cause issues with the report when running in forked mode, only the second set of results are visible. #74

1.1.2
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,14 +461,45 @@ class ExecutionResultsCollector extends IExecutionResultsCollector {
case class FeatureSummary(nodeType: String, filename: String, result : String, id : Long,
executionDurationMillis : Option[Long], description : String, scenarios: List[ScenarioSummary], tags : List[String])

object FeatureSummary {
def sequenceIds(summary: FeatureSummary, toAdd: Long): FeatureSummary = {
summary.copy(id = summary.id + toAdd, scenarios = ScenarioSummary.sequenceIds(summary.scenarios, toAdd))
}
}

case class ScenarioSummary(nodeId : Long, filename : String, result: String, tags : List[String])

object ScenarioSummary {
def sequenceIds(scenarios: List[ScenarioSummary], toAdd : Long): scala.List[ScenarioSummary] = {

scenarios.map(s => {
s.copy(nodeId = s.nodeId + toAdd)
})
}
}


case class FeatureSummaryForRootNode(nodeId : Long, resultsDir: String, result : String)

object FeatureSummaryForRootNode {
def sequenceIds(features: List[FeatureSummaryForRootNode], toAdd: Long): scala.List[FeatureSummaryForRootNode] = {

features.map(f => {
f.copy(nodeId = f.nodeId + toAdd)
})
}
}

case class RootNodeSummary(nodeType: String, description: String, result : String, id : Long,
executionDurationMillis : Option[Long], features : List[FeatureSummaryForRootNode], tags : Option[String], nonFatalTags : Option[String], timestamp : Long, environment : String)

object RootNodeSummary {
def sequenceIds(rootNodeSummary: RootNodeSummary, toAdd: Long): RootNodeSummary = {

rootNodeSummary.copy(id = rootNodeSummary.id + toAdd, features = FeatureSummaryForRootNode.sequenceIds(rootNodeSummary.features, toAdd))
}
}


case class SubstepsNode(id : Long, nodeType: String, description: String, children : List[SubstepsNode])

Expand Down
9 changes: 9 additions & 0 deletions core/src/main/scala/org/substeps/report/NodeDetail.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ case class NodeDetail(nodeType: String, filename: String, lineNumber : Int, resu


case object NodeDetail {

def sequenceIds(nodeDetails: List[NodeDetail], toAdd: Long): scala.List[NodeDetail] = {

nodeDetails.map(n => {
n.copy(id = n.id + toAdd, children = sequenceIds(n.children, toAdd))
})
}


def basicScenarioNodeInError(scenarioNode: BasicScenarioNode, children: List[NodeDetail], tags: Option[List[String]]) = {

val stackTrace = scenarioNode.getResult.getFailure.getCause.getStackTrace.toList.map(elem => elem.toString)
Expand Down
43 changes: 36 additions & 7 deletions core/src/main/scala/org/substeps/report/ReportBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,40 @@ object ReportBuilder {

case class FeatureDetails(summary : FeatureSummary, nodeDetails : List[NodeDetail])

object FeatureDetails {
def sequenceIds(featuresList: List[FeatureDetails], toAdd: Long): scala.List[_root_.org.substeps.report.FeatureDetails] = {

featuresList.map(f => {
f.copy(summary = FeatureSummary.sequenceIds(f.summary, toAdd), nodeDetails = NodeDetail.sequenceIds(f.nodeDetails, toAdd))
})
}
}

case class SourceDataModel(rootNodeSummary : RootNodeSummary, featuresList : List[FeatureDetails], config : Config)

case object SourceDataModel{

def sequenceIds(srcDataList: List[SourceDataModel]) : List[SourceDataModel] = {



srcDataList match {
case sdm :: Nil => srcDataList
case head :: tail => {

var toAdd = head.rootNodeSummary.id
// renumber the tail list
val newTail =
tail.map(sd => {
val copied = sd.copy(rootNodeSummary = RootNodeSummary.sequenceIds(sd.rootNodeSummary, toAdd) , featuresList = FeatureDetails.sequenceIds(sd.featuresList, toAdd))
toAdd = copied.rootNodeSummary.id
copied
})
head :: newTail
}
}
}


}

Expand All @@ -101,7 +131,7 @@ case class UncalledStepImpl(value:String, implementedIn: String, keyword: String
/**
* Created by ian on 30/06/16.
*/
class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTreeTemplate with GlossaryTemplate {
class ReportBuilder extends IReportBuilder with IndexPageTemplate with UsageTreeTemplate with GlossaryTemplate {

// TODO need to leave here as legacy to ensure maven is able to inject in parameter, mojo fails otherwise
@BeanProperty
Expand Down Expand Up @@ -223,7 +253,7 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr

processUncalledAndUnusedDataFiles( dataDir, executionConfigs)

val srcDataList: List[SourceDataModel] = readModels(dataDir, executionConfigs)
val srcDataList: List[SourceDataModel] = SourceDataModel.sequenceIds(readModels(dataDir, executionConfigs))

val detailData = createFile( "detail_data.js")

Expand Down Expand Up @@ -680,7 +710,7 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr
f
}

def writeResultSummary(resultsFile: RootNodeSummary)(implicit reportDir : File): Unit = {
def writeResultSummaryX(resultsFile: RootNodeSummary)(implicit reportDir : File): Unit = {

val file = createFile("results-summary.js")

Expand Down Expand Up @@ -734,7 +764,7 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr
resultsFileOption match {
case Some(resultsFile) => {

writeResultSummary(resultsFile)
//writeResultSummary(resultsFile)

resultsFile.features.flatMap(featureSummary => {

Expand Down Expand Up @@ -910,13 +940,12 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr

val featureSummaries = srcData.featuresList.map(f => f.summary) //srcData._2.map(_._1)

srcData.featuresList.foreach(feature =>{
writeRootNode(writer, srcData.rootNodeSummary, featureSummaries, srcData.config)

srcData.featuresList.foreach(feature =>{

val nodeDetailList = feature.nodeDetails

writeRootNode(writer, srcData.rootNodeSummary, featureSummaries, srcData.config)

val dataSubdir = NewSubstepsExecutionConfig.getDataSubdir(srcData.config)

writeFeatureNode(writer, feature.summary, nodeDetailList, dataSubdir)
Expand Down
8 changes: 1 addition & 7 deletions core/src/main/scala/org/substeps/report/ReportFrame.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package org.substeps.report

import java.time.{Instant, LocalDateTime, ZoneId}
import java.time.format.DateTimeFormatter

import com.typesafe.config.Config

/**
* Created by ian on 18/08/16.
*/


trait ReportFrameTemplate {
trait IndexPageTemplate {


def buildStatsBlock(name: String, counters : Counters) = {
Expand Down Expand Up @@ -87,9 +84,6 @@ trait ReportFrameTemplate {
| <link href="css/substeps.css" rel="stylesheet"/>
|
| <link rel="stylesheet" href="css/jstree/style.min.css" />
| <script type="text/javascript" src="results-summary.js"></script>
|
|
|
|</head>
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,77 +26,81 @@
import com.technophobia.substeps.runner.syntax.ClassAnalyser;
import com.technophobia.substeps.runner.syntax.SubStepDefinitionParser;
import com.technophobia.substeps.runner.syntax.SyntaxBuilder;
import com.technophobia.substeps.runner.syntax.validation.fake.FakeSyntaxErrorReporter;
import com.technophobia.substeps.runner.syntax.validation.fake.FakeSyntaxErrorReporter.SyntaxErrorData;
import com.technophobia.substeps.runner.syntax.SyntaxErrorReporter;
import com.technophobia.substeps.stepimplementations.MockStepImplementations;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

import java.io.File;
import java.util.Arrays;
import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

@RunWith(MockitoJUnitRunner.class)
public class SyntaxAwareStepValidatorTest {

private static final String FEATURE_PATH = "./target/test-classes/features/";
private static final String SUBSTEPS_PATH = "./target/test-classes/substeps/";

private FakeSyntaxErrorReporter syntaxErrorReporter;
private FeatureFileParser featureFileParser;
private SubStepDefinitionParser substepsFileParser;

private SyntaxErrorReporter mock;

@Before
public void initialise() {

this.syntaxErrorReporter = new FakeSyntaxErrorReporter();
this.mock = Mockito.mock(SyntaxErrorReporter.class);
this.featureFileParser = new FeatureFileParser();
this.substepsFileParser = new SubStepDefinitionParser(this.syntaxErrorReporter);
this.substepsFileParser = new SubStepDefinitionParser(mock);
}


@Test
public void validatorReportsMissingStepsInScenario() {
final FeatureFile featureFile = this.featureFileParser.loadFeatureFile(createFeatureFile("error.feature"));
File ff = createFeatureFile("error.feature");
final FeatureFile featureFile = this.featureFileParser.loadFeatureFile(ff);

createStepValidatorWithSubsteps("simple.substeps").validateFeatureFile(featureFile, syntaxErrorReporter);
final List<SyntaxErrorData> errors = syntaxErrorReporter.syntaxErrors();
assertThat(Integer.valueOf(errors.size()), is(Integer.valueOf(2)));
createStepValidatorWithSubsteps("simple.substeps", mock).validateFeatureFile(featureFile, mock);

checkError(errors.get(0), 6, "Given step 1");
checkError(errors.get(1), 7, "Given step 2");
verify(mock).reportFeatureError(eq(ff), eq("Given step 1"), eq(6), anyInt(), any());
verify(mock).reportFeatureError(eq(ff), eq("Given step 2"), eq(7), anyInt(), any());
}


@Test
public void validatorReportsNoErrorsForFeatureWithValidSteps() {
final FeatureFile featureFile = this.featureFileParser.loadFeatureFile(createFeatureFile("error.feature"));

createStepValidatorWithSubsteps("error.substeps").validateFeatureFile(featureFile, syntaxErrorReporter);
final List<SyntaxErrorData> errors = syntaxErrorReporter.syntaxErrors();
assertTrue(errors.isEmpty());
createStepValidatorWithSubsteps("error.substeps",mock).validateFeatureFile(featureFile, mock);

verify(mock, never()).reportFeatureError(any(),any(),anyInt(),anyInt(),any());

verify(mock, never()).reportSubstepsError(any());
verify(mock, never()).reportStepImplError(any());
}


@Test
public void validatorReportsMissingSubstepsInDefinition() {
final PatternMap<ParentStep> substeps = substepsFileParser.loadSubSteps(createSubstepsFile("error.substeps"));

final StepValidator stepValidator = createStepValidatorWithSubsteps("simple.substeps");
File substepsFile = createSubstepsFile("error.substeps").getAbsoluteFile();

final PatternMap<ParentStep> substeps = substepsFileParser.loadSubSteps(substepsFile);

final StepValidator stepValidator = createStepValidatorWithSubsteps("simple.substeps", mock);
for (final ParentStep substep : substeps.values()) {
stepValidator.validateSubstep(substep, syntaxErrorReporter);
stepValidator.validateSubstep(substep, mock);
}

final List<SyntaxErrorData> errors = syntaxErrorReporter.syntaxErrors();
assertThat(Integer.valueOf(errors.size()), is(Integer.valueOf(3)));
verify(mock).reportFeatureError(eq(substepsFile), eq("SingleWord"), eq(5), eq(101), eq("Step \"SingleWord\" is not defined"));
verify(mock).reportFeatureError(eq(substepsFile), eq("Test_Then something else has happened"), eq(6), anyInt(), any());
verify(mock).reportFeatureError(eq(substepsFile), eq("Test_Then something has happened"), eq(9), anyInt(), any());

checkError(errors.get(0), 5, "SingleWord");
checkError(errors.get(1), 6, "Test_Then something else has happened");
checkError(errors.get(2), 9, "Test_Then something has happened");
}


Expand All @@ -105,38 +109,30 @@ public void validatorReportsNoErrorsForSubstepsWithValidSteps() {
final PatternMap<ParentStep> substeps = this.substepsFileParser
.loadSubSteps(createSubstepsFile("allFeatures.substeps"));

final StepValidator stepValidator = createStepValidatorWithSubsteps("simple.substeps",
final StepValidator stepValidator = createStepValidatorWithSubsteps("simple.substeps", mock,
MockStepImplementations.class);
for (final ParentStep substep : substeps.values()) {
stepValidator.validateSubstep(substep, syntaxErrorReporter);
stepValidator.validateSubstep(substep, mock);
}
final List<SyntaxErrorData> errors = syntaxErrorReporter.syntaxErrors();
assertTrue(errors.isEmpty());
}


private void checkError(final SyntaxErrorData error, final int lineNumber, final String line) {
assertThat(Integer.valueOf(error.getLineNumber()), is(Integer.valueOf(lineNumber)));
assertThat(error.getLine(), is(line));
assertThat(error.getDescription(), is("Step \"" + line + "\" is not defined"));
verify(mock, never()).reportFeatureError(any(),any(),anyInt(),anyInt(),any());
verify(mock, never()).reportSubstepsError(any());
verify(mock, never()).reportStepImplError(any());
}


private File createFeatureFile(final String name) {
return new File(FEATURE_PATH, name);
}


private File createSubstepsFile(final String name) {
return new File(SUBSTEPS_PATH, name);
}


private StepValidator createStepValidatorWithSubsteps(final String substepsFilename,
private StepValidator createStepValidatorWithSubsteps(final String substepsFilename, SyntaxErrorReporter errorReporter,
final Class<?>... stepImplClasses) {
final Syntax syntax = SyntaxBuilder.buildSyntax(Arrays.asList(stepImplClasses),
createSubstepsFile(substepsFilename), true, new String[0], new ClassAnalyser(), true,
this.syntaxErrorReporter);
errorReporter);

return new SyntaxAwareStepValidator(syntax);
}
Expand Down
Loading