diff --git a/docs/api.rst b/docs/api.rst --- a/docs/api.rst +++ b/docs/api.rst @@ -144,7 +144,6 @@ swh:1:rev:8d517bdfb57154b8a11d7f1682ecc0f79abf8e02 ... - .. http:get:: /graph/randomwalk/:src/:dst Performs a graph *random* traversal, i.e., picking one random successor @@ -178,6 +177,12 @@ ... +.. http:get:: /graph/randomwalk/last/:src/:dst + + Same as ``/graph/randomwalk``, but only retururn the last visited node, + i.e., destination, if any. + + Visit ----- diff --git a/swh/graph/client.py b/swh/graph/client.py --- a/swh/graph/client.py +++ b/swh/graph/client.py @@ -72,18 +72,22 @@ 'direction': direction })) - def walk(self, src, dst, edges="*", traversal="dfs", direction="forward"): + def walk(self, src, dst, + edges="*", traversal="dfs", direction="forward", last=False): + endpoint = 'walk/last/{}/{}' if last else 'walk/{}/{}' return self.get_lines( - 'walk/{}/{}'.format(src, dst), + endpoint.format(src, dst), params={ 'edges': edges, 'traversal': traversal, 'direction': direction }) - def random_walk(self, src, dst, edges="*", direction="forward"): + def random_walk(self, src, dst, + edges="*", direction="forward", last=False): + endpoint = 'randomwalk/last/{}/{}' if last else 'randomwalk/{}/{}' return self.get_lines( - 'randomwalk/{}/{}'.format(src, dst), + endpoint.format(src, dst), params={ 'edges': edges, 'direction': direction diff --git a/swh/graph/server/app.py b/swh/graph/server/app.py --- a/swh/graph/server/app.py +++ b/swh/graph/server/app.py @@ -125,7 +125,7 @@ return simple_traversal -def get_walk_handler(random=False): +def get_walk_handler(random=False, last=False): async def walk(request): backend = request.app['backend'] @@ -144,7 +144,12 @@ src_node, dst) else: it = backend.walk(direction, edges, algo, src_node, dst) + res_node = None async for res_node in it: + if not last: + res_pid = pid_of_node(res_node, backend) + await response.write('{}\n'.format(res_pid).encode()) + if last and res_node is not None: res_pid = pid_of_node(res_node, backend) await response.write('{}\n'.format(res_pid).encode()) return response @@ -204,9 +209,13 @@ # temporarily disabled in wait of a proper fix for T1969 # app.router.add_get('/graph/walk/{src}/{dst}', # get_walk_handler(random=False)) + # app.router.add_get('/graph/walk/last/{src}/{dst}', + # get_walk_handler(random=False, last=True)) app.router.add_get('/graph/randomwalk/{src}/{dst}', - get_walk_handler(random=True)) + get_walk_handler(random=True, last=False)) + app.router.add_get('/graph/randomwalk/last/{src}/{dst}', + get_walk_handler(random=True, last=True)) app.router.add_get('/graph/neighbors/count/{src}', get_count_handler('neighbors')) diff --git a/swh/graph/tests/test_api_client.py b/swh/graph/tests/test_api_client.py --- a/swh/graph/tests/test_api_client.py +++ b/swh/graph/tests/test_api_client.py @@ -93,12 +93,14 @@ @pytest.mark.skip(reason='currently disabled due to T1969') def test_walk(graph_client): - actual = list(graph_client.walk( - 'swh:1:dir:0000000000000000000000000000000000000016', 'rel', - edges='dir:dir,dir:rev,rev:*', - direction='backward', - traversal='bfs' - )) + args = ('swh:1:dir:0000000000000000000000000000000000000016', 'rel') + kwargs = { + 'edges': 'dir:dir,dir:rev,rev:*', + 'direction': 'backward', + 'traversal': 'bfs', + } + + actual = list(graph_client.walk(*args, **kwargs)) expected = [ 'swh:1:dir:0000000000000000000000000000000000000016', 'swh:1:dir:0000000000000000000000000000000000000017', @@ -107,18 +109,34 @@ ] assert set(actual) == set(expected) + kwargs2 = kwargs.copy() + kwargs2['last'] = True + actual = list(graph_client.walk(*args, **kwargs2)) + expected = [ + 'swh:1:rel:0000000000000000000000000000000000000019' + ] + assert set(actual) == set(expected) + def test_random_walk(graph_client): """as the walk is random, we test a visit from a cnt node to the only origin in the dataset, and only check the final node of the path (i.e., the origin) """ - src = 'swh:1:cnt:0000000000000000000000000000000000000001' - actual = list(graph_client.random_walk(src, 'ori', direction='backward')) + args = ('swh:1:cnt:0000000000000000000000000000000000000001', 'ori') + kwargs = {'direction': 'backward'} expected_root = 'swh:1:ori:0000000000000000000000000000000000000021' - assert actual[0] == src + + actual = list(graph_client.random_walk(*args, **kwargs)) + assert len(actual) > 1 # no origin directly links to a content + assert actual[0] == args[0] assert actual[-1] == expected_root + kwargs2 = kwargs.copy() + kwargs2['last'] = True + actual = list(graph_client.random_walk(*args, **kwargs2)) + assert actual == [expected_root] + def test_count(graph_client): actual = graph_client.count_leaves(