Giter VIP home page Giter VIP logo

oracle-bedrock's Introduction

Oracle Bedrock

Oracle Bedrock provides a general purpose Java framework for the development, orchestration and testing of highly concurrent distributed applications.

It's often used for orchestrating and testing multi-server, multi-process distributed applications, meaning it's especially useful for working with Coherence-based applications. However it can be used for any type of application or server, Java or not.

Oracle Bedrock provides extremely uniform mechanisms to start/stop and manage applications and processes on a variety of platforms, including;

  • Local Platforms
  • Remote Platforms (via ssh, powershell et al)
  • Virtualized Platforms (via Vagrant), including machine / platform orchestration (VirtualBox, VMWare etc)
  • Containerized Platforms (via Docker), including image management
  • Java Virtual Machines (aka: in-process applications)

Which means it can orchestrate launching applications/servers in any environment, locally, on-premise, across data-centers or in one or more clouds.

For example: To Launch a "HelloWorld" Java Application on the current classpath on the LocalPlatform, use the following:

    LocalPlatform platform = LocalPlatform.get();

    try (JavaApplication application = platform.launch(JavaApplication.class,
                                                       ClassName.of(HelloWorld.class))) {

        // potentially do something with the application ...

        // wait until it finishes execution
        application.waitFor();
    }

To launch this application on another platform, simply change the platform. The rest of the code remains the same.

    // launch using a RemotePlatform
    RemotePlatform platform = new RemotePlatform(address, username, authentication);

    // ... or launch inside the running JavaVirtualMachine Platform (ie: in-process)
    JavaVirtualMachine platform = JavaVirtualMachine.get();

For Java-based applications, Oracle Bedrock uniquely provides support for:

  • Packaging and automatically deploying applications (based on a ClassPath or Maven Dependency POM)
  • Dynamically interacting with applications at runtime, without requiring technologies like RMI, including the ability to dynamically execute lambdas / remote callables / runnables through an ExecutorService like interface.
    // execute the lambda in the java application, where ever it is running!
    application.submit(() -> { System.out.println("Hello World");});

    // request a lambda to execute (in the java application) and return a result (as a CompleteableFuture)
    CompletableFuture<String> property = application.submit(() -> System.getProperty("os.name"));

Lastly, Oracle Bedrock provides a powerful extension to testing tools, allow developers to Eventually assert that conditions in concurrent data-structures and distributed applications are reached.

   // ensure that the application internal state reaches some condition
   Eventually.assertThat(application, () -> { someFunction() }, is(someValue));

Contributing

Oracle Bedrock is an open source project. Pull Requests are accepted. See CONTRIBUTING for details.

License

Copyright (c) 2010, 2019 Oracle and/or its affiliates. Licensed under the Common Development and Distribution License v1.0 ("CDDL")

Building

Bedrock is a Maven project and can be built with standard Maven commands.

Prerequisites

  1. The Coherence modules have a dependency on four versions of Coherence. The exact versions can be found in the coherence.version property in pom.xml files

    bedrock-coherence/3.7.1/pom.xml
    bedrock-coherence/12.1.2/pom.xml
    bedrock-coherence/12.1.3/pom.xml
    bedrock-coherence/12.2.1/pom.xml

    As Coherence is not available in public Maven repos the coherence.jar files for each of those versions needs to be loaded to your own local or remote Maven repository under the groupId com.oracle.coherence and artifactId coherence.

  2. There are a number of tests in the bedrock-runtime-remote-tests module that will attempt to SSH into your local machine using private/public key pair. For this to work you need a key pair configured.

    1. By default the private key file is called 127.0.0.1_dsa and corresponding public key 127.0.0.1_dsa.pub. You can run the build with a system property to change this to any valid key that you already have configured for ssh'ing into your machine: For example to use id_rsa then add -Dbedrock.remote.privatekey.file=~/.ssh/id_rsa to the Maven command line.

    2. Alternatively you may need to generate a new key pair using ssh-keygen. NOTE ensure that they type of key-pair generated is a valid type to SSH into your machine. For example on MacOS an RSA key pair will be fine, a DSA key pair may not, so even though the default file name used in tests has the suffix _dsa it can contain any type of key.

      ssh-keygen -t rsa -f 127.0.0.1_dsa
      

      Do not set a passphrase for the keys.

    3. Add the public key to your ~/.ssh/authorized_keys file:

      cat ~/.ssh/127.0.0.1_dsa.pub >> ~/.ssh/authorized_keys
      
    4. Restart your SSH daemon to pick up the change to the ~/.ssh/authorized_keys file. On MacOS run

      sudo launchctl stop com.openssh.sshd
      sudo launchctl start com.openssh.sshd
      
    5. Test that you can ssh into your own machine with the new key

      ssh -i ~/.ssh/foo_rsa <your-user-name>@127.0.0.1
      

