Junit 如何在flink中测试keyedbroadcastprocessfunction?

Junit 如何在flink中测试keyedbroadcastprocessfunction?,junit,apache-flink,flink-streaming,flink-cep,Junit,Apache Flink,Flink Streaming,Flink Cep,我是flink的新手,我正在尝试编写junit测试用例来测试KeyedBroadCastProcessFunction。下面是我的代码,当前,我正在TestUtils类中调用getDataStreamOutput方法,并在输入数据根据模式规则列表进行评估后将inputdata和patternrules传递给方法,如果输入数据满足条件,我将获取信号并调用sink函数,并在getDataStreamOutput方法中以字符串形式返回输出数据 @Test public void testCo

我是flink的新手,我正在尝试编写junit测试用例来测试KeyedBroadCastProcessFunction。下面是我的代码,当前,我正在TestUtils类中调用getDataStreamOutput方法,并在输入数据根据模式规则列表进行评估后将inputdata和patternrules传递给方法,如果输入数据满足条件,我将获取信号并调用sink函数,并在getDataStreamOutput方法中以字符串形式返回输出数据

 @Test
    public void testCompareInputAndOutputDataForInputSignal() throws Exception {
        Assertions.assertEquals(sampleInputSignal,
                TestUtils.getDataStreamOutput(
                        inputSignal,
                        patternRules));
    }



public static String getDataStreamOutput(JSONObject input, Map<String, String> patternRules) throws Exception {

            env.setParallelism(1);

            DataStream<JSONObject> inputSignal = env.fromElements(input);

            DataStream<Map<String, String>> rawPatternStream =
                    env.fromElements(patternRules);

            //Generate a key,value pair of set of patterns where key is pattern name and value is pattern condition
            DataStream<Tuple2<String, Map<String, String>>> patternRuleStream =
                    rawPatternStream.flatMap(new FlatMapFunction<Map<String, String>,
                            Tuple2<String, Map<String, String>>>() {
                        @Override
                        public void flatMap(Map<String, String> patternRules,
                                            Collector<Tuple2<String, Map<String, String>>> out) throws Exception {
                            for (Map.Entry<String, String> stringEntry : patternRules.entrySet()) {
                                JSONObject jsonObject = new JSONObject(stringEntry.getValue());
                                Map<String, String> map = new HashMap<>();
                                for (String key : jsonObject.keySet()) {
                                    String value = jsonObject.get(key).toString();
                                    map.put(key, value);
                                }
                                out.collect(new Tuple2<>(stringEntry.getKey(), map));
                            }
                        }
                    });

            BroadcastStream<Tuple2<String, Map<String, String>>> patternRuleBroadcast =
                    patternStream.broadcast(patternRuleDescriptor);


            DataStream<Tuple2<String, JSONObject>> validSignal = inputSignal.map(new MapFunction<JSONObject,
                    Tuple2<String, JSONObject>>() {
                @Override
                public Tuple2<String, JSONObject> map(JSONObject inputSignal) throws Exception {
                    String source =
                            inputSignal.getSource();
                    return new Tuple2<>(source, inputSignal);
                }
            }).keyBy(0).connect(patternRuleBroadcast).process(new MyKeyedBroadCastProcessFunction());
            
            
             validSignal.map(new MapFunction<Tuple2<String, JSONObject>,
                    JSONObject>() {
                @Override
                public JSONObject map(Tuple2<String, JSONObject> inputSignal) throws Exception {
                    return inputSignal.f1;
                }
            }).addSink(new getDataStreamOutput());

            env.execute("TestFlink");
        }
        return (getDataStreamOutput.dataStreamOutput);
    }


    @SuppressWarnings("serial")
    public static final class getDataStreamOutput implements SinkFunction<JSONObject> {
        public static String dataStreamOutput;

        public void invoke(JSONObject inputSignal) throws Exception {
            dataStreamOutput = inputSignal.toString();
        }
    }
