/*
* JBoss, Home of Professional Open Source
* Copyright 2012, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.savara.protocol.internal.aggregator;
import static org.junit.Assert.*;
import org.junit.Ignore;
import org.junit.Test;
import org.savara.common.logging.DefaultFeedbackHandler;
import org.savara.common.logging.FeedbackHandler;
import org.savara.protocol.aggregator.ProtocolAggregator;
import org.savara.protocol.util.JournalProxy;
import org.savara.protocol.util.ProtocolServices;
import org.scribble.common.logging.CachedJournal;
import org.scribble.common.resource.Content;
import org.scribble.common.resource.ResourceContent;
import org.scribble.protocol.model.Block;
import org.scribble.protocol.model.Interaction;
import org.scribble.protocol.model.MessageSignature;
import org.scribble.protocol.model.ProtocolModel;
import org.scribble.protocol.model.Repeat;
import org.scribble.protocol.model.Role;
import org.scribble.protocol.model.TypeReference;
import org.scribble.protocol.model.Choice;
public class ProtocolAggregatorImplTest {
// Protocols generated from BPEL
// SAVARA-350 - currently does not aggregate the behaviour correctly
@Test
public void testPurchaseGoods() {
testAggregateGlobalModel("PurchaseGoods", new String[] {
"Store", "CreditAgency", "Logistics"});
}
@Test
public void testMergePathsSimple() {
Block b1=new Block();
Block b2=new Block();
Interaction i1=new Interaction(new Role("CreditAgency"),
new MessageSignature(new TypeReference("CreditOk")));
Interaction i2=new Interaction(new Role("Seller"),
new MessageSignature(new TypeReference("Confirm")));
b1.add(i1);
b1.add(i2);
b2.add(i1);
b2.add(i2);
Block targetPath=new Block();
FeedbackHandler handler=new DefaultFeedbackHandler();
java.util.List<Block> sourcePaths=new java.util.Vector<Block>();
sourcePaths.add(b1);
sourcePaths.add(b2);
ProtocolAggregatorImpl aggregator=new ProtocolAggregatorImpl();
aggregator.mergePaths(sourcePaths, targetPath, handler);
if (targetPath.size() != 2) {
fail("Target path should have two components: "+targetPath.size());
}
if (!targetPath.get(0).equals(i1)) {
fail("First component was unexpected");
}
if (!targetPath.get(1).equals(i2)) {
fail("Second component was unexpected");
}
}
@Test
public void testMergePathsSmallDeviation() {
Block b1=new Block();
Block b2=new Block();
Interaction i1=new Interaction(new Role("P1"),
new MessageSignature(new TypeReference("A")));
Interaction i2=new Interaction(new Role("P2"),
new MessageSignature(new TypeReference("B")));
Interaction i3=new Interaction(new Role("P2"),
new MessageSignature(new TypeReference("C")));
Interaction i4=new Interaction(new Role("P3"),
new MessageSignature(new TypeReference("D")));
b1.add(i1);
b1.add(i2);
b1.add(i4);
b2.add(i1);
b2.add(i3);
b2.add(i4);
Block targetPath=new Block();
FeedbackHandler handler=new DefaultFeedbackHandler();
java.util.List<Block> sourcePaths=new java.util.Vector<Block>();
sourcePaths.add(b1);
sourcePaths.add(b2);
ProtocolAggregatorImpl aggregator=new ProtocolAggregatorImpl();
aggregator.mergePaths(sourcePaths, targetPath, handler);
if (targetPath.size() != 3) {
fail("Target path should have three components: "+targetPath.size());
}
if (!targetPath.get(0).equals(i1)) {
fail("First component was unexpected");
}
if (!(targetPath.get(1) instanceof Choice)) {
fail("Second component should be a choice");
}
Choice c=(Choice)targetPath.get(1);
if (c.getRole() == null) {
fail("Role not set");
}
if (!c.getRole().getName().equals("P2")) {
fail("Choice role not P2");
}
if (c.getPaths().size() != 2) {
fail("Two choice paths expected");
}
Block rb1=c.getPaths().get(0);
if (rb1.size() != 1) {
fail("Choice block 1 should only have single entry: "+rb1.size());
}
if (!rb1.get(0).equals(i2)) {
fail("Choice block 1 should contain i2");
}
Block rb2=c.getPaths().get(1);
if (rb2.size() != 1) {
fail("Choice block 2 should only have single entry: "+rb2.size());
}
if (!rb2.get(0).equals(i3)) {
fail("Choice block 2 should contain i3");
}
if (!targetPath.get(2).equals(i4)) {
fail("Third component was unexpected");
}
}
@Test
public void testMergePathsOptional() {
Block b1=new Block();
Block b2=new Block();
Interaction i1=new Interaction(new Role("P1"),
new MessageSignature(new TypeReference("A")));
Interaction i2=new Interaction(new Role("P2"),
new MessageSignature(new TypeReference("B")));
Interaction i4=new Interaction(new Role("P4"),
new MessageSignature(new TypeReference("D")));
b1.add(i1);
b1.add(i2);
b1.add(i4);
b2.add(i1);
b2.add(i4);
Block targetPath=new Block();
FeedbackHandler handler=new DefaultFeedbackHandler();
java.util.List<Block> sourcePaths=new java.util.Vector<Block>();
sourcePaths.add(b1);
sourcePaths.add(b2);
ProtocolAggregatorImpl aggregator=new ProtocolAggregatorImpl();
aggregator.mergePaths(sourcePaths, targetPath, handler);
if (targetPath.size() != 3) {
fail("Target path should have three components: "+targetPath.size());
}
if (!targetPath.get(0).equals(i1)) {
fail("First component was unexpected");
}
if (!(targetPath.get(1) instanceof Choice)) {
fail("Second component should be a choice");
}
Choice c=(Choice)targetPath.get(1);
if (c.getPaths().size() != 2) {
fail("Two choice paths expected");
}
Block rb1=c.getPaths().get(0);
if (rb1.size() != 1) {
fail("Choice block 1 should only have single entry: "+rb1.size());
}
if (!rb1.get(0).equals(i2)) {
fail("Choice block 1 should contain i2");
}
Block rb2=c.getPaths().get(1);
if (rb2.size() != 0) {
fail("Choice block 2 should only have no entry: "+rb2.size());
}
if (!targetPath.get(2).equals(i4)) {
fail("Third component was unexpected");
}
}
@Test
public void testMergePathsMultiCommonDeviation() {
Block b1=new Block();
Block b2=new Block();
Block b3=new Block();
Interaction i1=new Interaction(new Role("P1"),
new MessageSignature(new TypeReference("A")));
Interaction i2=new Interaction(new Role("P2"),
new MessageSignature(new TypeReference("B")));
Interaction i3=new Interaction(new Role("P3"),
new MessageSignature(new TypeReference("C")));
Interaction i4=new Interaction(new Role("P3"),
new MessageSignature(new TypeReference("D")));
Interaction i5=new Interaction(new Role("P2"),
new MessageSignature(new TypeReference("E")));
Interaction i6=new Interaction(new Role("P6"),
new MessageSignature(new TypeReference("F")));
b1.add(i1);
b1.add(i2);
b1.add(i3);
b1.add(i6);
b2.add(i1);
b2.add(i5);
b2.add(i6);
b3.add(i1);
b3.add(i2);
b3.add(i4);
b3.add(i6);
Block targetPath=new Block();
FeedbackHandler handler=new DefaultFeedbackHandler();
java.util.List<Block> sourcePaths=new java.util.Vector<Block>();
sourcePaths.add(b1);
sourcePaths.add(b2);
sourcePaths.add(b3);
ProtocolAggregatorImpl aggregator=new ProtocolAggregatorImpl();
aggregator.mergePaths(sourcePaths, targetPath, handler);
if (targetPath.size() != 3) {
fail("Target path should have three components: "+targetPath.size());
}
if (!targetPath.get(0).equals(i1)) {
fail("First component was unexpected");
}
if (!(targetPath.get(1) instanceof Choice)) {
fail("Second component should be a choice");
}
if (!targetPath.get(2).equals(i6)) {
fail("Third component was unexpected");
}
Choice c=(Choice)targetPath.get(1);
if (c.getRole() == null) {
fail("Role not set");
}
if (!c.getRole().getName().equals("P2")) {
fail("Choice role not P2");
}
if (c.getPaths().size() != 2) {
fail("Two choice paths expected");
}
Block rb1=c.getPaths().get(0);
if (rb1.size() != 2) {
fail("Choice block 1 should only have 2 entries: "+rb1.size());
}
if (!rb1.get(0).equals(i2)) {
fail("Choice block 1 should contain i2");
}
if (!(rb1.get(1) instanceof Choice)) {
fail("Second component in first choice path should be another choice");
}
Choice innerChoice=(Choice)rb1.get(1);
if (innerChoice.getRole() == null) {
fail("Role not set");
}
if (!innerChoice.getRole().getName().equals("P3")) {
fail("Choice role not P3");
}
if (innerChoice.getPaths().size() != 2) {
fail("Inner choice should have two paths");
}
Block innerrb1=innerChoice.getPaths().get(0);
if (innerrb1.size() != 1) {
fail("Choice inner block 1 should only have 1 entry: "+innerrb1.size());
}
if (!innerrb1.get(0).equals(i3)) {
fail("Choice inner block 1 should contain i3");
}
Block innerrb2=innerChoice.getPaths().get(1);
if (innerrb2.size() != 1) {
fail("Choice inner block 2 should only have 1 entry: "+innerrb2.size());
}
if (!innerrb2.get(0).equals(i4)) {
fail("Choice inner block 2 should contain i4");
}
Block rb2=c.getPaths().get(1);
if (rb2.size() != 1) {
fail("Choice block 2 should only have 1 entry: "+rb2.size());
}
if (!rb2.get(0).equals(i5)) {
fail("Choice block 2 should contain i5");
}
}
@Test
public void testMergePathsRepeatWithBeforeAndAfterInteractions() {
Block b1=new Block();
Block b2=new Block();
Block b3=new Block();
Interaction i1=new Interaction(new Role("P1"),
new MessageSignature(new TypeReference("A")));
Interaction i2=new Interaction(new Role("P2"),
new MessageSignature(new TypeReference("B")));
Interaction i3=new Interaction(new Role("P3"),
new MessageSignature(new TypeReference("C")));
Interaction i4=new Interaction(new Role("P4"),
new MessageSignature(new TypeReference("D")));
b1.add(i1);
b1.add(i2);
b1.add(i3);
b1.add(i4);
b2.add(i1);
b2.add(i2);
b2.add(i3);
b2.add(i2);
b2.add(i3);
b2.add(i4);
b3.add(i1);
b3.add(i4);
Block targetPath=new Block();
FeedbackHandler handler=new DefaultFeedbackHandler();
java.util.List<Block> sourcePaths=new java.util.Vector<Block>();
sourcePaths.add(b1);
sourcePaths.add(b2);
sourcePaths.add(b3);
ProtocolAggregatorImpl aggregator=new ProtocolAggregatorImpl();
aggregator.mergePaths(sourcePaths, targetPath, handler);
aggregator.postProcessMerged(targetPath, handler);
if (targetPath.size() != 3) {
fail("Target path should have three components: "+targetPath.size());
}
if (!targetPath.get(0).equals(i1)) {
fail("First component was unexpected");
}
if (!(targetPath.get(1) instanceof Repeat)) {
fail("Second component should be a repeat");
}
if (!targetPath.get(2).equals(i4)) {
fail("Third component was unexpected");
}
Repeat r=(Repeat)targetPath.get(1);
if (r.getRoles().size() == 0) {
fail("Role not set");
}
if (!r.getRoles().get(0).getName().equals("P2")) {
fail("Repeat role not P2");
}
if (r.getBlock().size() != 2) {
fail("Repeat should have two components: "+r.getBlock().size());
}
if (!r.getBlock().get(0).equals(i2)) {
fail("Repeat component 1 should contain i2");
}
if (!r.getBlock().get(1).equals(i3)) {
fail("Repeat component 2 should contain i3");
}
}
@Test
public void testMergePathsRepeatWithoutBeforeAndAfterInteractions() {
Block b1=new Block();
Block b2=new Block();
Block b3=new Block();
Interaction i2=new Interaction(new Role("P2"),
new MessageSignature(new TypeReference("B")));
Interaction i3=new Interaction(new Role("P3"),
new MessageSignature(new TypeReference("C")));
b1.add(i2);
b1.add(i3);
b2.add(i2);
b2.add(i3);
b2.add(i2);
b2.add(i3);
b3.add(i2);
b3.add(i3);
b3.add(i2);
b3.add(i3);
b3.add(i2);
b3.add(i3);
Block targetPath=new Block();
FeedbackHandler handler=new DefaultFeedbackHandler();
java.util.List<Block> sourcePaths=new java.util.Vector<Block>();
sourcePaths.add(b1);
sourcePaths.add(b2);
sourcePaths.add(b3);
ProtocolAggregatorImpl aggregator=new ProtocolAggregatorImpl();
aggregator.mergePaths(sourcePaths, targetPath, handler);
aggregator.postProcessMerged(targetPath, handler);
if (targetPath.size() != 3) {
fail("Target path should have three components: "+targetPath.size());
}
if (!targetPath.get(0).equals(i2)) {
fail("Component 1 should be i2");
}
if (!targetPath.get(1).equals(i3)) {
fail("Component 2 should be i3");
}
if (!(targetPath.get(2) instanceof Repeat)) {
fail("Component 3 should be a repeat");
}
Repeat repeat=(Repeat)targetPath.get(2);
if (repeat.getRoles().size() == 0) {
fail("Role not set");
}
if (!repeat.getRoles().get(0).getName().equals("P2")) {
fail("Repeat role not P2");
}
if (repeat.getBlock().size() != 2) {
fail("Repeat should only have 2 components");
}
if (!repeat.getBlock().get(0).equals(i2)) {
fail("Repeat Component 1 should be i2");
}
if (!repeat.getBlock().get(1).equals(i3)) {
fail("Repeat Component 2 should be i3");
}
}
@Test
public void testPurchasingLocalAggregationAtBuyer() {
testAggregateLocalModel("Purchasing", "Buyer", new String[]{
"SuccessfulPurchase", "CustomerUnknown", "InsufficientCredit"});
}
@Test
public void testPurchasingLocalAggregationAtStore() {
testAggregateLocalModel("Purchasing", "Store", new String[]{
"SuccessfulPurchase", "CustomerUnknown", "InsufficientCredit"});
}
@Test
public void testPurchasingLocalAggregationAtCreditAgency() {
testAggregateLocalModel("Purchasing", "CreditAgency", new String[]{
"SuccessfulPurchase", "CustomerUnknown", "InsufficientCredit"});
}
@Test
public void testPurchasingLocalAggregationAtLogistics() {
testAggregateLocalModel("Purchasing", "Logistics", new String[]{
"SuccessfulPurchase"});
}
@Test
public void testPurchasing() {
testAggregateGlobalModel("Purchasing", new String[] {
"Buyer", "Store", "CreditAgency", "Logistics"});
}
/* Behaviour must be identical but imports and annotations maybe in different order
@Test
public void testPurchasingReorderedRoles() {
testAggregateGlobalModel("Purchasing", new String[] {
"CreditAgency", "Logistics", "Buyer", "Store"});
}
*/
@Test
public void testPurchasing2() {
testAggregateGlobalModel("Purchasing2", new String[] {
"Buyer", "Store", "CreditAgency", "Logistics"});
}
@Test
public void testMultiPartyInteractionsAndChoice() {
testAggregateGlobalModel("MultiPartyInteractionsAndChoice", new String[] {
"Buyer", "Broker", "CreditAgency", "Seller"});
}
@Test
public void testBarterLocalAggregationAtBuyer() {
testAggregateLocalModel("Barter", "Buyer", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept"});
// TODO: Allow alternate paths after repetition
//"FirstOfferRejected", "SecondOfferRejected", "ThirdOfferRejected"});
}
@Test
public void testBarterLocalAggregationAtSeller() {
testAggregateLocalModel("Barter", "Seller", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept"});
// TODO: Allow alternate paths after repetition
//"FirstOfferRejected", "SecondOfferRejected", "ThirdOfferRejected"});
}
@Test
public void testBarter() {
testAggregateGlobalModel("Barter", new String[] {
"Buyer", "Seller"});
}
@Test
public void testBarterLocalAggregationWithRejectPathAtBuyer() {
testAggregateLocalModel("BarterWithReject", "Buyer", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept",
"FirstOfferRejected"});
}
@Test
public void testBarterLocalAggregationWithRejectPathAtSeller() {
testAggregateLocalModel("BarterWithReject", "Seller", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept",
"FirstOfferRejected"});
}
@Test
@Ignore("SAVARA-337")
public void testBarterLocalAggregationWithReject2PathAtBuyer() {
testAggregateLocalModel("BarterWithReject2", "Buyer", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept",
"FirstOfferRejected", "SecondOfferRejected"});
}
@Test
@Ignore("SAVARA-337")
public void testBarterLocalAggregationWithReject2PathAtSeller() {
testAggregateLocalModel("BarterWithReject2", "Seller", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept",
"FirstOfferRejected", "SecondOfferRejected"});
}
@Test
public void testBarterLocalAggregationWithReject3PathAtBuyer() {
testAggregateLocalModel("BarterWithReject3", "Buyer", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept",
"FirstOfferRejected", "ThirdOfferRejected"});
}
@Test
public void testBarterLocalAggregationWithReject3PathAtSeller() {
testAggregateLocalModel("BarterWithReject3", "Seller", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept",
"FirstOfferRejected", "ThirdOfferRejected"});
}
@Test
public void testBarterLocalAggregationWithReject4PathAtBuyer() {
testAggregateLocalModel("BarterWithReject4", "Buyer", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept",
"FirstOfferRejected", "SecondOfferRejected", "ThirdOfferRejected"});
}
@Test
public void testBarterLocalAggregationWithReject4PathAtSeller() {
testAggregateLocalModel("BarterWithReject4", "Seller", new String[]{
"FirstOfferAccept", "SecondOfferAccept", "ThirdOfferAccept",
"FirstOfferRejected", "SecondOfferRejected", "ThirdOfferRejected"});
}
@Test
public void testBarterWithReject() {
testAggregateGlobalModel("BarterWithReject", new String[] {
"Buyer", "Seller"});
}
protected void testAggregateLocalModel(String localName, String role,
String[] scenarioLocalModels) {
java.util.List<ProtocolModel> locals=new java.util.Vector<ProtocolModel>();
for (String localModel : scenarioLocalModels) {
String filename="testmodels/protocol/aggregator/scenario/"+localModel+"@"+role+".spr";
ProtocolModel model=getModel(filename);
if (model != null) {
locals.add(model);
}
}
ProtocolAggregator aggregator=new ProtocolAggregatorImpl();
DefaultFeedbackHandler feedback=new DefaultFeedbackHandler();
ProtocolModel aggregated=aggregator.aggregateLocalModel(localName, locals, feedback);
if (feedback.getIssues().size() > 0) {
fail("Issues detected");
}
if (aggregated == null) {
fail("Aggregated model is null");
}
org.scribble.protocol.export.text.TextProtocolExporter exporter=
new org.scribble.protocol.export.text.TextProtocolExporter();
java.io.ByteArrayOutputStream os=new java.io.ByteArrayOutputStream();
CachedJournal journal=new CachedJournal();
exporter.export(aggregated, journal, os);
try {
os.close();
} catch(Exception e) {
fail("Failed to close stream");
}
String str=os.toString();
checkResults(localName+"@"+role, "local", str);
}
protected void testAggregateGlobalModel(String globalName, String[] roles) {
java.util.List<ProtocolModel> locals=new java.util.Vector<ProtocolModel>();
for (String role : roles) {
String filename="testmodels/protocol/aggregator/local/"+globalName+"@"+role+".spr";
ProtocolModel model=getModel(filename);
if (model != null) {
locals.add(model);
}
}
ProtocolAggregator aggregator=new ProtocolAggregatorImpl();
DefaultFeedbackHandler feedback=new DefaultFeedbackHandler();
ProtocolModel aggregated=aggregator.aggregateGlobalModel(globalName, null,
locals, feedback);
if (feedback.getIssues().size() > 0) {
fail("Issues detected");
}
if (aggregated == null) {
fail("Aggregated model is null");
}
org.scribble.protocol.export.text.TextProtocolExporter exporter=
new org.scribble.protocol.export.text.TextProtocolExporter();
java.io.ByteArrayOutputStream os=new java.io.ByteArrayOutputStream();
CachedJournal journal=new CachedJournal();
exporter.export(aggregated, journal, os);
try {
os.close();
} catch(Exception e) {
fail("Failed to close stream");
}
String str=os.toString();
checkResults(globalName, "global", str);
}
protected void checkResults(String aggregatedProtocolName, String subfolder, String protocol) {
boolean f_valid=false;
// Load aggregated model
String filename="testmodels/protocol/aggregator/"+subfolder+"/"+aggregatedProtocolName+".spr";
java.io.InputStream is=
ClassLoader.getSystemResourceAsStream(filename);
if (is != null) {
try {
byte[] b=new byte[is.available()];
is.read(b);
is.close();
String orig=new String(b);
f_valid = orig.equals(protocol);
} catch(Exception e) {
fail("Failed to load protocol model: "+e);
}
} else {
fail("Protocol '"+filename+
"' not found for comparison");
}
if (f_valid == false) {
java.net.URL url=ClassLoader.getSystemResource(filename);
if (url != null) {
// URL will point to copy of test models in the classes folder, so need
// to obtain reference back to source version
java.io.File f=null;
if (url.getFile().indexOf("target/test-classes") != -1) {
f = new java.io.File(url.getFile().replaceFirst("target/test-classes","src/test/resources"));
} else if (url.getFile().indexOf("classes") != -1) {
f = new java.io.File(url.getFile().replaceFirst("classes","src/test/resources"));
} else if (url.getFile().indexOf("bin") != -1) {
f = new java.io.File(url.getFile().replaceFirst("bin","src/test/resources"));
} else {
fail("Could not locate results folder to record expected result");
}
if (f != null && f.exists()) {
f = f.getParentFile();
java.io.File resultFile=new java.io.File(f,
aggregatedProtocolName+".generated");
if (resultFile.exists() == false) {
try {
java.io.FileOutputStream fos=new java.io.FileOutputStream(resultFile);
fos.write(protocol.getBytes());
fos.flush();
fos.close();
} catch(Exception e){
fail("Failed to write generated protocol: "+e);
}
} else {
System.err.println("NOTE: Generated output '"+resultFile+
"' already exists - not being overwritten");
}
} else {
fail("Unable to obtain URL for protocol model '"+
filename+"': "+url);
}
}
fail("Aggregated protocol '"+aggregatedProtocolName+"' did not match expected description");
}
}
protected ProtocolModel getModel(String filename) {
java.net.URL url=
ClassLoader.getSystemResource(filename);
if (url == null) {
fail("Unable to locate resource: "+filename);
}
FeedbackHandler feedback=new DefaultFeedbackHandler();
org.scribble.protocol.model.ProtocolModel model=null;
try {
Content content=new ResourceContent(url.toURI());
model = ProtocolServices.getParserManager().parse(null, content,
new JournalProxy(feedback));
} catch(Exception e) {
fail("Parsing choreography failed");
}
return(model);
}
}