โš ๏ธ WARNING Any keys used for testing and building should be used with care. If the private key is disclosed, any observer will be able to log into the user's machine. Users should delete the key from authorized_keys as soon as the tests are complete.

Run the build

To run a full build:

mvn clean install

To run a full build without tests:

mvn clean install -DskipTests

oracle-bedrock's People

Contributors

aseovic avatar brianoliver avatar dependabot[bot] avatar dunkin6 avatar jfialli avatar lsho avatar manfredriem avatar mgamanho avatar narliss avatar rlubke avatar thegridman avatar tmiddlet2666 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oracle-bedrock's Issues

Remove Notified Deferred implementation

The Notified implementation can never be guaranteed to operate correctly when we consider the possibility of Operating System "notification". Furthermore the behavior and timing of notification can differ significantly across platforms, especially between Windows and Linux, worse when these platforms are virtualized.

Consequently the safest thing to do is remove this support - it's not used anywhere in the Coherence Incubator.

Add automatic support for Coherence-based Schemas on JDK8

When running Oracle Tools on JDK8 (b91), Coherence (any version using XSD) won't start due to improved/tightened JDK8 XSD loading permissions.

To work around this we should add the following default system property to the Coherence-based Schemas, at least until this is either fixed in JDK8 or Coherence (with a change of XSD loading security).

schema.setSystemProperty("javax.xml.accessExternalSchema", "file");

Create a LocalJavaApplicationBuilder to support using ApplicationSchema to set local JVM properties

Consider a test that wants to set numerous System properties, and/or establish local JMX instrumentation for a test.

Instead of having @before test methods do this via calls to System.setProperty(...) etc, it would be nice if we could simply leverage an Application Schema.

eg: In the case of a Coherence-based test we could do this.