@测试
public void testcompareInputAddOutDataForInputSignal()引发异常{
assertEquals(sampleInputSignal,
TestUtils.getDataStreamOutput(
输入信号,
规则),;
}
公共静态字符串getDataStreamOutput(JSONObject输入,映射模式规则)引发异常{
环境(一);
DataStream inputSignal=env.fromElements(输入);
数据流rawPatternStream=
环境fromElements(模式规则);
//生成一组模式的键、值对,其中键是模式名称,值是模式条件
数据流模式规则流=
flatMap(新的FlatMapFunction(){
@凌驾
公共空间平面地图(地图模式规则,
收集器输出)抛出异常{
对于(Map.Entry-stringEntry:patternRules.entrySet()){
JSONObject JSONObject=新的JSONObject(stringEntry.getValue());
Map Map=newhashmap();
for(字符串键:jsonObject.keySet()){
字符串值=jsonObject.get(key.toString();
map.put(键、值);
}
collect(新的Tuple2(stringEntry.getKey(),map));
}
}
});
广播流模式规则广播=
patternStream.broadcast(patternRuleDescriptor);
DataStream validSignal=inputSignal.map(新的MapFunction(){
@凌驾
公共Tuple2映射(JSONObject inputSignal)引发异常{
字符串源=
inputSignal.getSource();
返回新的Tuple2(源、输入信号);
}
}).keyBy(0).connect(patternRuleBroadcast).process(新的MyKeyedBroadCastProcessFunction());
validSignal.map(新的MapFunction(){
@凌驾
公共JSONObject映射(Tuple2 inputSignal)引发异常{
返回inputSignal.f1;
}
}).addSink(新的getDataStreamOutput());
环境执行(“TestFlink”);
}
返回(getDataStreamOutput.dataStreamOutput);
}
@抑制警告(“串行”)
公共静态final类getDataStreamOutput实现函数{
公共静态字符串dataStreamOutput;
公共void调用(JSONObject inputSignal)引发异常{
dataStreamOutput=inputSignal.toString();
}
}
我需要使用相同的广播规则测试不同的输入,但每次我调用此函数时,它会一次又一次地从一开始就执行获取输入信号广播数据的过程,是否有一种方法可以广播一次并继续将输入发送到我探索的方法我可以使用类似下面的CoFlatMapFunction组合datastream并在方法运行时继续发送输入规则,但对于这一方法,datastream必须再次继续从kafka主题获取数据,这将使要加载的方法负担过重kafka utils和服务器

 DataStream<JSONObject> inputSignalFromKafka = env.addSource(inputSignalKafka);

    DataStream<org.json.JSONObject> inputSignalFromMethod = env.fromElements(inputSignal));
    
    DataStream<JSONObject> inputSignal = inputSignalFromMethod.connect(inputSignalFromKafka)
                .flatMap(new SignalCoFlatMapper());


   public static class SignalCoFlatMapper
            implements CoFlatMapFunction<JSONObject, JSONObject, JSONObject> {

        @Override
        public void flatMap1(JSONObject inputValue, Collector<JSONObject> out) throws Exception {
            out.collect(inputValue);

        }

        @Override
        public void flatMap2(JSONObject kafkaValue, Collector<JSONObject> out) throws Exception {
            out.collect(kafkaValue);

        }
    }
数据流inputSignalFromKafka=env.addSource(inputSignalKafka); DataStream inputSignalFromMethod=env.fromElements(inputSignal)); DataStream inputSignal=inputSignalFromMethod.connect(inputSignalFromKafka) .flatMap(新的SignalCoFlatMapper()); 公共静态类SignalCoFlatMapper 实现CoFlatMapFunction{ @凌驾 公共void flatMap1(JSONObject inputValue,Collector out)引发异常{ 输出。收集(输入值); } @凌驾 公共void flatMap2(JSONObject kafkaValue,收集器输出)引发异常{ 出.收(卡夫卡瓦卢); } } 我在stackoverflow中找到了一个链接,但这让我很困惑


无论如何,在测试用例中,我只能在Before方法中广播一次,并不断向我的广播函数发送不同类型的数据

您可以使用
KeyedTwoInputStreamOperatorTestHarness
来实现这一点,例如,让我们假设您有以下
KeyedBroadcastProcessFunction
,其中定义了一些两个
DataStream
通道的业务逻辑

public class SimpleKeyedBroadcastProcessFunction extends KeyedBroadcastProcessFunction<String, String, String, String> {
    @Override
    public void processElement(String inputEntry,
                               ReadOnlyContext readOnlyContext, Collector<String> collector) throws Exception {
    //business logic for how you want to process your data stream records
    }

  @Override
    public void processBroadcastElement(String broadcastInput, Context
            context, Collector<String> collector) throws Exception {
   //process input from your broadcast channel
}

请注意,邮件列表中也讨论了这一点。请参阅。如果您有一个无状态函数,则不需要使用测试工具,您可以参考官方文档,更好地了解ApacheFlink中的测试工作原理
public class SimpleKeyedBroadcastProcessFunctionTest {
    private SimpleKeyedBroadcastProcessFunction processFunction;
    private KeyedTwoInputStreamOperatorTestHarness<String, String, String, String> testHarness;

  @Before
  public void setup() throws Exception {
    processFunction =  new SimpleKeyedBroadcastProcessFunction();
    testHarness = new KeyedTwoInputStreamOperatorTestHarness<>(
                new CoBroadcastWithKeyedOperator<>(processFunction, ImmutableList.of(BROADCAST_MAP_STATE_DESCRIPTOR)),
                (KeySelector<String, String>) string -> string ,
                (KeySelector<String, String>) string -> string,
                TypeInformation.of(String.class));
   testHarness.setup();
   testHarness.open();
  }

  @After
    public void cleanup() throws Exception {
        testHarness.close();
    }

  @Test
  public void testProcessRegularInput() throws Exception {
      //processElement1 send elements into your regular stream, second param will be the event time of the record
      testHarness.processElement1(new StreamRecord<>("Hello", 0));
      //Access records collected during processElement  
      List<StreamRecord<? extends String>> records = testHarness.extractOutputStreamRecords();
      assertEquals("Hello", records.get(0).getValue())
  }

    @Test
  public void testProcessBroadcastInput() throws Exception {
      //processElement2 send elements into your broadcast stream, second param will be the event time of the record
      testHarness.processElement2(new StreamRecord<>("Hello from Broadcast", 0));
      //Access records collected during processElement  
      List<StreamRecord<? extends String>> records = testHarness.extractOutputStreamRecords();
      assertEquals("Hello from Broadcast", records.get(0).getValue())
  }
}