diff --git a/acceptance-tests/build.gradle b/acceptance-tests/build.gradle index 73ae1a4144..375731c560 100644 --- a/acceptance-tests/build.gradle +++ b/acceptance-tests/build.gradle @@ -27,9 +27,11 @@ dependencies { testImplementation project(':ethereum:eth') testImplementation project(':ethereum:graphql') testImplementation project(':ethereum:jsonrpc') + testImplementation project(':ethereum:p2p') testImplementation project(':ethereum:permissioning') testImplementation project(':ethereum:rlp') testImplementation project(':metrics:core') + testImplementation project(':plugins') testImplementation project(path: ':plugins', configuration: 'testArtifacts') testImplementation project(':pantheon') testImplementation project(':services:kvstore') @@ -38,6 +40,7 @@ dependencies { testImplementation 'com.google.guava:guava' testImplementation 'com.squareup.okhttp3:okhttp' + testImplementation 'info.picocli:picocli' testImplementation 'io.reactivex.rxjava2:rxjava' testImplementation 'io.vertx:vertx-core' testImplementation 'junit:junit' diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java index 591dd6baf3..4560fcad61 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java @@ -26,9 +26,15 @@ import tech.pegasys.pantheon.ethereum.eth.transactions.PendingTransactions; import tech.pegasys.pantheon.ethereum.graphql.GraphQLConfiguration; import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; +import tech.pegasys.pantheon.plugins.internal.PantheonPluginContextImpl; +import tech.pegasys.pantheon.plugins.services.PantheonEvents; +import tech.pegasys.pantheon.plugins.services.PicoCLIOptions; +import tech.pegasys.pantheon.services.PantheonEventsImpl; +import tech.pegasys.pantheon.services.PicoCLIOptionsImpl; import tech.pegasys.pantheon.services.kvstore.RocksDbConfiguration; import tech.pegasys.pantheon.util.enode.EnodeURL; +import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.time.Clock; @@ -45,6 +51,8 @@ import com.google.common.io.Files; import io.vertx.core.Vertx; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import picocli.CommandLine; +import picocli.CommandLine.Model.CommandSpec; public class ThreadPantheonNodeRunner implements PantheonNodeRunner { @@ -52,12 +60,28 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { private final Map pantheonRunners = new HashMap<>(); private ExecutorService nodeExecutor = Executors.newCachedThreadPool(); + private final Map pantheonPluginContextMap = new HashMap<>(); + @Override public void startNode(final PantheonNode node) { if (nodeExecutor == null || nodeExecutor.isShutdown()) { nodeExecutor = Executors.newCachedThreadPool(); } + final CommandLine commandLine = new CommandLine(CommandSpec.create()); + final PantheonPluginContextImpl pantheonPluginContext = + pantheonPluginContextMap.computeIfAbsent(node, n -> new PantheonPluginContextImpl()); + pantheonPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine)); + final Path pluginsPath = node.homeDirectory().resolve("plugins"); + final File pluginsDirFile = pluginsPath.toFile(); + if (!pluginsDirFile.isDirectory()) { + pluginsDirFile.mkdirs(); + pluginsDirFile.deleteOnExit(); + } + System.setProperty("pantheon.plugins.dir", pluginsPath.toString()); + pantheonPluginContext.registerPlugins(pluginsPath); + commandLine.parseArgs(node.getConfiguration().getExtraCLIOptions().toArray(new String[0])); + final MetricsSystem noOpMetricsSystem = new NoOpMetricsSystem(); final List bootnodes = node.getConfiguration().getBootnodes().stream() @@ -95,6 +119,11 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { final RunnerBuilder runnerBuilder = new RunnerBuilder(); node.getPermissioningConfiguration().ifPresent(runnerBuilder::permissioningConfiguration); + pantheonPluginContext.addService( + PantheonEvents.class, + new PantheonEventsImpl(pantheonController.getProtocolManager().getBlockBroadcaster())); + pantheonPluginContext.startPlugins(); + final Runner runner = runnerBuilder .vertx(Vertx.vertx()) @@ -120,6 +149,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner { @Override public void stopNode(final PantheonNode node) { + pantheonPluginContextMap.get(node).stopPlugins(); node.stop(); killRunner(node.getName()); } diff --git a/plugins/src/test/java/tech/pegasys/pantheon/plugins/TestPantheonEventsPlugin.java b/plugins/src/test/java/tech/pegasys/pantheon/plugins/TestPantheonEventsPlugin.java index eda550ffce..b6468913ca 100644 --- a/plugins/src/test/java/tech/pegasys/pantheon/plugins/TestPantheonEventsPlugin.java +++ b/plugins/src/test/java/tech/pegasys/pantheon/plugins/TestPantheonEventsPlugin.java @@ -28,15 +28,18 @@ import org.apache.logging.log4j.Logger; @AutoService(PantheonPlugin.class) public class TestPantheonEventsPlugin implements PantheonPlugin { private static final Logger LOG = LogManager.getLogger(); - private Optional subscriptionId; private PantheonContext context; + + private Optional subscriptionId; private final AtomicInteger blockCounter = new AtomicInteger(); + private File callbackDir; @Override public void register(final PantheonContext context) { this.context = context; LOG.info("Registered"); + callbackDir = new File(System.getProperty("pantheon.plugins.dir", "plugins")); } @Override @@ -62,8 +65,7 @@ public class TestPantheonEventsPlugin implements PantheonPlugin { final int blockCount = blockCounter.incrementAndGet(); LOG.info("I got a new block! (I've seen {}) - {}", blockCount, json); try { - final File callbackFile = - new File(System.getProperty("pantheon.plugins.dir", "plugins"), "newBlock." + blockCount); + final File callbackFile = new File(callbackDir, "newBlock." + blockCount); if (!callbackFile.getParentFile().exists()) { callbackFile.getParentFile().mkdirs(); callbackFile.getParentFile().deleteOnExit(); diff --git a/plugins/src/test/java/tech/pegasys/pantheon/plugins/TestPicoCLIPlugin.java b/plugins/src/test/java/tech/pegasys/pantheon/plugins/TestPicoCLIPlugin.java index 1597c5085a..7cea3ad100 100644 --- a/plugins/src/test/java/tech/pegasys/pantheon/plugins/TestPicoCLIPlugin.java +++ b/plugins/src/test/java/tech/pegasys/pantheon/plugins/TestPicoCLIPlugin.java @@ -32,6 +32,7 @@ public class TestPicoCLIPlugin implements PantheonPlugin { String testOption = System.getProperty("testPicoCLIPlugin.testOption"); private String state = "uninited"; + private File callbackDir; @Override public void register(final PantheonContext context) { @@ -49,6 +50,7 @@ public class TestPicoCLIPlugin implements PantheonPlugin { picoCLIOptions -> picoCLIOptions.addPicoCLIOptions("Test PicoCLI Plugin", TestPicoCLIPlugin.this)); + callbackDir = new File(System.getProperty("pantheon.plugins.dir", "plugins")); writeSignal("registered"); state = "registered"; } @@ -89,8 +91,7 @@ public class TestPicoCLIPlugin implements PantheonPlugin { /** This is used to signal to the acceptance test that certain tasks were completed. */ private void writeSignal(final String signal) { try { - final File callbackFile = - new File(System.getProperty("pantheon.plugins.dir", "plugins"), "testPlugin." + signal); + final File callbackFile = new File(callbackDir, "testPlugin." + signal); if (!callbackFile.getParentFile().exists()) { callbackFile.getParentFile().mkdirs(); callbackFile.getParentFile().deleteOnExit();