@Before
public void setup()
{
ClusterMemberSchema schema = new ClusterMemberSchema().setClusterPort(...);

LocalApplicationBuilder builder = new LocalApplicationBuilder();
LocalApplication application = builder.build(schema);   //<-- will set the local application properties etc, from the schema. }

Introduce the concept of an AbstractCoherenceTest

For platforms that don't correctly isolate Coherence applications, and/or those that don't respect standard network settings, we should provide a top-level Abstract class that we can base all our tests (especially for the Coherence Incubator).

This will ensure we always have the correct isolation.

Introduce a Container-based Runner for the Testing

By introducing a specialized Junit Test Runner for Containers, we can do a lot more isolation and dramatically simplify test setup/cleanup.

eg: we can support annotations like
@SystemIsolation(NONE)
@SystemIsolation(FOR_EACH_TEST_METHOD)
@SystemIsolation(FOR_TEST_CLASS)

This could then be extended for Coherence as well.

NOTE: When we do this we can remove the requirement to inherit from the AbstractTest class (we could theoretically deprecate it)

VirtualizationClassLoaderTest method execution order is significant (it should not be)

When running the VirtualizationClassLoaderTests on Windows with Java 7 and 8, the order of the test method execution becomes significant. This is because some methods cause side-effects which then later methods either implicitly depend upon or don't expect. As the order of method execution for Junit (based on Java 7 and 8 method reflection) is somewhat random on Windows, this can cause tests to fail some what randomly.

We need to ensure that there's no implicit ordering or dependencies or side-effects in our test methods, particularly those testing ClassLoaders.

Application Group produced Application names should start at 1 not 0

Currently the application names produced by an application group builder start at 0. This is confusing, especially when being used with Coherence (and other cluster-based systems), where member names start at 1.

Fixing this will be a BREAKING CHANGE for anyone that assumes the name of an application starts at 0.

Introduce Coherence Test Runner

Once we have a custom Container runner we could introduce a specific Coherence-based runner that can setup/establish clusters using annotations.

This will make testing way simpler and more isolated through declarative configuration.

eg:

@cluster(name=RANDOM, port=RANDOM, ttl=0)

We can also extend this to pre-load cache data, record cache data after runs/exceptions and compare cluster state to that which is desired. ie: assert that the state of a cluster after running a test is as expected.

NOTE: When we do this we can remove the requirement to inherit from the AbstractCoherenceTest class (we could theoretically deprecate it)

Refactor PropertiesBuilder.fromCurrentSystemProperties to return only custom properties

When running on some platforms (like Windows) copying all of the System Properties, including those defined at runtime by the Java Platform, from one process and passing them to another can be problematic. In some instances attempting to re-define the Java Platform defined system properties can cause applications (ie: Java) not to start. Hence we need to avoid providing this facility!

To solve this issue we're going to refactor the PropertiesBuilder.fromCurrentSystemProperties method to instead become PropertiesBuilder.fromCurrentNonStandardSystemProperties so that the PropertyBuilder that is created only contains those defined by the end-user.

It turns out we don't actually use this method anywhere anyway - apart from in tests. Anyone using this method outside of the tests are essentially in trouble anyway - as their applications won't be cross platform.

Introduce the concept of ApplicationGroupControllers

An ApplicationGroupController allows programmatic control of ApplicationGroups at runtime. Specific examples include;

a). the ability to perform automatic "Rolling Restarts" of (specific) Applications in an ApplicationGroup.

b). the ability to introduce Chaos Monkeys (see: http://www.codinghorror.com/blog/2011/04/working-with-the-chaos-monkey.html) into an Application Group.

c). systematically perform custom actions against Applications in an ApplicationGroup (eg: running a report).

Refactor Deferreds to support returning null

Currently the Deferred#get() method does not permit returning null object references as null has the implied meaning "object not yet available". This is unfortunately as it doesn't let null be returned - when it is a valid object.

To resolve this we need to refactor the semantics so that:

  1. We throw an UnresolvableInstanceException - when the Object can never be resolved (thus replacing ObjectNotAvailableException which is misleading)

  2. We throw an InstanceUnavailableException - when the Object resolution failed, but may be retried in the future (thus replacing the return value of "null").

Oracle Tools virtualization will fail to run when classpaths contain whitespace

I noticed when running test on Windows, specifically using a Jenkins installation that was in "C:\Program Files\jenkins" that the application builders may not work as expected and in some circumstances, actually fail.

The proposed solution is to introduce the concept of a ClassPath class that can be used to represent and manipulate ClassPaths in a platform independent manner, instead of having class path parsing code all over the place.

Rename "Virtualization" to "Container" to improve understanding

Currently we use the term "virtualization" to represent the concept of running a Java application "virtually" with in another application. Though correct in that we actually "virtualize" System properties, I/O, MBean servers etc, this however can be confusing when running such applications in a virtual appliance.

