'Checks that ops ending up at root are called in the expected order.
To check the order, we find a path along the directed graph formed by
the inputs of each op. If op X has a chain of inputs to op Y, then X
cannot be executed before Y. There may be multiple paths between any two
ops, but the ops along any path are executed in that order. Therefore, we
look up the expected ops in reverse order.
Args:
name: string name of the endpoint, for logging.
endpoint: node whose execution we want to check.
expected_op_order: string list of op types, in the order we expecte them
to be executed leading up to `endpoint`.'

def checkOpOrder(self, name, endpoint, expected_op_order):

    for target in reversed(expected_op_order):
        path = _find_input_path_to_type(endpoint, target)
        self.assertNotEmpty(path)
        logging.info('path[%d]    from    %s    to    %s:    %s', len(path), name, target, [_as_op(x).type for x in path])
        endpoint = path[(-1)]
