class ASearchTestSuite(AStampedTestCase): """ Base class for all search-related test suites, providing the core _run_tests method which is used extensively in all subclasses. """ __metaclass__ = ABCMeta def setUp(self): self.searcher = EntitySearch() def tearDown(self): pass def _run_tests(self, tests, base_args, retries=3, delay=1, test_coords=False, test_unique=True, async=True): """ Runs a list of search tests, verifying that each one satisfies its accompanying SearchResultConstraint(s). tests - list of tests, where each test is a tuple(dict, list(SearchResultConstraint)) base_args - dict containing base entity search parameters shared across all tests, all or some of which may override specific args. retries - int denoting the number of times to retry a test case if one or more constraints fail before aborting. test_coords - boolean denoting whether or not to perform each test twice, once with coords enabled, and once without coords enabled (useful for verifying that certain searches really are coordinate agnostic). Example usage with a single test case (excerpt from MovieSearchTests subclass): args = { 'query' : '', 'coords' : None, 'limit' : 10, } tests = [ # search for 'ninja turtles' and expect a movie entity of the same name # as the top result (e.g., at index 0) ({ 'query' : 'ninja turtles', }, [ SearchResultConstraint(title='teenage mutant ninja turtles', types='movie', index=0), ]), ] self._run_tests(tests, args) """ async = False # optionally run test cases in parallel if async: pool = Pool(4) for test in tests: args = copy(base_args) for k, v in test[0].iteritems(): args[k] = v assert "query" in args def validate(results, args, constraints): if test_unique: # constraints = copy(constraints) # constraints.append(UniqueSearchResultConstraint()) # constraints = [ UniqueSearchResultConstraint() ] pass # TODO: optionally test uniqueness / dedupping w.r.t. results via another SearchResultConstraint for constraint in constraints: if not constraint.validate(results): utils.log("") utils.log("-" * 80) utils.log("[%s] SEARCH ERROR query '%s'" % (self, args["query"])) for r in results: utils.log(r) utils.log("-" * 80) utils.log("") raise Exception("search constraint failed (%s) (%s)" % (args, constraint)) subtests = [args] # optionally run each test twice, once with coordinates enabled, and once with them # disabled and expect the same constraints to be satisfied; note: test_coords should # not be set to true for non-national place search tests, but all other search tests # should be agnostic to coords (e.g., movies, books, etc.) if test_coords: args2 = copy(args) coords = (40.736, -73.989) if "coords" not in args2 or args2["coords"] is None: args2["coords"] = coords else: args2["coords"] = None subtests.append(args2) def __do_search(args, constraints): utils.log("") utils.log("-" * 80) utils.log("[%s] SEARCH TEST query '%s'" % (self, args["query"])) utils.log("-" * 80) utils.log("") # perform the actual search itself, validating the results against all constraints # specified by this test case, and retrying if necessary until either the test case # satisfies its constraints or the maximum number of allotted retries is exceeded. fullArgs = copy(args) query = args.pop("query") category = args.pop("category") self.async( lambda: self.searcher.searchEntities(category, query, **args), lambda r: validate(r, fullArgs, constraints), retries=retries, delay=delay, ) for args in subtests: if async: pool.spawn_link_exception(__do_search, args, test[1]) else: __do_search(args, test[1]) if async: pool.join()
def setUp(self): self.searcher = EntitySearch()
# Tests for title + corroborating detail 'true grit john wayne', 'true grit 2010', 'true grit jeff bridges', 'true grit coens brothers', 'superman reeves', 'superman brandon routh', 'superman kirk alyn', 'superman ii', 'superman iii', 'superman kevin spacey', ] def summarize_proxy(proxy): return proxy.name, proxy.release_date def summarize_cluster(cluster): return [summarize_proxy(result.resolverObject) for result in cluster.results] if __name__ == '__main__': searcher = EntitySearch() samples = [] for query in FILM_QUERIES: entitiesAndClusters = searcher.searchEntitiesAndClusters('film', query) samples.append([summarize_cluster(cluster) for _, cluster in entitiesAndClusters]) print for s in samples: print s