We should rename the internal classes to be a "Container" instead of "Virtualized". While this may cause confusion when discussing using applications in a container, it is closer to what is happening in a traditional sense (with the additional characteristic of isolating I/O streams and MBean servers which containers dont' traditionally do).

Add the ability to set the "tangosol.coherence.localport" property

When attempting to run Coherence in WKA mode (using system properties), both the WKA port ("tangosol.coherence.wka.port") and the Local Address Port ("tangosol.coherence.localport") need to be set to the same value.

Unfortunately the ClusterMemberSchema doesn't provide an out-of-the-box method to set the LocalPort which is somewhat annoying (as you have to use setSystemProperty).

We should hence;
i). add a "setLocalHostPort" method, and
ii). when a call to "setWellKnownAddressPort" is made, it should also call this method (to make it easy for the developer).

Provide the ability to protect launched (Java) processes from becoming orphaned

Currently the processes built by the NativeApplicationBuilder(s) will create (child) processes that are independent of the creating (parent) process. Should the parent process terminate (for what ever reason), the child processes will be let running (ie: orphaned). Often this is undesirable (and not the expected default behavior).

Leveraging the work in #51, it should be possible to introduce the concept of orphan-protection for native application builders.

Add the ability to enable remote Java debugging

When creating external/native Java processes, it would be nice if we could control/debug them.

