@Test
  public void testJoinWithTuples() {
    try {
      final Partitioner<Long> partitioner = new TestPartitionerLong();

      ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

      DataSet<Tuple2<Long, Long>> input1 = env.fromElements(new Tuple2<Long, Long>(0L, 0L));
      DataSet<Tuple3<Long, Long, Long>> input2 =
          env.fromElements(new Tuple3<Long, Long, Long>(0L, 0L, 0L));

      input1
          .join(input2, JoinHint.REPARTITION_HASH_FIRST)
          .where(1)
          .equalTo(0)
          .withPartitioner(partitioner)
          .print();

      Plan p = env.createProgramPlan();
      OptimizedPlan op = compileNoStats(p);

      SinkPlanNode sink = op.getDataSinks().iterator().next();
      DualInputPlanNode join = (DualInputPlanNode) sink.getInput().getSource();

      assertEquals(ShipStrategyType.PARTITION_CUSTOM, join.getInput1().getShipStrategy());
      assertEquals(ShipStrategyType.PARTITION_CUSTOM, join.getInput2().getShipStrategy());
      assertEquals(partitioner, join.getInput1().getPartitioner());
      assertEquals(partitioner, join.getInput2().getPartitioner());
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    }
  }
  @Test
  public void testIncompatibleHashAndCustomPartitioning() {
    try {
      ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

      DataSet<Tuple3<Long, Long, Long>> input =
          env.fromElements(new Tuple3<Long, Long, Long>(0L, 0L, 0L));

      DataSet<Tuple3<Long, Long, Long>> partitioned =
          input
              .partitionCustom(
                  new Partitioner<Long>() {
                    @Override
                    public int partition(Long key, int numPartitions) {
                      return 0;
                    }
                  },
                  0)
              .map(new IdentityMapper<Tuple3<Long, Long, Long>>())
              .withForwardedFields("0", "1", "2");

      DataSet<Tuple3<Long, Long, Long>> grouped =
          partitioned
              .distinct(0, 1)
              .groupBy(1)
              .sortGroup(0, Order.ASCENDING)
              .reduceGroup(new IdentityGroupReducer<Tuple3<Long, Long, Long>>())
              .withForwardedFields("0", "1");

      grouped
          .join(partitioned, JoinHint.REPARTITION_HASH_FIRST)
          .where(0)
          .equalTo(0)
          .with(new DummyFlatJoinFunction<Tuple3<Long, Long, Long>>())
          .print();

      Plan p = env.createProgramPlan();
      OptimizedPlan op = compileNoStats(p);

      SinkPlanNode sink = op.getDataSinks().iterator().next();
      DualInputPlanNode coGroup = (DualInputPlanNode) sink.getInput().getSource();

      assertEquals(ShipStrategyType.PARTITION_HASH, coGroup.getInput1().getShipStrategy());
      assertTrue(
          coGroup.getInput2().getShipStrategy() == ShipStrategyType.PARTITION_HASH
              || coGroup.getInput2().getShipStrategy() == ShipStrategyType.FORWARD);
    } catch (Exception e) {
      e.printStackTrace();
      fail(e.getMessage());
    }
  }