/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.compiler.phreak;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.common.TupleSets;
import org.drools.core.common.TupleSetsImpl;
import org.drools.core.phreak.PhreakExistsNode;
import org.drools.core.phreak.PhreakJoinNode;
import org.drools.core.phreak.PhreakNotNode;
import org.drools.core.phreak.SegmentPropagator;
import org.drools.core.reteoo.BetaMemory;
import org.drools.core.reteoo.BetaNode;
import org.drools.core.reteoo.ExistsNode;
import org.drools.core.reteoo.JoinNode;
import org.drools.core.reteoo.LeftTuple;
import org.drools.core.reteoo.LeftTupleSink;
import org.drools.core.reteoo.NotNode;
import org.drools.core.reteoo.RightTuple;
import org.drools.core.reteoo.SegmentMemory;
import org.drools.core.reteoo.TupleMemory;
import org.drools.core.spi.Tuple;
import org.drools.core.util.FastIterator;
import org.junit.Assert;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
public class Scenario {
/**
*
*/
Class phreakNode;
BetaNode betaNode;
LeftTupleSink sinkNode;
BetaMemory bm;
InternalWorkingMemory wm;
TupleSets<LeftTuple> leftTuples;
TupleSets<RightTuple> rightRuples;
StagedBuilder expectedResultBuilder;
TupleSets<LeftTuple> actualResultLeftTuples;
TupleSets<LeftTuple> previousResultTuples;
List<StagedBuilder> preStagedBuilders;
List<StagedBuilder> postStagedBuilders;
List<LeftTuple> leftMemory;
List<RightTuple> rightMemory;
private boolean testLeftMemory;
private boolean testRightMemory;
public Scenario(Class phreakNode,
BetaNode betaNode,
LeftTupleSink sinkNode,
BetaMemory bm,
InternalWorkingMemory wm) {
this.phreakNode = phreakNode;
this.betaNode = betaNode;
this.sinkNode = sinkNode;
this.bm = bm;
this.wm = wm;
this.leftTuples = new TupleSetsImpl<LeftTuple>();
this.rightRuples = new TupleSetsImpl<RightTuple>();
this.preStagedBuilders = new ArrayList<StagedBuilder>();
this.postStagedBuilders = new ArrayList<StagedBuilder>();
this.bm.setStagedRightTuples(rightRuples);
this.leftMemory = new ArrayList<LeftTuple>();
this.rightMemory = new ArrayList<RightTuple>();
}
public StagedBuilder getExpectedResultBuilder() {
return expectedResultBuilder;
}
public void setExpectedResultBuilder(StagedBuilder stagedBuilder) {
this.expectedResultBuilder = stagedBuilder;
}
public boolean isTestLeftMemory() {
return testLeftMemory;
}
public void setTestLeftMemory(boolean testLeftMemory) {
this.testLeftMemory = testLeftMemory;
}
public boolean isTestRightMemory() {
return testRightMemory;
}
public void setTestRightMemory(boolean testRightMemory) {
this.testRightMemory = testRightMemory;
}
public TupleSets<LeftTuple> getActualResultLeftTuples() {
return actualResultLeftTuples;
}
public void addPreStagedBuilder(StagedBuilder stagedBuilder) {
this.preStagedBuilders.add( stagedBuilder );
}
public void addPostStagedBuilder(StagedBuilder stagedBuilder) {
this.postStagedBuilders.add( stagedBuilder );
}
public LeftBuilder left() {
return new LeftBuilder( this );
}
public RightBuilder right() {
return new RightBuilder( this );
}
public BetaNode getBetaNode() {
return betaNode;
}
public LeftTupleSink getSinkNode() {
return sinkNode;
}
public BetaMemory getBm() {
return bm;
}
public InternalWorkingMemory getWorkingMemory() {
return wm;
}
public TupleSets<RightTuple> getRightRuples() {
return rightRuples;
}
public TupleSets<LeftTuple> getLeftTuples() {
return leftTuples;
}
public TupleSets<RightTuple> getRightTuples() {
return rightRuples;
}
public List<LeftTuple> getLeftMemory() {
return leftMemory;
}
public List<RightTuple> getRightMemory() {
return rightMemory;
}
public Scenario run() {
previousResultTuples = bm.getSegmentMemory().getFirst().getStagedLeftTuples();
actualResultLeftTuples = new TupleSetsImpl<LeftTuple>();
if ( phreakNode == PhreakJoinNode.class ) {
new PhreakJoinNode().doNode( (JoinNode) betaNode, sinkNode,
bm, wm, leftTuples, actualResultLeftTuples, previousResultTuples );
} else if ( phreakNode == PhreakNotNode.class ) {
new PhreakNotNode().doNode( (NotNode) betaNode, sinkNode,
bm, wm, leftTuples, actualResultLeftTuples, previousResultTuples );
} else if ( phreakNode == PhreakExistsNode.class ) {
new PhreakExistsNode().doNode( (ExistsNode) betaNode, sinkNode,
bm, wm, leftTuples, actualResultLeftTuples, previousResultTuples );
}
if ( expectedResultBuilder != null ) {
assertEquals( expectedResultBuilder.get(), actualResultLeftTuples,
expectedResultBuilder.isTestStagedInsert(), expectedResultBuilder.isTestStagedDelete(), expectedResultBuilder.isTestStagedUpdate() );
}
if ( !preStagedBuilders.isEmpty() ) {
for ( StagedBuilder stagedBuilder : preStagedBuilders ) {
TupleSets<LeftTuple> expected = stagedBuilder.get();
TupleSets<LeftTuple> actual = stagedBuilder.getSegmentMemory().getStagedLeftTuples();
assertEquals( expected, actual, stagedBuilder.isTestStagedInsert(), stagedBuilder.isTestStagedDelete(), stagedBuilder.isTestStagedUpdate() );
}
}
SegmentMemory smem = bm.getSegmentMemory();
SegmentPropagator.propagate(smem, actualResultLeftTuples, wm);
if ( testLeftMemory ) {
equalsLeftMemory( leftMemory );
}
if ( testRightMemory) {
equalsRightMemory( rightMemory );
}
if ( !postStagedBuilders.isEmpty() ) {
for ( StagedBuilder stagedBuilder : postStagedBuilders ) {
TupleSets<LeftTuple> expected = stagedBuilder.get();
TupleSets<LeftTuple> actual = stagedBuilder.getSegmentMemory().getStagedLeftTuples();
assertEquals( expected, actual, stagedBuilder.isTestStagedInsert(), stagedBuilder.isTestStagedDelete(), stagedBuilder.isTestStagedUpdate() );
}
}
return this;
}
public StagedBuilder result() {
StagedBuilder stagedBuilder = new StagedBuilder( this, null );
setExpectedResultBuilder( stagedBuilder );
return stagedBuilder;
}
public StagedBuilder preStaged(SegmentMemory sm) {
StagedBuilder stagedBuilder = new StagedBuilder( this, sm );
addPreStagedBuilder( stagedBuilder );
return stagedBuilder;
}
public StagedBuilder postStaged(SegmentMemory sm) {
StagedBuilder stagedBuilder = new StagedBuilder( this, sm );
addPostStagedBuilder( stagedBuilder );
return stagedBuilder;
}
public void assertEquals(TupleSets<LeftTuple> expected,
TupleSets<LeftTuple> actual,
boolean testInsert,
boolean testDelete,
boolean testUpdate) {
Tuple expectedTuple;
Tuple actualTuple;
if ( testInsert ) {
if ( expected.getInsertFirst() != null ) {
expectedTuple = expected.getInsertFirst();
actualTuple = actual.getInsertFirst();
int i = 0;
for ( ; expectedTuple != null; expectedTuple = expectedTuple.getStagedNext() ) {
Assert.assertTrue("insert " + i + ":\n" + actualTuple + "\nis not the expected\n" + expectedTuple, equals(expectedTuple, actualTuple));
actualTuple = actualTuple.getStagedNext();
i++;
}
assertNull( "Insert excpected more", actualTuple );
} else if ( actual.getInsertFirst() != null ) {
fail( "Expected nothing, but insert existed" );
}
}
if ( testDelete ) {
if ( expected.getDeleteFirst() != null ) {
expectedTuple = expected.getDeleteFirst();
actualTuple = actual.getDeleteFirst();
int i = 0;
for ( ; expectedTuple != null; expectedTuple = expectedTuple.getStagedNext() ) {
Assert.assertTrue( "delete " + i + ":\n" + actualTuple + "\nis not the expected\n" + expectedTuple, equals( expectedTuple, actualTuple ) );
actualTuple = actualTuple.getStagedNext();
i++;
}
assertNull( "Delete excpected more", actualTuple );
} else if ( actual.getDeleteFirst() != null ) {
fail( "Expected nothing, but delete existed" );
}
}
if ( testUpdate ) {
if ( expected.getUpdateFirst() != null ) {
expectedTuple = expected.getUpdateFirst();
actualTuple = actual.getUpdateFirst();
int i = 0;
for ( ; expectedTuple != null; expectedTuple = expectedTuple.getStagedNext() ) {
Assert.assertTrue( "update " + i + ":\n" + actualTuple + "\nis not the expected\n" + expectedTuple, equals( expectedTuple, actualTuple ) );
actualTuple = actualTuple.getStagedNext();
i++;
}
assertNull( "Update excpected more", actualTuple );
} else if ( actual.getUpdateFirst() != null ) {
fail( "Expected nothing, but update existed" );
}
}
}
public boolean equals(final Tuple expected, Tuple actual) {
// we know the object is never null and always of the type LeftTuple
if ( expected == actual ) {
return true;
}
if ( expected == null ) {
return actual == null;
} else if ( actual == null ) {
return expected == null;
}
while ( actual.getFactHandle() == null ) {
// skip exists, not, evals
actual = actual.getParent();
}
// A LeftTuple is only the same if it has the same hashCode, factId and parent
return expected.hashCode() == actual.hashCode() &&
expected.getFactHandle() == actual.getFactHandle() &&
equals( expected.getParent(), actual.getParent() );
}
public void equalsLeftMemory(List<LeftTuple> leftTuples) {
TupleMemory ltm = bm.getLeftTupleMemory();
int length = 0;
for ( LeftTuple expectedLeftTuple : leftTuples ) {
FastIterator it = betaNode.getLeftIterator( ltm );
Tuple actualLeftTuple = null;
for ( actualLeftTuple = BetaNode.getFirstTuple( ltm, it ); actualLeftTuple != null; actualLeftTuple = (LeftTuple) it.next( actualLeftTuple ) ) {
if ( expectedLeftTuple.equals( actualLeftTuple ) ) {
length++;
break;
}
}
if ( actualLeftTuple == null ) {
fail( "Could not find LeftTuple: " + expectedLeftTuple );
}
}
if ( leftTuples.size() != ltm.size() ) {
fail( "LeftTuple memory size did not match: " + length );
}
}
public void equalsRightMemory(List<RightTuple> rightTuples) {
TupleMemory rtm = bm.getRightTupleMemory();
int length = 0;
for ( RightTuple expectedRightTuple : rightTuples ) {
FastIterator it = betaNode.getRightIterator( rtm );
Tuple actualRightTuple = null;
for ( actualRightTuple = BetaNode.getFirstTuple( rtm, it ); actualRightTuple != null; actualRightTuple = (RightTuple) it.next( actualRightTuple ) ) {
if ( expectedRightTuple.equals( actualRightTuple ) ) {
length++;
break;
}
}
if ( actualRightTuple == null ) {
fail( "Could not find RightTuple: " + expectedRightTuple );
}
}
if ( rightTuples.size() != rtm.size() ) {
fail( "RightTuple memory size did not match: " + length );
}
}
}