To enable this we should add the ability to specify debug properties when using External/Native Java Application builders (they don't apply to Virtual/Container-based builders).

Refactor ApplicationConsole to allow separate control of stdout, stderr and stdin

Currently we only allow capturing stdout for an ApplicationConsole. This is problematic when we need to test with applications specifically use other streams, like stderr. Furthermore we currently provide no facility to control or provide stdin for an application, thus again limiting the ability to write fully interactive tests.

To resolve this I propose we redesign/refactor how we use ApplicationConsoles. In particular I suggest the following interface:

interface ApplicationConsole
{
/**
* Obtains the BufferedReader that can be used to read content an Application sent to stdout.
*/
public BufferedReader getStdOutReader();

/**
* Obtains the BufferedReader that can be used to read content an Application sent to stderr.
*/
public BufferedReader getStdErrReader();

/**
* Obtains the PrintWriter that can be used to send input to the stdin of an Application.
*/
public PrintWriter getStdInWriter();

/**
* Closes the ApplicationConsole.
*/
public void close();
}

Introduce the concept of a Capture to capture the last value returned by an iterator.

When using an Iterator there's often the requirement to capture an individual value and then use it later.

For example: When using an AvailablePortIterator to configure a cluster, the first port chosen should be used for all other members in the cluster (so that a cluster is formed).

Instead of choosing the port "early", we often want to delay the choice until the last minute. To do this we need a way of "capturing" a choice and then using the choice in other places.

Capture<Integer> clusterPort = new Capture<Integer>(availablePortIterator);

The first time the clusterPort is used it won't have a value, in which case the availablePortIterator is used to determine a value. After that the first "captured" value will always be used.

Add the ability to turn on application lifecycle diagnostics

When creating application processes we often would like to see diagnostic information about how the process. For example, the environment, settings, classpath etc, that the Oracle Tools established to establish an application.

To provide this capability, on a schema-by-schema basis we should add the ability to do this:

schema.setDiagnosticsEnabled(true);

Additionally, we should allow:

  1. this on a builder-by-builder basis.
  2. provide a system property (like oracle.tools.runtime.diagnostics=true).

Correct license text mistake in file headers

The license headers in all files contain the text:

It should be:

We need to fix this in:

  1. JIndent Templates.
  2. Every File.
  3. The template documents.

Refactor Coherence-based Tools to use RemoteExecutors instead of relying on JMX/MBeans to acquire Cluster/Member information

Currently we rely on JMX being enabled to provide cluster/member information that for the most part is used for integration testing (with assertThat).

Now that we have the ability to submit arbitrary remote executables, there's little reason to use/require JMX. Changing to use remote executables will reduce/eliminate the requirement for JMX setup / configuration / installation / virtualization, especially in a Container-based environment.

Remove (Default Virtualized System) from system when using Virtualization

Currently when we use a virtualized system (of System resources), the StdOut and StdErr streams are prefixed with [(Default Virtual System) XX:].

This is not really required and actually makes the output look weird. We can easily remove this (and line numbering).

To indicate that virtualization is occurring we should simply log a message when virtualization starts and stops (via logging).

Closing an in-container (virtual) application should close its JMX server too

When running a Java application internally when it is closed its JMX server is left running. This leaves the port in use but can also on rare occasions stop the JVM from shutting down. The port in use is not a big issue if using an AvailablePortIterator to assign port numbers but could be for repeated use of a schema in a test suite with a fixed JMX port. The intermittent problem with the JVM came to light occasionally when running tests for the .Net wrapper of Oracle Tools. Occasionally the test runner process in Visual Studio would not stop as the internal JVM still had live non-daemon threads associated to JMX running. Closing the JMX servers seemed to make this issue go away - although it was very intermittent to start with.

Closing the JMX server also allows test code to wait for an internal process to be closed. It is possible to register a listener on a JMX connection to a virtual process and be notified when that connection closes.
E.G you can do something like this...

JMXConnector jmxConnector = member.getDeferredJMXConnector().get();
final CountDownLatch memberDestroyedLatch = new CountDownLatch(1);
jmxConnector.addConnectionNotificationListener(new NotificationListener()
{
@Override
public void handleNotification(Notification notification, Object handback)
{
memberDestroyedLatch.countDown();
}
},

new NotificationFilter()
{
@Override
public boolean isNotificationEnabled(Notification notification)
{
return false == JMXConnectionNotification.OPENED.equals(notification.getType());
}
},
null);

member.destroy();

memberDestroyedLatch.await();

This is useful where your test needs to know the process has really stopped before it does something

Native Windows NT / XP processes may hang on destroy

Paul Makin found that when running Native / External Application-based Tests on Windows NT / XP, destroying the application may lead to tests hanging.

This appears to be caused by the order in which we close the i/o streams. To resolve the problem we must close the streams before interrupting the i/o threads and before destroying the underlying process.

Make ApplicationSchemas inherit Environment properties by default

We've seen numerous times that failing to set a schema to inherit environment properties can cause application start and shutdown issues. In every case it seems that failing to inherit environment properties is the underlying cause (as without it new processes have no environment variables - which can make locating the Java executable/binary problematic).

Consequently we should make it inheriting the default, not clearing (as it is now).

NOTE: all existing functional tests are set to inherit, so it's a good reason to make it the default!

Provide the ability to specify the retry mechanism (polling, backoff etc) for Ensured

The current approach to "ensuring" a Deferred is to simply poll at regular intervals until a maximum timeout is reached.

While useful, this could be improved as continuous polling is often a waste of time. Instead we should allow different strategies to be specified, including:

  1. Polling (as we do now)
  2. Exponential Back-Off (both random and uniform)
  3. Fibonacci Back-Off (both random and uniform)

By default we should use a Random Fibonacci Back-Off approach as this has proven to be more effective than polling and exponential back-off algorithms.

To implement this approach we should modify the Ensured class to resolve and use an Iterator that provides suitable times to wait for each attempt at resolving the underlying resource. Once this refactoring has occurred, we can define several Iterator implementations that provides Ensured's with the appropriate values. Those would include:

  1. ConstantIterator that returns a constant value - forever.
  2. FibonacciIterator that returns a number from the Fibonacci sequence.
  3. ExponentialIterator that returns a number from an Exponential sequence.
  4. RandomIterator that returns a random number between 0 and some other number, that of which comes from an Iterator.

Introduce ability to run in NativeJavaApplications in headlesss mode.

In the latest release of Java (on OSX), applications appear to run with awt enabled. This causes background testing applications to gain UI focus and thus stop developers working in the foreground on other applications. To resolve this we need to introduce the headless mode switch and set it "on" by default.

eg: -Djava.awt.headless=true

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.