function checkIndexJoin(tableARelation, tableBRelation, joinPredicate) {
  var noOpStepA = new lf.proc.NoOpStep([tableARelation]);
  var noOpStepB = new lf.proc.NoOpStep([tableBRelation]);
  var joinStep = new lf.proc.JoinStep(env.global, joinPredicate, false);
  joinStep.addChild(noOpStepA);
  joinStep.addChild(noOpStepB);

  // Detecting the expected IDs that should appear in the result.
  var tableAIds = lf.structs.set.create(tableARelation.entries.map(
      function(entry) {
        return entry.getField(ta['id']);
      }));
  var tableBIds = lf.structs.set.create(tableARelation.entries.map(
      function(entry) {
        return entry.getField(tb['id']);
      }));
  var expectedIds = lf.structs.set.values(
      setIntersection(tableAIds, tableBIds));

  // Choosing the left predicate column as the indexed column.
  joinStep.markAsIndexJoin(joinPredicate.leftColumn);
  assertTrue(joinStep.toString().indexOf('index_nested_loop') != -1);
  return joinStep.exec().then(function(relations) {
    assertEquals(1, relations.length);
    assertTableATableBJoin(relations[0], expectedIds);
  });
}
Performs index join on the given relation and asserts that the results are
correct.
@param {!lf.proc.Relation} tableARelation
@param {!lf.proc.Relation} tableBRelation
@param {!lf.pred.JoinPredicate} joinPredicate The join predicate to used for
    joining. The left column of the join predicate will be used for
    performing the join. Callers are responsible to ensure that the relation
    corresponding to the indexed column (could be either of tableARelation or
    tableBRelation) includes ALL rows of this table, otherwise index join is
    invalid and this test would fail.
@return {!IThenable}