/*
# Licensed Materials - Property of IBM
# Copyright IBM Corp. 2015
*/
package com.ibm.streamsx.topology.test.spl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import com.ibm.json.java.JSONObject;
import com.ibm.streams.flow.handlers.MostRecent;
import com.ibm.streams.operator.StreamSchema;
import com.ibm.streams.operator.Tuple;
import com.ibm.streams.operator.Type;
import com.ibm.streams.operator.Type.MetaType;
import com.ibm.streamsx.topology.Topology;
import com.ibm.streamsx.topology.context.ContextProperties;
import com.ibm.streamsx.topology.function.Supplier;
import com.ibm.streamsx.topology.generator.spl.SPLGenerator;
import com.ibm.streamsx.topology.spl.SPL;
import com.ibm.streamsx.topology.spl.SPLStream;
import com.ibm.streamsx.topology.test.TestTopology;
import com.ibm.streamsx.topology.tester.Condition;
import com.ibm.streamsx.topology.tester.Tester;
public class SPLOperatorsTest extends TestTopology {
@Before
public void runSpl() {
assumeSPLOk();
}
/**
* Test we can invoke an SPL operator.
*/
@Test
public void testSPLOperator() throws Exception {
Topology topology = new Topology("testSPLOperator");
SPLStream tuples = SPLStreamsTest.testTupleStream(topology);
// Filter on the vi attribute, passing the value 321.
Map<String,Object> params = new HashMap<>();
params.put("attr", tuples.getSchema().getAttribute("vi"));
params.put("value", 321);
SPL.addToolkit(tuples, new File(getTestRoot(), "spl/testtk"));
SPLStream int32Filtered = SPL.invokeOperator("testspl::Int32Filter", tuples, tuples.getSchema(), params);
Tester tester = topology.getTester();
Condition<Long> expectedCount = tester.tupleCount(int32Filtered, 2);
Condition<List<Tuple>> expectedTuples = tester.tupleContents(int32Filtered,
SPLStreamsTest.TEST_TUPLES[0],
SPLStreamsTest.TEST_TUPLES[2]
);
complete(tester, expectedCount, 10, TimeUnit.SECONDS);
assertTrue(expectedCount.toString(), expectedCount.valid());
assertTrue(expectedTuples.toString(), expectedTuples.valid());
}
/**
* Test we can invoke an SPL operator.
*/
@Test
public void testSPLOperatorMultipleOuptuts() throws Exception {
Topology topology = new Topology();
SPLStream tuples = SPLStreamsTest.testTupleStream(topology);
// Filter on the vi attribute, passing the value 321.
Map<String,Object> params = new HashMap<>();
params.put("attr", tuples.getSchema().getAttribute("vi"));
params.put("value", 321);
SPL.addToolkit(tuples, new File(getTestRoot(), "spl/testtk"));
List<SPLStream> outputs = SPL.invokeOperator(
topology,
"testSPLOperatorMultipleOuptuts",
"testspl::Int32FilterPF",
Collections.singletonList(tuples),
Collections.nCopies(2, tuples.getSchema()),
params);
SPLStream int32Filtered = outputs.get(0);
SPLStream int32Dropped = outputs.get(1);
Tester tester = topology.getTester();
Condition<Long> expectedCount = tester.tupleCount(int32Dropped, 2);
Condition<List<Tuple>> expectedTuples = tester.tupleContents(int32Filtered,
SPLStreamsTest.TEST_TUPLES[0],
SPLStreamsTest.TEST_TUPLES[2]
);
Condition<List<Tuple>> droppedTuples = tester.tupleContents(int32Dropped,
SPLStreamsTest.TEST_TUPLES[1],
SPLStreamsTest.TEST_TUPLES[3]
);
complete(tester, expectedCount, 10, TimeUnit.SECONDS);
assertTrue(expectedCount.toString(), expectedCount.valid());
assertTrue(expectedTuples.toString(), expectedTuples.valid());
assertTrue(droppedTuples.toString(), droppedTuples.valid());
}
/**
* Test we can invoke an SPL operator with various parameter types.
*/
private void testOpParams(String testName, OpParamAdder opParamAdder) throws Exception {
Topology topology = new Topology(testName);
opParamAdder.init(topology, getConfig());
// getConfig().put(ContextProperties.KEEP_ARTIFACTS, true);
StreamSchema schema = Type.Factory.getStreamSchema(
"tuple<"
+ "rstring r"
+ ", ustring u"
+ ", boolean b"
+ ", int8 i8, int16 i16, int32 i32, int64 i64"
+ ", uint8 ui8, uint16 ui16, uint32 ui32, uint64 ui64"
+ ", float32 f32, float64 f64"
+ " >");
Random rand = new Random();
String r = "test X\tY\"Lit\nerals\\nX\\tY " + rand.nextInt();
opParamAdder.put("r", r);
String u = "test X\tY\"Lit\nerals\\nX\\tY " + rand.nextInt();
opParamAdder.put("u", SPL.createValue(u, MetaType.USTRING));
boolean b = rand.nextBoolean();
opParamAdder.put("b", b);
byte i8 = (byte) rand.nextInt();
short i16 = (short) rand.nextInt();
int i32 = rand.nextInt();
long i64 = rand.nextLong();
opParamAdder.put("i8", i8);
opParamAdder.put("i16", i16);
opParamAdder.put("i32", i32);
opParamAdder.put("i64", i64);
byte ui8 = (byte) 0xFF; // 255 => -1
short ui16 = (short) 0xFFFE; // 65534 => -2
int ui32 = 0xFFFFFFFD; // 4294967293 => -3
long ui64 = 0xFFFFFFFFFFFFFFFCL; // 18446744073709551612 => -4
opParamAdder.put("ui8", SPL.createValue(ui8, MetaType.UINT8));
opParamAdder.put("ui16", SPL.createValue(ui16, MetaType.UINT16));
opParamAdder.put("ui32", SPL.createValue(ui32, MetaType.UINT32));
opParamAdder.put("ui64", SPL.createValue(ui64, MetaType.UINT64));
float f32 = rand.nextFloat();
double f64 = rand.nextDouble();
opParamAdder.put("f32", f32);
opParamAdder.put("f64", f64);
SPL.addToolkit(topology, new File(getTestRoot(), "spl/testtk"));
SPLStream paramTuple = SPL.invokeSource(topology, "testgen::TypeLiteralTester", opParamAdder.getParams(), schema);
// paramTuple.print();
// paramTuple.filter(new AllowAll<Tuple>());
Tester tester = topology.getTester();
Condition<Long> expectedCount = tester.tupleCount(paramTuple, 1);
MostRecent<Tuple> mr = tester.splHandler(paramTuple, new MostRecent<Tuple>());
// getConfig().put(ContextProperties.KEEP_ARTIFACTS, true);
complete(tester, expectedCount, 10, TimeUnit.SECONDS);
assertTrue(expectedCount.toString(), expectedCount.valid());
Tuple tuple = mr.getMostRecentTuple();
// System.out.println("tuple: " + tuple);
assertEquals(r, tuple.getString("r"));
assertEquals(u, tuple.getString("u"));
assertEquals(i8, tuple.getByte("i8"));
assertEquals(i16, tuple.getShort("i16"));
assertEquals(i32, tuple.getInt("i32"));
assertEquals(i64, tuple.getLong("i64"));
assertEquals(ui8, tuple.getByte("ui8"));
assertEquals(ui16, tuple.getShort("ui16"));
assertEquals(ui32, tuple.getInt("ui32"));
assertEquals(ui64, tuple.getLong("ui64"));
assertEquals(f32, tuple.getFloat("f32"), 0.001);
assertEquals(f64, tuple.getDouble("f64"), 0.001);
}
/**
* Operator parameter adder.
* Base implementation adds as Literals.
*/
private static class OpParamAdder {
final Map<String,Object> params = new HashMap<>();
Topology top;
Map<String,Object> config;
void init(Topology top, Map<String,Object> config) {
this.top = top;
this.config = config;
}
void put(String opParamName, Object opParamValue) {
params.put(opParamName, opParamValue);
}
Map<String,Object> getParams() {
return params;
}
}
@Test
public void testParamLiterals() throws Exception {
// Test operator parameters with literal values
testOpParams("testParamLiterals", new OpParamAdder());
}
@Test
public void testSubmissionParamsWithDefault() throws Exception {
// Test operator parameters with submission time values with defaults
testOpParams("testSubmissionParamsWithDefault", new OpParamAdder() {
void put(String opParamName, Object opParamValue) {
Supplier<?> sp;
if (!(opParamValue instanceof JSONObject))
sp = top.createSubmissionParameter(opParamName, opParamValue);
else
sp = SPL.createSubmissionParameter(top, opParamName, opParamValue, true);
params.put(opParamName, sp);
}
});
}
@Test
public void testSubmissionParamsWithoutDefault() throws Exception {
// Test operator parameters with submission time values without defaults
testOpParams("testSubmissionParamsWithoutDefault", new OpParamAdder() {
void put(String opParamName, Object opParamValue) {
Supplier<?> sp;
if (!(opParamValue instanceof JSONObject))
sp = top.createSubmissionParameter(opParamName,
(Class<?>)opParamValue.getClass());
else
sp = SPL.createSubmissionParameter(top, opParamName, opParamValue, false);
params.put(opParamName, sp);
@SuppressWarnings("unchecked")
Map<String,Object> submitParams = (Map<String,Object>) config.get(ContextProperties.SUBMISSION_PARAMS);
if (submitParams == null) {
submitParams = new HashMap<>();
config.put(ContextProperties.SUBMISSION_PARAMS, submitParams);
}
if (!(opParamValue instanceof JSONObject))
submitParams.put(opParamName, opParamValue);
else
submitParams.put(opParamName, pvToStr((JSONObject)opParamValue));
}
});
}
private String pvToStr(JSONObject jo) {
// A Client of the API shouldn't find itself in
// a place to need this. It's just an artifact of
// the way these tests are composed plus lack of a
// public form of valueToString(SPL.createValue(...)).
String type = (String) jo.get("type");
if (!"__spl_value".equals(type))
throw new IllegalArgumentException("jo " + jo);
JSONObject value = (JSONObject) jo.get("value");
String metaType = (String) value.get("metaType");
Object v = value.get("value");
if (metaType.startsWith("UINT"))
return SPLGenerator.unsignedString(v);
else
return v.toString();
}
}