Commit e599ee97 authored by Rem Collier's avatar Rem Collier

moved astra-unittest and astra-protocols into support package

parent 66e2ab04
.classpath
.project
.settings/
target/
{
"java.configuration.updateBuildConfiguration": "automatic"
}
\ No newline at end of file
{
"java.configuration.updateBuildConfiguration": "automatic",
"files.exclude": {
"**/.classpath": true,
"**/.project": true,
"**/.settings": true,
"**/.factorypath": true
}
}
\ No newline at end of file
# astra-protocols
This project implements some common protocols that can be used in ASTRA projects
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>astra</groupId>
<artifactId>astra-protocols</artifactId>
<version>0.2.0</version>
<parent>
<groupId>astra</groupId>
<artifactId>astra-base</artifactId>
<version>0.2.0</version>
</parent>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>astra-repo</id>
<url>https://gitlab.com/astra-language/astra-mvn-repo/raw/master</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>astra</groupId>
<artifactId>astra-unittest</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/astra</directory>
<includes>
<include>**/*.astra</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>astra</groupId>
<artifactId>astra-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<altDeploymentRepository>internal.repo::default::file://${project.basedir}/../../astra-mvn-repo</altDeploymentRepository>
</configuration>
</plugin>
</plugins>
</build>
</project>
package astra.protocol;
agent FipaRequest {
module System system;
module Console console;
types fr {
formula action(funct);
formula success(funct, funct);
}
//***********************************************************************************
// Participant Rules
//***********************************************************************************
goal +!monitor_action_requests() <: false {
rule @message(request, string sender, action(funct act)) {
console.println("received request: " + act);
!evaluate_request(sender, act, boolean result);
if (result == true) {
send(agree, sender, action(act));
try {
!execute_request(sender, act, funct outcome, boolean result2);
if (result2 == true) {
send(inform, sender, success(act, outcome));
} else {
send(failure, sender, action(act));
}
} recover {
send(failure, sender, action(act));
}
} else {
send(refuse, sender, action(act));
}
}
}
rule +!evaluate_request(string name, funct act, boolean result) {
result = false;
}
rule +!execute_request(string name, funct act, funct outcome, boolean result) {
outcome = null_outcome();
result = false;
}
//***********************************************************************************
// Initiator Rules
//***********************************************************************************
goal +!request_action(string target, funct act) <: false {
body {
console.println("sending request: " + act);
send(request, target, action(act));
}
rule @message(agree, target, action(act)) {
!agreed_request(act);
}
rule @message(refuse, target, action(act)) {
!failed_request(act);
done;
}
rule @message(failure, target, action(act)) {
system.fail();
}
rule @message(inform, target, success(act, funct outcome)) {
!succeeded_request(act, outcome);
done;
}
}
rule +!agreed_request(funct act) {}
rule +!failed_request(funct act) {}
rule +!succeeded_request(funct act, funct outcome) {}
}
package astra.protocol;
agent FipaSubscribe {
module System system;
module Console console;
types fs {
formula topic(string);
formula channel(string);
formula subscribed(string, string);
formula cancelled_topic(string);
formula content(string, funct);
}
//***********************************************************************************
// Participant Rules
//***********************************************************************************
goal +!monitor_subscriptions() <: false {
rule @message(subscribe, string sender, topic(string channel)) : channel(channel) {
!evaluate_subscription(channel, boolean result);
if (result == true) {
send(agree, sender, topic(channel));
+subscribed(sender, channel);
} else {
send(refuse, sender, topic(channel));
}
}
rule @message(subscribe, string sender, topic(string channel)) {
send(refuse, sender, topic(channel));
}
rule @message(cancel, string sender, topic(string channel)) : subscribed(sender, channel) {
-subscribed(sender, channel);
send(inform, sender, cancelled_topic(channel));
}
rule @message(cancel, string sender, topic(string channel)) {
send(failure, sender, cancelled_topic(channel));
}
}
rule +!evaluate_subscription(string channel, boolean result) {
result = true;
}
rule +!publish(string channel, funct message) : channel(channel) {
foreach(subscribed(string agtId, channel)) {
send(inform, agtId, content(channel, message));
}
}
//***********************************************************************************
// Initiator Rules
//***********************************************************************************
goal +!subscribe(string target, string channel) <: false {
body {
send(subscribe, target, topic(channel));
}
rule @message(agree, target, topic(channel)) {
+subscribed(target, channel);
!subscription_accepted(channel);
}
rule @message(refuse, target, topic(channel)) {
!subscription_refused(channel);
done;
}
rule @message(failure, target, topic(channel)) {
system.fail();
}
rule @message(inform, target, content(channel, funct message)) {
!handle_content(channel,message);
}
rule @message(inform, target, cancelled_topic(channel)) {
!subscription_cancelled(channel);
done;
}
}
rule +!subscription_accepted(string channel) {}
rule +!subscription_refused(string channel) {}
rule +!subscription_cancelled(string channel) {}
rule +!handle_content(string channel, funct message) {console.println("unhandled content from '" + channel + "': " + message);}
rule +!cancel_subscription(string target, string channel) : subscribed(target, channel) {
send(cancel, target, topic(channel));
}
}
package astra.protocol;
agent VickreyAuction {
module System system;
module Console console;
types auction {
formula created(string, string);
formula available(string, string);
formula attend(string);
formula auction(string);
formula auction(string, funct);
formula auction(string,funct,int);
formula bid(string, int);
}
types auctioneer {
formula participant(string);
formula bid(string, string, int);
formula winner(string, string, int);
}
//***********************************************************************************
// Participant Rules
//***********************************************************************************
goal +!auction(string id, funct description, config(int timeout)) <: false {
body {
console.println("Starting Auction of: " + id);
foreach(participant(string name)) {
send(cfp, name, auction(id, description, timeout));
}
console.println("Waiting for bids");
system.sleep(timeout);
console.println("Evaluating bids");
int best_bid = -1;
string winner = "";
foreach (bid(id, string name, int bid)) {
!compare_bids(id, current(name, bid), winner(winner, best_bid), boolean better);
if (better == true) {
best_bid = bid;
winner = name;
}
}
if (winner == "") {
console.println("no winner: " + id);
} else {
+winner(id, winner, best_bid);
}
done;
}
rule @message(propose, string sender, bid(id, int price)) {
console.println("received bid: " + price +" from: "+sender);
+bid(id, sender, price);
}
rule +winner(id, string winner, int best_bid) {
foreach(bid(id, string name, int bid) & (name ~= winner)) {
send(reject-proposal, name, bid(id, bid));
-bid(id, name, bid);
}
send(accept-proposal, winner, bid(id, best_bid));
console.println("Winner: " + winner + " with bid: " + best_bid);
-bid(id, winner, best_bid);
}
}
rule +!compare_bids(string id, current(string name, int bid), winner(string winner, int best_bid), boolean better) {
if (bid > best_bid) {
better = true;
} else {
better = false;
}
}
//***********************************************************************************
// Initiator Rules
//***********************************************************************************
goal +!monitor_for_auctions() <: false {
rule @message(cfp, string sender, auction(string id, funct description, int deadline)) {
+auction(id, description);
!generate_bid(id, description, int bid);
send(propose, sender, bid(id, bid));
}
rule @message(reject-proposal, string sender, bid(string id, int bid)) : auction(id, funct description) {
!failed_bid(id, bid);
-auction(id, description);
}
rule @message(accept-proposal, string sender, bid(string id, int bid)) : auction(id, funct description) {
!successful_bid(id, bid);
-auction(id, description);
}
}
rule +!generate_bid(string id, funct description, int bid) {
bid = 2;
}
rule +!failed_bid(string id, int bid) : auction(id, funct description) {}
rule +!successful_bid(string id, int bid) : auction(id, funct description) {
console.println("I AM WINNER of: " + id + " with bid: " + bid);
}
}
import astra.unit.*;
agent FIPARequestTests extends astra.unit.ASTRAUnitTest, astra.protocol.FipaRequest {
rule +!test_request(TestSuite suite) {
system.createAgent("opp", "HelloResponder");
!request_action("opp", hello());
system.terminateAgent("opp");
UT.success(suite);
}
}
\ No newline at end of file
agent HelloResponder extends astra.protocol.FipaRequest {
initial !monitor_action_requests();
rule +!evaluate_request(string name, hello(), boolean result) {
result = true;
}
rule +!execute_request(string name, hello(), funct outcome, boolean result) {
console.println("Hello, " + name);
outcome = null_outcome();
result = true;
}
}
\ No newline at end of file
{
"java.configuration.updateBuildConfiguration": "automatic"
}
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>astra</groupId>
<artifactId>astra-unittest</artifactId>
<version>0.2.0</version>
<parent>
<groupId>astra</groupId>
<artifactId>astra-base</artifactId>
<version>0.2.0</version>
</parent>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>astra-repo</id>
<url>https://gitlab.com/astra-language/astra-mvn-repo/raw/master</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.12</version>
</dependency>
</dependencies>
<build>
<defaultGoal>clean compile astra:deploy</defaultGoal>
<plugins>
<plugin>
<groupId>astra</groupId>
<artifactId>astra-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>astra.unit.TestRunner</mainClass>
</configuration>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<altDeploymentRepository>internal.repo::default::file://${project.basedir}/../../astra-mvn-repo</altDeploymentRepository>
</configuration>
</plugin>
</plugins>
</build>
</project>
package astra.unit;
agent ASTRAUnitTest {
module UnitTest UT;
}
\ No newline at end of file
package astra.unit;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.reflections.Reflections;
import astra.core.ASTRAClass;
public class TestRunner {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
List<String> tests = new LinkedList<String>();
Reflections reflections = new Reflections("");
Set<Class<? extends ASTRAClass>> javaClasses = reflections.getSubTypesOf(ASTRAClass.class);
for (Class<? extends ASTRAClass> javaClass : javaClasses) {
ASTRAClass astraClass = javaClass.newInstance();
for (Class<ASTRAClass> parent : astraClass.getParents()) {
if (parent.getCanonicalName().equals("astra.unit.ASTRAUnitTest")) {
tests.add(javaClass.getCanonicalName());
}
}
}
TestSuite suite = new TestSuite(tests.toArray(new String[tests.size()]));
suite.execute();
TestSuite.displayResults(suite);
}
}
\ No newline at end of file
package astra.unit;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import astra.core.ASTRAClass;
import astra.core.ASTRAClassNotFoundException;
import astra.core.Agent;
import astra.core.Intention;
import astra.core.Rule;
import astra.core.Scheduler;
import astra.event.GoalEvent;
import astra.execution.AdaptiveSchedulerStrategy;
import astra.formula.Goal;
import astra.formula.Predicate;
import astra.messaging.LocalMQService;
import astra.messaging.MessageService;
import astra.term.Primitive;
import astra.term.Term;
public class TestSuite {
/**
* Class to represent a test record
*
* @author Rem
*/
private static class Test {
public Test(String agent, Goal goal) {
this.agent = agent;
this.goal = goal;
}
String agent;
Goal goal;
String message;
int steps;
boolean result;
public String toString() {
return "["+(result ? "PASSED":"FAILED") + "] " + agent+"."+goal.formula().predicate()+" (steps: " + steps + ") -> " + message;
}
}
/**
* The test classes
*/
protected List<String> testClasses = new LinkedList<String>();
/**
* The test records
*/
protected List<Test> records = new LinkedList<Test>();
/**
* The test record currently being evaluated.
*/
private Test current;
public TestSuite(String[] tests) {
for(String test : tests) {
testClasses.add(test);
}
}
/**
* Execution of the test suite:
* - for each test class specified in the test set, an agent is created
* - the test records for that test class are identified
* - the !setup(TestSuite) goal is executed
* - each test record is executed
* - the !teardown(TestSuite) goal is executed.
* - the agent is terminated
*/
public void execute() {
// Scheduler.setStrategy(new DummySchedulerStrategy());
Scheduler.setStrategy(new AdaptiveSchedulerStrategy());
MessageService.installService("local", new LocalMQService());
MessageService.getService("local").configure("logging", "on");
MessageService.getService("local").start();
try {
for (String clazz : testClasses) {
// The next line of code create an agent whose name is the key part of the entry and
// whose type (class) is the value part of the entry.
ASTRAClass cls = (ASTRAClass) Class.forName(clazz).newInstance();
buildTestList(cls);
// Create the test agent
Agent agent = cls.newInstance(clazz);
// Now execute the three goals that correspond to a test:
executeIntention(agent, new Goal(new Predicate("setup", new Term[] {Primitive.newPrimitive(this)})));
for (int i=0; i<records.size(); i++) {
current = records.get(i);
executeTestIntention(agent, current.goal);
}
executeIntention(agent, new Goal(new Predicate("teardown", new Term[] {Primitive.newPrimitive(this)})));
agent.terminate();
}
} catch (Exception e) {
e.printStackTrace();
}
Scheduler.shutdown();
}
/**
* Contructs the test list by identifying all goals with prefix "test_". A test record is
* created for each such goal.
*
* @param cls
* @return
* @throws ASTRAClassNotFoundException
*/
private List<Goal> buildTestList(ASTRAClass cls) throws ASTRAClassNotFoundException {
for (ASTRAClass clazz : cls.getLinearization()) {
for(Entry<String, List<Rule>> entry : clazz.rules().entrySet()) {
for(Rule rule : entry.getValue()) {
if (rule.event instanceof GoalEvent) {
GoalEvent event = (GoalEvent) rule.event;
if (event.goal.formula().predicate().startsWith("test_") && (event.goal.formula().size() == 1)){
records.add(new Test(cls.getCanonicalName(), new Goal(new Predicate(event.goal.formula().predicate(), new Term[] {Primitive.newPrimitive(this)}))));
}
}
}
}
}
return null;
}
/**
* Executes an intention to completion (identified by the agent
* having no more intentions).
*
* @param agent
* @param goal
*/
private void executeIntention(Agent agent, Goal goal) {
agent.initialize(goal);