Advanced topics
In what follows, we discuss miscellaneous information on topics that are not mandatory for usage of Copper in a project, yet they can prove to be useful for the user.
Cross compatibility with non-Copper definitions
Defining measures using both Copper 2 and the classic ways (like the builders or using the measure definitions) should work seamlessly.
Copper is also able to handle non-Copper analysis levels and hierarchies, under the condition that the property in com.quartetfs.biz.pivot.cube.hierarchy.IAnalysisHierarchy#LEVEL_TYPES_PROPERTY
be specified. This is because Copper cannot be aware of the level names or types for the analysis hierarchies defined outside of Copper (like Java-based analysis hierarchies); in this case the user needs to help it a little by providing that information in the hierarchy properties.
Example:
...
.withHierarchy(HIERARCHY_NAME).slicing()
.withPluginKey(ANALYSIS_HIERARCHY_PLUGIN_KEY)
.withProperty(IAnalysisHierarchy.LEVEL_TYPES_PROPERTY, LEVEL_NAME + ":" + Types.TYPE_LONG)
...
Using the Copper testing framework
One of the objectives of Copper is to be easily testable. This is why it bundles a lot of utilities and APIs to help test your calculations. The main one is the CubeTester.
Since the testing framework is only needed for tests and require test dependencies, it is not available in the activepivot-copper2-impl maven module. You must import the activepivot-copper2-test module before using it :
<dependency> <groupId>com.activeviam.activepivot</groupId> <artifactId>activepivot-copper2-test</artifactId> <scope>test</scope> </dependency>
Defining a test environment
We use JUnit rules to define a builder field that will be reset at each test, this rule allows us to automatize the creation, and deletion of multiple ActivePivot components in order to make the tests more concise and entirely focused on the tested features.
@Rule
public JUnitCubeTesterBuilder builder = new JUnitCubeTesterBuilder(createTester());
In the definition of the builder, we provide a static function that returns a CubeTesterBuilder, in which you define the specifics of your Datastore, Datastore selection and cube descriptions :
public static CubeTesterBuilder createTester() {
IDatastoreSchemaDescription datastoreDescription = new DatastoreDescriptionConfig()
.schemaDescription();
ISelectionDescription selectionDescription = EquityDerivativesManagerConfig
.createSandboxSchemaSelectionDescription(datastoreDescription);
IActivePivotInstanceDescription cubeDescription = StartBuilding.cube()
.withName("C")
.withDimensions(EquityDerivativesCubeDimensionsConfig::dimensions)
.build();
return new CubeTesterBuilder(
datastoreDescription,
selectionDescription,
createTestData(),
cubeDescription);
}
In the tests, you can call the builder.build(consumer)
method, where consumer
is a
Comsumer<ICopperContext>
(e.g. a Java lambda containing the tested Copper code.),
and obtain the built Testing cube :
final CubeTester tester = builder.build(EquityDerivativesCubeMeasuresConfig::pnlMonitoring);
Where pnlMonitoring()
is a static function such as :
public static void pnlMonitoring(ICopperContext context) {
Copper.combine(
Copper.sum(RISK__PNL),
Copper.constant(0d).as(PNL_LIMIT))
.mapToDouble(a -> a.readDouble(0) >= a.readDouble(1) ? 1 : -1)
.as(PNL_STATUS).publish(context);
}
And then you can use the subsequent tester to perform inquiries on data returned by queries like :
tester.query()
.forMeasures(PNL_LIMIT)
.run()
.getTester()
.hasOnlyOneCell()
.containing(0D);
or some meta-inquiries on the state of the cube after being enriched by Copper :
tester.description()
.hasOnlyOneMeasure()
.hasOnlyOnePreAggregatedMeasure()
.withName("myMeasure");
Using the testers
As mentioned before, different methods of the obtained {CubeTester} can be used for various needs :
query()
will start the builder of aCompiledQuery
that can be customized extensively and executed with therun()
method. The obtained results can be tested on every location.description()
returns a Tester allowing to test the status of the cube, such as the presence of measures, the hierarchies count, etc.mdxQuery(mdx, contextValues...)
runs a MDX Query and returns the obtained CellSetmanager()
returns the manager attached to the tested Cubepivot()
returns the tested cube