function testTree_JoinPredicates2() {
  var c = schema.getCountry();
  var d = schema.getDepartment();
  var e = schema.getEmployee();
  var jh = schema.getJobHistory();
  var j = schema.getJob();

  var treeBefore =
      'select(join_pred(Country.id eq Department.id))\n' +
      '-select(value_pred(Employee.id eq empId))\n' +
      '--select(join_pred(Employee.departmentId eq Department.id))\n' +
      '---select(join_pred(Employee.jobId eq Job.id))\n' +
      '----select(join_pred(JobHistory.jobId eq Job.id))\n' +
      '-----cross_product\n' +
      '------cross_product\n' +
      '-------cross_product\n' +
      '--------cross_product\n' +
      '---------table_access(Employee)\n' +
      '---------table_access(Job)\n' +
      '--------table_access(Department)\n' +
      '-------table_access(JobHistory)\n' +
      '------table_access(Country)\n';

  var treeAfter =
      'select(join_pred(Country.id eq Department.id))\n' +
      '-cross_product\n' +
      '--select(join_pred(JobHistory.jobId eq Job.id))\n' +
      '---cross_product\n' +
      '----select(join_pred(Employee.departmentId eq Department.id))\n' +
      '-----cross_product\n' +
      '------select(join_pred(Employee.jobId eq Job.id))\n' +
      '-------cross_product\n' +
      '--------select(value_pred(Employee.id eq empId))\n' +
      '---------table_access(Employee)\n' +
      '--------table_access(Job)\n' +
      '------table_access(Department)\n' +
      '----table_access(JobHistory)\n' +
      '--table_access(Country)\n';

  var constructTree = function() {
    var queryContext = new lf.query.SelectContext(hr.db.getSchema());
    queryContext.from = [e, j, d, jh, c];
    var predicate1 = jh.jobId.eq(j.id);
    var predicate2 = e.jobId.eq(j.id);
    var predicate3 = e.departmentId.eq(d.id);
    var predicate4 = e.id.eq('empId');
    var predicate5 = c.id.eq(d.id);
    queryContext.where = lf.op.and(
        predicate1, predicate2, predicate3, predicate4, predicate5);

    var crossProductNode1 = new lf.proc.CrossProductNode();
    crossProductNode1.addChild(new lf.proc.TableAccessNode(e));
    crossProductNode1.addChild(new lf.proc.TableAccessNode(j));

    var crossProductNode2 = new lf.proc.CrossProductNode();
    crossProductNode2.addChild(crossProductNode1);
    crossProductNode2.addChild(new lf.proc.TableAccessNode(d));

    var crossProductNode3 = new lf.proc.CrossProductNode();
    crossProductNode3.addChild(crossProductNode2);
    crossProductNode3.addChild(new lf.proc.TableAccessNode(jh));

    var crossProductNode4 = new lf.proc.CrossProductNode();
    crossProductNode4.addChild(crossProductNode3);
    crossProductNode4.addChild(new lf.proc.TableAccessNode(c));

    var selectStep1 = new lf.proc.SelectNode(predicate1);
    selectStep1.addChild(crossProductNode4);
    var selectStep2 = new lf.proc.SelectNode(predicate2);
    selectStep2.addChild(selectStep1);
    var selectStep3 = new lf.proc.SelectNode(predicate3);
    selectStep3.addChild(selectStep2);
    var selectStep4 = new lf.proc.SelectNode(predicate4);
    selectStep4.addChild(selectStep3);
    var selectStep5 = new lf.proc.SelectNode(predicate5);
    selectStep5.addChild(selectStep4);

    return {queryContext: queryContext, root: selectStep5};
  };

  lf.testing.treeutil.assertTreeTransformation(
      constructTree(), treeBefore, treeAfter, pass);
}
Tests a tree that involves a 5 table join. It ensures that all predicate
nodes (both JoinPredicate and ValuePredicate) are pushed as down in the tree
as possible.