diff --git a/api/server/src/main/java/org/softwareheritage/graph/AllowedEdges.java b/api/server/src/main/java/org/softwareheritage/graph/AllowedEdges.java index 72bcdf7..784207d 100644 --- a/api/server/src/main/java/org/softwareheritage/graph/AllowedEdges.java +++ b/api/server/src/main/java/org/softwareheritage/graph/AllowedEdges.java @@ -1,48 +1,58 @@ package org.softwareheritage.graph; import java.util.ArrayList; +import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.Node; public class AllowedEdges { + Graph graph; // First dimension is source node type, second dimension is destination node type boolean[][] allowed; - public AllowedEdges(String edgesFmt) { + public AllowedEdges(Graph graph, String edgesFmt) { + this.graph = graph; + int nbNodeTypes = Node.Type.values().length; this.allowed = new boolean[nbNodeTypes][nbNodeTypes]; // Special values (null, empty, "*") if (edgesFmt == null || edgesFmt.isEmpty()) { return; } if (edgesFmt.equals("*")) { for (int i = 0; i < nbNodeTypes; i++) { for (int j = 0; j < nbNodeTypes; j++) { allowed[i][j] = true; } } return; } // Format: "src1:dst1,src2:dst2,[...]" String[] edgeTypes = edgesFmt.split(","); for (String edgeType : edgeTypes) { String[] nodeTypes = edgeType.split(":"); if (nodeTypes.length != 2) { throw new IllegalArgumentException("Cannot parse edge type: " + edgeType); } ArrayList srcTypes = Node.Type.parse(nodeTypes[0]); ArrayList dstTypes = Node.Type.parse(nodeTypes[1]); for (Node.Type srcType : srcTypes) { for (Node.Type dstType : dstTypes) { allowed[srcType.ordinal()][dstType.ordinal()] = true; } } } } - public boolean isAllowed(Node.Type currentType, Node.Type neighborType) { - return allowed[currentType.ordinal()][neighborType.ordinal()]; + public boolean isAllowed(long srcNodeId, long dstNodeId) { + Node.Type srcType = graph.getNodeType(srcNodeId); + Node.Type dstType = graph.getNodeType(dstNodeId); + return isAllowed(srcType, dstType); + } + + public boolean isAllowed(Node.Type srcType, Node.Type dstType) { + return allowed[srcType.ordinal()][dstType.ordinal()]; } } diff --git a/api/server/src/main/java/org/softwareheritage/graph/App.java b/api/server/src/main/java/org/softwareheritage/graph/App.java index 45b8803..e02a6a5 100644 --- a/api/server/src/main/java/org/softwareheritage/graph/App.java +++ b/api/server/src/main/java/org/softwareheritage/graph/App.java @@ -1,124 +1,124 @@ package org.softwareheritage.graph; import java.io.IOException; import java.util.List; import java.util.Map; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import io.javalin.Javalin; import io.javalin.http.Context; import io.javalin.plugin.json.JavalinJackson; +import org.softwareheritage.graph.Endpoint; import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.SwhId; import org.softwareheritage.graph.algo.Stats; -import org.softwareheritage.graph.algo.Traversal; public class App { public static void main(String[] args) throws IOException { String path = args[0]; Graph graph = new Graph(path); Stats stats = new Stats(path); // Clean up on exit Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { try { graph.cleanUp(); } catch (IOException e) { System.out.println("Could not clean up graph on exit: " + e); } } }); // Configure Jackson JSON to use snake case naming style ObjectMapper objectMapper = JavalinJackson.getObjectMapper(); objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); JavalinJackson.configure(objectMapper); Javalin app = Javalin.create().start(5009); app.before("/stats/*", ctx -> { checkQueryStrings(ctx, ""); }); app.before("/leaves/*", ctx -> { checkQueryStrings(ctx, "direction|edges"); }); app.before("/neighbors/*", ctx -> { checkQueryStrings(ctx, "direction|edges"); }); app.before("/visit/*", ctx -> { checkQueryStrings(ctx, "direction|edges"); }); app.before("/walk/*", ctx -> { checkQueryStrings(ctx, "direction|edges|traversal"); }); app.get("/stats/", ctx -> { ctx.json(stats); }); // Graph traversal endpoints // By default the traversal is a forward DFS using all edges app.get("/leaves/:src", ctx -> { SwhId src = new SwhId(ctx.pathParam("src")); String direction = ctx.queryParam("direction", "forward"); String edgesFmt = ctx.queryParam("edges", "*"); - Traversal traversal = new Traversal(graph, direction, edgesFmt); - ctx.json(traversal.leavesEndpoint(src)); + Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); + ctx.json(endpoint.leaves(src)); }); app.get("/neighbors/:src", ctx -> { SwhId src = new SwhId(ctx.pathParam("src")); String direction = ctx.queryParam("direction", "forward"); String edgesFmt = ctx.queryParam("edges", "*"); - Traversal traversal = new Traversal(graph, direction, edgesFmt); - ctx.json(traversal.neighborsEndpoint(src)); + Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); + ctx.json(endpoint.neighbors(src)); }); // TODO: anonymous class to return both nodes/paths? (waiting on node types map merged/refactor) /*app.get("/visit/:src", ctx -> { SwhId src = new SwhId(ctx.pathParam("src")); String direction = ctx.queryParam("direction", "forward"); String edgesFmt = ctx.queryParam("edges", "*"); Visit visit = new Visit(graph, src, edgesFmt, direction, Visit.OutputFmt.NODES_AND_PATHS); ctx.json(visit); });*/ app.get("/visit/nodes/:src", ctx -> { SwhId src = new SwhId(ctx.pathParam("src")); String direction = ctx.queryParam("direction", "forward"); String edgesFmt = ctx.queryParam("edges", "*"); - Traversal traversal = new Traversal(graph, direction, edgesFmt); - ctx.json(traversal.visitNodesEndpoint(src)); + Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); + ctx.json(endpoint.visitNodes(src)); }); app.get("/visit/paths/:src", ctx -> { SwhId src = new SwhId(ctx.pathParam("src")); String direction = ctx.queryParam("direction", "forward"); String edgesFmt = ctx.queryParam("edges", "*"); - Traversal traversal = new Traversal(graph, direction, edgesFmt); - ctx.json(traversal.visitPathsEndpoint(src)); + Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); + ctx.json(endpoint.visitPaths(src)); }); app.get("/walk/:src/:dst", ctx -> { SwhId src = new SwhId(ctx.pathParam("src")); String dstFmt = ctx.pathParam("dst"); String direction = ctx.queryParam("direction", "forward"); String edgesFmt = ctx.queryParam("edges", "*"); String algorithm = ctx.queryParam("traversal", "dfs"); - Traversal traversal = new Traversal(graph, direction, edgesFmt); - ctx.json(traversal.walkEndpoint(src, dstFmt, algorithm)); + Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); + ctx.json(endpoint.walk(src, dstFmt, algorithm)); }); app.exception(IllegalArgumentException.class, (e, ctx) -> { ctx.status(400); ctx.result(e.getMessage()); }); } private static void checkQueryStrings(Context ctx, String allowedFmt) { Map> queryParamMap = ctx.queryParamMap(); for (String key : queryParamMap.keySet()) { if (!key.matches(allowedFmt)) { throw new IllegalArgumentException("Unknown query string: " + key); } } } } diff --git a/api/server/src/main/java/org/softwareheritage/graph/Endpoint.java b/api/server/src/main/java/org/softwareheritage/graph/Endpoint.java new file mode 100644 index 0000000..5742cad --- /dev/null +++ b/api/server/src/main/java/org/softwareheritage/graph/Endpoint.java @@ -0,0 +1,85 @@ +package org.softwareheritage.graph; + +import java.util.ArrayList; + +import org.softwareheritage.graph.Graph; +import org.softwareheritage.graph.SwhId; +import org.softwareheritage.graph.SwhPath; +import org.softwareheritage.graph.algo.Traversal; + +public class Endpoint { + Graph graph; + Traversal traversal; + + public Endpoint(Graph graph, String direction, String edgesFmt) { + this.graph = graph; + this.traversal = new Traversal(graph, direction, edgesFmt); + } + + private ArrayList convertNodesToSwhIds(ArrayList nodeIds) { + ArrayList swhIds = new ArrayList<>(); + for (long nodeId : nodeIds) { + swhIds.add(graph.getSwhId(nodeId)); + } + return swhIds; + } + + private SwhPath convertNodesToSwhPath(ArrayList nodeIds) { + SwhPath path = new SwhPath(); + for (long nodeId : nodeIds) { + path.add(graph.getSwhId(nodeId)); + } + return path; + } + + private ArrayList convertPathsToSwhIds(ArrayList> pathsNodeId) { + ArrayList paths = new ArrayList<>(); + for (ArrayList path : pathsNodeId) { + paths.add(convertNodesToSwhPath(path)); + } + return paths; + } + + public ArrayList leaves(SwhId src) { + long srcNodeId = graph.getNodeId(src); + ArrayList nodeIds = traversal.leaves(srcNodeId); + return convertNodesToSwhIds(nodeIds); + } + + public ArrayList neighbors(SwhId src) { + long srcNodeId = graph.getNodeId(src); + ArrayList nodeIds = traversal.neighbors(srcNodeId); + return convertNodesToSwhIds(nodeIds); + } + + public SwhPath walk(SwhId src, String dstFmt, String algorithm) { + long srcNodeId = graph.getNodeId(src); + ArrayList nodeIds = null; + + // Destination is either a SWH ID or a node type + try { + SwhId dstSwhId = new SwhId(dstFmt); + long dstNodeId = graph.getNodeId(dstSwhId); + nodeIds = traversal.walk(srcNodeId, dstNodeId, algorithm); + } catch (IllegalArgumentException ignored1) { + try { + Node.Type dstType = Node.Type.fromStr(dstFmt); + nodeIds = traversal.walk(srcNodeId, dstType, algorithm); + } catch (IllegalArgumentException ignored2) { } + } + + return convertNodesToSwhPath(nodeIds); + } + + public ArrayList visitNodes(SwhId src) { + long srcNodeId = graph.getNodeId(src); + ArrayList nodeIds = traversal.visitNodes(srcNodeId); + return convertNodesToSwhIds(nodeIds); + } + + public ArrayList visitPaths(SwhId src) { + long srcNodeId = graph.getNodeId(src); + ArrayList> paths = traversal.visitPaths(srcNodeId); + return convertPathsToSwhIds(paths); + } +} diff --git a/api/server/src/main/java/org/softwareheritage/graph/Neighbors.java b/api/server/src/main/java/org/softwareheritage/graph/Neighbors.java index 7fcf609..c31f430 100644 --- a/api/server/src/main/java/org/softwareheritage/graph/Neighbors.java +++ b/api/server/src/main/java/org/softwareheritage/graph/Neighbors.java @@ -1,60 +1,56 @@ package org.softwareheritage.graph; import java.util.Iterator; import it.unimi.dsi.fastutil.longs.LongBigArrays; import org.softwareheritage.graph.AllowedEdges; import org.softwareheritage.graph.Graph; -import org.softwareheritage.graph.SwhId; public class Neighbors implements Iterable { Graph graph; boolean useTransposed; AllowedEdges edges; - SwhId src; + long srcNodeId; - public Neighbors(Graph graph, boolean useTransposed, AllowedEdges edges, SwhId src) { + public Neighbors(Graph graph, boolean useTransposed, AllowedEdges edges, long srcNodeId) { this.graph = graph; this.useTransposed = useTransposed; this.edges = edges; - this.src = src; + this.srcNodeId = srcNodeId; } @Override public Iterator iterator() { return new NeighborsIterator(); } public class NeighborsIterator implements Iterator { long nextNeighborIdx; long nbNeighbors; long[][] neighbors; public NeighborsIterator() { - long srcNodeId = graph.getNodeId(src); - this.nextNeighborIdx = -1; this.nbNeighbors = graph.degree(srcNodeId, useTransposed); this.neighbors = graph.neighbors(srcNodeId, useTransposed); } // Look ahead because with edge restriction not all neighbors are considered public boolean hasNext() { for (long lookAheadIdx = nextNeighborIdx + 1; lookAheadIdx < nbNeighbors; lookAheadIdx++) { long nextNodeId = LongBigArrays.get(neighbors, lookAheadIdx); - SwhId nextSwhId = graph.getSwhId(nextNodeId); - if (edges.isAllowed(src.getType(), nextSwhId.getType())) { + if (edges.isAllowed(srcNodeId, nextNodeId)) { nextNeighborIdx = lookAheadIdx; return true; } } return false; } public Long next() { long nextNodeId = LongBigArrays.get(neighbors, nextNeighborIdx); return nextNodeId; } } } diff --git a/api/server/src/main/java/org/softwareheritage/graph/SwhPath.java b/api/server/src/main/java/org/softwareheritage/graph/SwhPath.java index e1927b2..be9c80b 100644 --- a/api/server/src/main/java/org/softwareheritage/graph/SwhPath.java +++ b/api/server/src/main/java/org/softwareheritage/graph/SwhPath.java @@ -1,81 +1,76 @@ package org.softwareheritage.graph; import java.util.ArrayList; -import java.util.Collections; import com.fasterxml.jackson.annotation.JsonValue; import org.softwareheritage.graph.SwhId; public class SwhPath { ArrayList path; public SwhPath() { this.path = new ArrayList(); } public SwhPath(String ...swhIds) { this(); for (String swhId : swhIds) { add(new SwhId(swhId)); } } public SwhPath(SwhId ...swhIds) { this(); for (SwhId swhId : swhIds) { add(swhId); } } @JsonValue public ArrayList getPath() { return path; } public void add(SwhId swhId) { path.add(swhId); } public SwhId get(int index) { return path.get(index); } public int size() { return path.size(); } - public void reverse() { - Collections.reverse(path); - } - @Override public boolean equals(Object otherObj) { if (otherObj == this) return true; if (!(otherObj instanceof SwhPath)) return false; SwhPath other = (SwhPath) otherObj; if (size() != other.size()) { return false; } for (int i = 0; i < size(); i++) { SwhId thisSwhId = get(i); SwhId otherSwhId = other.get(i); if (!thisSwhId.equals(otherSwhId)) { return false; } } return true; } @Override public String toString() { String str = new String(); for (SwhId swhId : path) { str += swhId + "/"; } return str; } } diff --git a/api/server/src/main/java/org/softwareheritage/graph/algo/Traversal.java b/api/server/src/main/java/org/softwareheritage/graph/algo/Traversal.java index 9e4b707..c9c2e04 100644 --- a/api/server/src/main/java/org/softwareheritage/graph/algo/Traversal.java +++ b/api/server/src/main/java/org/softwareheritage/graph/algo/Traversal.java @@ -1,254 +1,219 @@ package org.softwareheritage.graph.algo; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.Queue; import java.util.Stack; import it.unimi.dsi.bits.LongArrayBitVector; import it.unimi.dsi.fastutil.longs.LongBigArrays; import org.softwareheritage.graph.AllowedEdges; import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.Neighbors; import org.softwareheritage.graph.Node; -import org.softwareheritage.graph.SwhId; public class Traversal { Graph graph; boolean useTransposed; AllowedEdges edges; // Big array storing if we have visited a node LongArrayBitVector visited; // Big array storing parents to retrieve the path when backtracking long[][] nodeParent; public Traversal(Graph graph, String direction, String edgesFmt) { if (!direction.matches("forward|backward")) { throw new IllegalArgumentException("Unknown traversal direction: " + direction); } this.graph = graph; this.useTransposed = (direction.equals("backward")); - this.edges = new AllowedEdges(edgesFmt); + this.edges = new AllowedEdges(graph, edgesFmt); long nbNodes = graph.getNbNodes(); this.visited = LongArrayBitVector.ofLength(nbNodes); this.nodeParent = LongBigArrays.newBigArray(nbNodes); } - // TODO: better separation between internal/external ids (waiting on node types map to be merged) - private ArrayList convertToSwhIds(ArrayList nodeIds) { - ArrayList swhIds = new ArrayList(); - for (long nodeId : nodeIds) { - swhIds.add(graph.getSwhId(nodeId)); - } - return swhIds; - } - - public ArrayList leavesEndpoint(SwhId src) { - long nodeId = graph.getNodeId(src); - ArrayList leavesNodeIds = leavesInternalEndpoint(nodeId); - return convertToSwhIds(leavesNodeIds); - } - - public ArrayList neighborsEndpoint(SwhId src) { - long nodeId = graph.getNodeId(src); - ArrayList neighborsNodeIds = neighborsInternalEndpoint(nodeId); - return convertToSwhIds(neighborsNodeIds); - } - - public ArrayList walkEndpoint(SwhId src, String dstFmt, String traversal) { - if (!traversal.matches("dfs|bfs")) { - throw new IllegalArgumentException("Unknown traversal algorithm: " + traversal); - } - - long srcNodeId = graph.getNodeId(src); - long dstNodeId = (traversal.equals("dfs")) ? dfs(srcNodeId, dstFmt) : bfs(srcNodeId, dstFmt); - if (dstNodeId == -1) { - throw new IllegalArgumentException("Unable to find destination point: " + dstFmt); - } - - ArrayList path = backtracking(srcNodeId, dstNodeId); - return convertToSwhIds(path); - } - - public ArrayList visitNodesEndpoint(SwhId src) { - long nodeId = graph.getNodeId(src); - ArrayList nodes = visitNodesInternalEndpoint(nodeId); - return convertToSwhIds(nodes); - } - - public ArrayList> visitPathsEndpoint(SwhId src) { - long nodeId = graph.getNodeId(src); - ArrayList> pathNodeIds = new ArrayList<>(); - Stack currentPath = new Stack(); - visitPathsInternalEndpoint(nodeId, pathNodeIds, currentPath); - - ArrayList> paths = new ArrayList<>(); - for (ArrayList nodeIds : pathNodeIds) { - paths.add(convertToSwhIds(nodeIds)); - } - return paths; - } - - private ArrayList leavesInternalEndpoint(long srcNodeId) { - ArrayList leaves = new ArrayList(); + public ArrayList leaves(long srcNodeId) { + ArrayList nodeIds = new ArrayList(); Stack stack = new Stack(); - this.visited.clear(); + this.visited.fill(false); stack.push(srcNodeId); visited.set(srcNodeId); while (!stack.isEmpty()) { long currentNodeId = stack.pop(); - SwhId currentSwhId = graph.getSwhId(currentNodeId); long neighborsCnt = 0; - for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentSwhId)) { + for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentNodeId)) { neighborsCnt++; if (!visited.getBoolean(neighborNodeId)) { stack.push(neighborNodeId); visited.set(neighborNodeId); } } if (neighborsCnt == 0) { - leaves.add(currentNodeId); + nodeIds.add(currentNodeId); } } - return leaves; + return nodeIds; } - private ArrayList neighborsInternalEndpoint(long srcNodeId) { - SwhId srcSwhId = graph.getSwhId(srcNodeId); - ArrayList neighbors = new ArrayList(); - for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, srcSwhId)) { - neighbors.add(neighborNodeId); + public ArrayList neighbors(long srcNodeId) { + ArrayList nodeIds = new ArrayList(); + for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, srcNodeId)) { + nodeIds.add(neighborNodeId); } - return neighbors; + return nodeIds; } - private ArrayList visitNodesInternalEndpoint(long srcNodeId) { - // No specific destination point - String dstFmt = null; - dfs(srcNodeId, dstFmt); + public ArrayList visitNodes(long srcNodeId) { + ArrayList nodeIds = new ArrayList(); + Stack stack = new Stack(); + this.visited.fill(false); + + stack.push(srcNodeId); + visited.set(srcNodeId); + + while (!stack.isEmpty()) { + long currentNodeId = stack.pop(); + nodeIds.add(currentNodeId); - ArrayList nodes = new ArrayList(); - for (long nodeId = 0; nodeId < graph.getNbNodes(); nodeId++) { - if (this.visited.getBoolean(nodeId)) { - nodes.add(nodeId); + for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentNodeId)) { + if (!visited.getBoolean(neighborNodeId)) { + stack.push(neighborNodeId); + visited.set(neighborNodeId); + } } } - return nodes; + + return nodeIds; + } + + public ArrayList> visitPaths(long srcNodeId) { + ArrayList> paths = new ArrayList<>(); + Stack currentPath = new Stack(); + visitPathsInternal(srcNodeId, paths, currentPath); + return paths; } - private void visitPathsInternalEndpoint( + private void visitPathsInternal( long currentNodeId, ArrayList> paths, Stack currentPath) { - SwhId currentSwhId = graph.getSwhId(currentNodeId); currentPath.push(currentNodeId); long visitedNeighbors = 0; - for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentSwhId)) { - visitPathsInternalEndpoint(neighborNodeId, paths, currentPath); + for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentNodeId)) { + visitPathsInternal(neighborNodeId, paths, currentPath); visitedNeighbors++; } if (visitedNeighbors == 0) { ArrayList path = new ArrayList(); for (long nodeId : currentPath) { path.add(nodeId); } paths.add(path); } currentPath.pop(); } - private ArrayList backtracking(long srcNodeId, long dstNodeId) { - ArrayList path = new ArrayList(); - long currentNodeId = dstNodeId; - while (currentNodeId != srcNodeId) { - path.add(currentNodeId); - currentNodeId = LongBigArrays.get(nodeParent, currentNodeId); + public ArrayList walk(long srcNodeId, T dst, String algorithm) { + long dstNodeId = -1; + if (algorithm.equals("dfs")) { + dstNodeId = walkInternalDfs(srcNodeId, dst); + } else if (algorithm.equals("bfs")) { + dstNodeId = walkInternalBfs(srcNodeId, dst); + } else { + throw new IllegalArgumentException("Unknown traversal algorithm: " + algorithm); } - path.add(srcNodeId); - Collections.reverse(path); - return path; + + if (dstNodeId == -1) { + throw new IllegalArgumentException("Unable to find destination point: " + dst); + } + + ArrayList nodeIds = backtracking(srcNodeId, dstNodeId); + return nodeIds; } - private long dfs(long srcNodeId, String dstFmt) { + private long walkInternalDfs(long srcNodeId, T dst) { Stack stack = new Stack(); - this.visited.clear(); + this.visited.fill(false); stack.push(srcNodeId); visited.set(srcNodeId); while (!stack.isEmpty()) { long currentNodeId = stack.pop(); - SwhId currentSwhId = graph.getSwhId(currentNodeId); - if (isDestinationNode(currentSwhId, dstFmt)) { + if (isDstNode(currentNodeId, dst)) { return currentNodeId; } - for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentSwhId)) { + for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentNodeId)) { if (!visited.getBoolean(neighborNodeId)) { stack.push(neighborNodeId); visited.set(neighborNodeId); LongBigArrays.set(nodeParent, neighborNodeId, currentNodeId); } } } return -1; } - private long bfs(long srcNodeId, String dstFmt) { + private long walkInternalBfs(long srcNodeId, T dst) { Queue queue = new LinkedList(); - this.visited.clear(); + this.visited.fill(false); queue.add(srcNodeId); visited.set(srcNodeId); while (!queue.isEmpty()) { long currentNodeId = queue.poll(); - SwhId currentSwhId = graph.getSwhId(currentNodeId); - if (isDestinationNode(currentSwhId, dstFmt)) { + if (isDstNode(currentNodeId, dst)) { return currentNodeId; } - for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentSwhId)) { + for (long neighborNodeId : new Neighbors(graph, useTransposed, edges, currentNodeId)) { if (!visited.getBoolean(neighborNodeId)) { queue.add(neighborNodeId); visited.set(neighborNodeId); LongBigArrays.set(nodeParent, neighborNodeId, currentNodeId); } } } return -1; } - private boolean isDestinationNode(SwhId swhId, String dstFmt) { - // No destination node, early exit - if (dstFmt == null) { + private boolean isDstNode(long nodeId, T dst) { + if (dst instanceof Long) { + long dstNodeId = (Long) dst; + return nodeId == dstNodeId; + } else if (dst instanceof Node.Type) { + Node.Type dstType = (Node.Type) dst; + return graph.getNodeType(nodeId) == dstType; + } else { return false; } + } - // SwhId as destination node - if (swhId.toString().equals(dstFmt)) { - return true; - } - - // Node.Type as destination node - try { - Node.Type dstType = Node.Type.fromStr(dstFmt); - return (swhId.getType().equals(dstType)); - } catch (IllegalArgumentException e) { - return false; + private ArrayList backtracking(long srcNodeId, long dstNodeId) { + ArrayList path = new ArrayList(); + long currentNodeId = dstNodeId; + while (currentNodeId != srcNodeId) { + path.add(currentNodeId); + currentNodeId = LongBigArrays.get(nodeParent, currentNodeId); } + path.add(srcNodeId); + Collections.reverse(path); + return path; } } diff --git a/api/server/src/main/java/org/softwareheritage/graph/backend/Setup.java b/api/server/src/main/java/org/softwareheritage/graph/backend/Setup.java index dfcc30f..3ef285f 100644 --- a/api/server/src/main/java/org/softwareheritage/graph/backend/Setup.java +++ b/api/server/src/main/java/org/softwareheritage/graph/backend/Setup.java @@ -1,106 +1,106 @@ package org.softwareheritage.graph.backend; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Writer; import java.util.zip.GZIPInputStream; import it.unimi.dsi.bits.LongArrayBitVector; import it.unimi.dsi.fastutil.Size64; import it.unimi.dsi.fastutil.io.BinIO; import it.unimi.dsi.fastutil.longs.LongBigArrays; import it.unimi.dsi.fastutil.longs.LongBigList; import it.unimi.dsi.fastutil.objects.Object2LongFunction; import it.unimi.dsi.fastutil.objects.ObjectBigArrays; import it.unimi.dsi.io.FastBufferedReader; import it.unimi.dsi.io.LineIterator; import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.Node; import org.softwareheritage.graph.SwhId; import org.softwareheritage.graph.backend.NodeTypesMap; public class Setup { public static void main(String[] args) throws IOException { if (args.length != 2) { System.err.println("Expected parameters: "); System.exit(1); } String nodesPath = args[0]; String graphPath = args[1]; System.out.println("Pre-computing node id maps..."); long startTime = System.nanoTime(); precomputeNodeIdMap(nodesPath, graphPath); long endTime = System.nanoTime(); double duration = (double) (endTime - startTime) / 1_000_000_000; System.out.println("Done in: " + duration + " seconds"); } // Suppress warning for Object2LongFunction cast @SuppressWarnings("unchecked") static void precomputeNodeIdMap(String nodesPath, String graphPath) throws IOException { // First internal mapping: SWH id (string) -> WebGraph MPH (long) Object2LongFunction mphMap = null; try { mphMap = (Object2LongFunction) BinIO.loadObject(graphPath + ".mph"); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("The .mph file contains unknown class object: " + e); } long nbIds = (mphMap instanceof Size64) ? ((Size64) mphMap).size64() : mphMap.size(); // Second internal mapping: WebGraph MPH (long) -> BFS ordering (long) long[][] bfsMap = LongBigArrays.newBigArray(nbIds); long loaded = BinIO.loadLongs(graphPath + ".order", bfsMap); if (loaded != nbIds) { throw new IllegalArgumentException("Graph contains " + nbIds + " nodes, but read " + loaded); } // Dump complete mapping for all nodes: SWH id (string) <=> WebGraph node id (long) InputStream nodesStream = new GZIPInputStream(new FileInputStream(nodesPath)); FastBufferedReader buffer = new FastBufferedReader(new InputStreamReader(nodesStream, "UTF-8")); LineIterator swhIdIterator = new LineIterator(buffer); - try ( - Writer swhToNodeMap = new BufferedWriter(new FileWriter(graphPath + Graph.PID_TO_NODE)); - Writer nodeToSwhMap = new BufferedWriter(new FileWriter(graphPath + Graph.NODE_TO_PID))) { + try (Writer swhToNodeMap = new BufferedWriter(new FileWriter(graphPath + Graph.PID_TO_NODE)); + Writer nodeToSwhMap = new BufferedWriter(new FileWriter(graphPath + Graph.NODE_TO_PID))) { // nodeToSwhMap needs to write SWH id in order of node id, so use a temporary array Object[][] nodeToSwhId = ObjectBigArrays.newBigArray(nbIds); // To effectively run edge restriction during graph traversals, we store node id (long) -> SWH // type map. This is represented as a bitmap using minimum number of bits per Node.Type. final int log2NbTypes = (int) Math.ceil(Math.log(Node.Type.values().length) / Math.log(2)); final int nbBitsPerNodeType = log2NbTypes; - LongArrayBitVector nodeTypesBitVector = LongArrayBitVector.ofLength(nbBitsPerNodeType * nbIds); + LongArrayBitVector nodeTypesBitVector = + LongArrayBitVector.ofLength(nbBitsPerNodeType * nbIds); LongBigList nodeTypesMap = nodeTypesBitVector.asLongBigList(nbBitsPerNodeType); for (long iNode = 0; iNode < nbIds && swhIdIterator.hasNext(); iNode++) { String strSwhId = swhIdIterator.next().toString(); long mphId = mphMap.getLong(strSwhId); long nodeId = LongBigArrays.get(bfsMap, mphId); String paddedNodeId = String.format("%0" + NodeIdMap.NODE_ID_LENGTH + "d", nodeId); String line = strSwhId + " " + paddedNodeId + "\n"; swhToNodeMap.write(line); ObjectBigArrays.set(nodeToSwhId, nodeId, strSwhId); SwhId swhId = new SwhId(strSwhId); nodeTypesMap.set(nodeId, swhId.getType().ordinal()); } BinIO.storeObject(nodeTypesMap, graphPath + Graph.NODE_TO_TYPE); for (long iNode = 0; iNode < nbIds; iNode++) { String line = ObjectBigArrays.get(nodeToSwhId, iNode).toString() + "\n"; nodeToSwhMap.write(line); } } } } diff --git a/api/server/src/main/java/org/softwareheritage/graph/benchmark/LinuxLog.java b/api/server/src/main/java/org/softwareheritage/graph/benchmark/LinuxLog.java index 32d4d82..f6e9eae 100644 --- a/api/server/src/main/java/org/softwareheritage/graph/benchmark/LinuxLog.java +++ b/api/server/src/main/java/org/softwareheritage/graph/benchmark/LinuxLog.java @@ -1,31 +1,31 @@ package org.softwareheritage.graph.benchmark; import java.io.IOException; +import org.softwareheritage.graph.Endpoint; import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.SwhId; -import org.softwareheritage.graph.algo.Traversal; public class LinuxLog { public static void main(String[] args) throws IOException { String path = args[0]; Graph graph = new Graph(path); // A linux kernel commit on Sun Dec 31 final SwhId commit = new SwhId("swh:1:rev:f39d7d78b70e0f39facb1e4fab77ad3df5c52a35"); final long expectedCount = 723640; System.out.println("git log " + commit); System.out.println("Expecting " + expectedCount + " commits"); long startTime = System.nanoTime(); - Traversal traversal = new Traversal(graph, "forward", "rev:rev"); - long count = traversal.visitNodesEndpoint(commit).size(); + Endpoint endpoint = new Endpoint(graph, "forward", "rev:rev"); + long count = endpoint.visitNodes(commit).size(); if (count != expectedCount) { throw new IllegalArgumentException("Counted " + count + " commits"); } long endTime = System.nanoTime(); double duration = (double) (endTime - startTime) / 1_000_000_000; System.out.println("Visit operation done in: " + duration + " seconds"); } } diff --git a/api/server/src/test/java/org/softwareheritage/graph/AllowedEdgesTest.java b/api/server/src/test/java/org/softwareheritage/graph/AllowedEdgesTest.java index 1c68ae8..02e0642 100644 --- a/api/server/src/test/java/org/softwareheritage/graph/AllowedEdgesTest.java +++ b/api/server/src/test/java/org/softwareheritage/graph/AllowedEdgesTest.java @@ -1,112 +1,119 @@ package org.softwareheritage.graph; import java.util.ArrayList; import org.junit.Test; import static org.junit.Assert.assertTrue; import org.softwareheritage.graph.AllowedEdges; +import org.softwareheritage.graph.GraphTest; import org.softwareheritage.graph.Node; -public class AllowedEdgesTest { +public class AllowedEdgesTest extends GraphTest { class EdgeType { Node.Type src; Node.Type dst; public EdgeType(Node.Type src, Node.Type dst) { this.src = src; this.dst = dst; } @Override public boolean equals(Object otherObj) { if (otherObj == this) return true; if (!(otherObj instanceof EdgeType)) return false; EdgeType other = (EdgeType) otherObj; return src == other.src && dst == other.dst; } } void assertEdgeRestriction(AllowedEdges edges, ArrayList expectedAllowed) { Node.Type[] nodeTypes = Node.Type.values(); for (Node.Type src : nodeTypes) { for (Node.Type dst : nodeTypes) { EdgeType edge = new EdgeType(src, dst); boolean isAllowed = edges.isAllowed(src, dst); boolean isExpected = false; for (EdgeType expected : expectedAllowed) { if (expected.equals(edge)) { isExpected = true; break; } } assertTrue("Edge type: " + src + " -> " + dst, isAllowed == isExpected); } } } @Test public void dirToDirDirToCntEdges() { - AllowedEdges edges = new AllowedEdges("dir:dir,dir:cnt"); + Graph graph = getGraph(); + AllowedEdges edges = new AllowedEdges(graph, "dir:dir,dir:cnt"); ArrayList expected = new ArrayList<>(); expected.add(new EdgeType(Node.Type.DIR, Node.Type.DIR)); expected.add(new EdgeType(Node.Type.DIR, Node.Type.CNT)); assertEdgeRestriction(edges, expected); } @Test public void relToRevRevToRevRevToDirEdges() { - AllowedEdges edges = new AllowedEdges("rel:rev,rev:rev,rev:dir"); + Graph graph = getGraph(); + AllowedEdges edges = new AllowedEdges(graph, "rel:rev,rev:rev,rev:dir"); ArrayList expected = new ArrayList<>(); expected.add(new EdgeType(Node.Type.REL, Node.Type.REV)); expected.add(new EdgeType(Node.Type.REV, Node.Type.REV)); expected.add(new EdgeType(Node.Type.REV, Node.Type.DIR)); assertEdgeRestriction(edges, expected); } @Test public void revToAllDirToDirEdges() { - AllowedEdges edges = new AllowedEdges("rev:*,dir:dir"); + Graph graph = getGraph(); + AllowedEdges edges = new AllowedEdges(graph, "rev:*,dir:dir"); ArrayList expected = new ArrayList<>(); for (Node.Type dst : Node.Type.values()) { expected.add(new EdgeType(Node.Type.REV, dst)); } expected.add(new EdgeType(Node.Type.DIR, Node.Type.DIR)); assertEdgeRestriction(edges, expected); } @Test public void allToCntEdges() { - AllowedEdges edges = new AllowedEdges("*:cnt"); + Graph graph = getGraph(); + AllowedEdges edges = new AllowedEdges(graph, "*:cnt"); ArrayList expected = new ArrayList<>(); for (Node.Type src : Node.Type.values()) { expected.add(new EdgeType(src, Node.Type.CNT)); } assertEdgeRestriction(edges, expected); } @Test public void allEdges() { - AllowedEdges edges = new AllowedEdges("*:*"); - AllowedEdges edges2 = new AllowedEdges("*"); + Graph graph = getGraph(); + AllowedEdges edges = new AllowedEdges(graph, "*:*"); + AllowedEdges edges2 = new AllowedEdges(graph, "*"); ArrayList expected = new ArrayList<>(); for (Node.Type src : Node.Type.values()) { for (Node.Type dst : Node.Type.values()) { expected.add(new EdgeType(src, dst)); } } assertEdgeRestriction(edges, expected); assertEdgeRestriction(edges2, expected); } @Test public void noEdges() { - AllowedEdges edges = new AllowedEdges(""); - AllowedEdges edges2 = new AllowedEdges(null); + Graph graph = getGraph(); + AllowedEdges edges = new AllowedEdges(graph, ""); + AllowedEdges edges2 = new AllowedEdges(graph, null); ArrayList expected = new ArrayList<>(); assertEdgeRestriction(edges, expected); assertEdgeRestriction(edges2, expected); } } diff --git a/api/server/src/test/java/org/softwareheritage/graph/LeavesTest.java b/api/server/src/test/java/org/softwareheritage/graph/LeavesTest.java index 574866e..53f68f9 100644 --- a/api/server/src/test/java/org/softwareheritage/graph/LeavesTest.java +++ b/api/server/src/test/java/org/softwareheritage/graph/LeavesTest.java @@ -1,101 +1,101 @@ package org.softwareheritage.graph; import java.util.ArrayList; import org.junit.Test; +import org.softwareheritage.graph.Endpoint; import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.GraphTest; import org.softwareheritage.graph.SwhId; -import org.softwareheritage.graph.algo.Traversal; public class LeavesTest extends GraphTest { @Test public void forwardFromSnp() { Graph graph = getGraph(); SwhId src = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal = new Traversal(graph, "forward", "*"); + Endpoint endpoint = new Endpoint(graph, "forward", "*"); ArrayList expectedLeaves = new ArrayList<>(); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000001")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000004")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000005")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000007")); - assertEquals(expectedLeaves, traversal.leavesEndpoint(src)); + GraphTest.assertEqualsAnyOrder(expectedLeaves, endpoint.leaves(src)); } @Test public void forwardFromRel() { Graph graph = getGraph(); SwhId src = new SwhId("swh:1:rel:0000000000000000000000000000000000000019"); - Traversal traversal = new Traversal(graph, "forward", "*"); + Endpoint endpoint = new Endpoint(graph, "forward", "*"); ArrayList expectedLeaves = new ArrayList<>(); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000015")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000014")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000001")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000004")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000005")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000007")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000011")); - assertEquals(expectedLeaves, traversal.leavesEndpoint(src)); + GraphTest.assertEqualsAnyOrder(expectedLeaves, endpoint.leaves(src)); } @Test public void backwardFromLeaf() { Graph graph = getGraph(); - Traversal traversal = new Traversal(graph, "backward", "*"); + Endpoint endpoint = new Endpoint(graph, "backward", "*"); SwhId src1 = new SwhId("swh:1:cnt:0000000000000000000000000000000000000015"); ArrayList expectedLeaves1 = new ArrayList<>(); expectedLeaves1.add(new SwhId("swh:1:rel:0000000000000000000000000000000000000019")); - assertEquals(expectedLeaves1, traversal.leavesEndpoint(src1)); + GraphTest.assertEqualsAnyOrder(expectedLeaves1, endpoint.leaves(src1)); SwhId src2 = new SwhId("swh:1:cnt:0000000000000000000000000000000000000004"); ArrayList expectedLeaves2 = new ArrayList<>(); expectedLeaves2.add(new SwhId("swh:1:snp:0000000000000000000000000000000000000020")); expectedLeaves2.add(new SwhId("swh:1:rel:0000000000000000000000000000000000000019")); - assertEquals(expectedLeaves2, traversal.leavesEndpoint(src2)); + GraphTest.assertEqualsAnyOrder(expectedLeaves2, endpoint.leaves(src2)); } @Test public void forwardRevToRevOnly() { Graph graph = getGraph(); SwhId src = new SwhId("swh:1:rev:0000000000000000000000000000000000000018"); - Traversal traversal = new Traversal(graph, "forward", "rev:rev"); + Endpoint endpoint = new Endpoint(graph, "forward", "rev:rev"); ArrayList expectedLeaves = new ArrayList<>(); expectedLeaves.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000003")); - assertEquals(expectedLeaves, traversal.leavesEndpoint(src)); + GraphTest.assertEqualsAnyOrder(expectedLeaves, endpoint.leaves(src)); } @Test public void forwardDirToAll() { Graph graph = getGraph(); SwhId src = new SwhId("swh:1:dir:0000000000000000000000000000000000000008"); - Traversal traversal = new Traversal(graph, "forward", "dir:*"); + Endpoint endpoint = new Endpoint(graph, "forward", "dir:*"); ArrayList expectedLeaves = new ArrayList<>(); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000004")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000005")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000001")); expectedLeaves.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000007")); - assertEquals(expectedLeaves, traversal.leavesEndpoint(src)); + GraphTest.assertEqualsAnyOrder(expectedLeaves, endpoint.leaves(src)); } @Test public void backwardCntToDirDirToDir() { Graph graph = getGraph(); SwhId src = new SwhId("swh:1:cnt:0000000000000000000000000000000000000005"); - Traversal traversal = new Traversal(graph, "backward", "cnt:dir,dir:dir"); + Endpoint endpoint = new Endpoint(graph, "backward", "cnt:dir,dir:dir"); ArrayList expectedLeaves = new ArrayList<>(); expectedLeaves.add(new SwhId("swh:1:dir:0000000000000000000000000000000000000012")); - assertEquals(expectedLeaves, traversal.leavesEndpoint(src)); + GraphTest.assertEqualsAnyOrder(expectedLeaves, endpoint.leaves(src)); } } diff --git a/api/server/src/test/java/org/softwareheritage/graph/NeighborsTest.java b/api/server/src/test/java/org/softwareheritage/graph/NeighborsTest.java index 568a047..9fec292 100644 --- a/api/server/src/test/java/org/softwareheritage/graph/NeighborsTest.java +++ b/api/server/src/test/java/org/softwareheritage/graph/NeighborsTest.java @@ -1,121 +1,121 @@ package org.softwareheritage.graph; import java.util.ArrayList; import org.junit.Test; +import org.softwareheritage.graph.Endpoint; import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.GraphTest; import org.softwareheritage.graph.SwhId; -import org.softwareheritage.graph.algo.Traversal; public class NeighborsTest extends GraphTest { @Test public void zeroNeighbor() { Graph graph = getGraph(); ArrayList expectedNodes = new ArrayList<>(); SwhId src1 = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal1 = new Traversal(graph, "backward", "*"); - GraphTest.assertEqualsAnyOrder(expectedNodes, traversal1.neighborsEndpoint(src1)); + Endpoint endpoint1 = new Endpoint(graph, "backward", "*"); + GraphTest.assertEqualsAnyOrder(expectedNodes, endpoint1.neighbors(src1)); SwhId src2 = new SwhId("swh:1:cnt:0000000000000000000000000000000000000004"); - Traversal traversal2 = new Traversal(graph, "forward", "*"); - GraphTest.assertEqualsAnyOrder(expectedNodes, traversal2.neighborsEndpoint(src2)); + Endpoint endpoint2 = new Endpoint(graph, "forward", "*"); + GraphTest.assertEqualsAnyOrder(expectedNodes, endpoint2.neighbors(src2)); SwhId src3 = new SwhId("swh:1:cnt:0000000000000000000000000000000000000015"); - Traversal traversal3 = new Traversal(graph, "forward", "*"); - GraphTest.assertEqualsAnyOrder(expectedNodes, traversal3.neighborsEndpoint(src3)); + Endpoint endpoint3 = new Endpoint(graph, "forward", "*"); + GraphTest.assertEqualsAnyOrder(expectedNodes, endpoint3.neighbors(src3)); SwhId src4 = new SwhId("swh:1:rel:0000000000000000000000000000000000000019"); - Traversal traversal4 = new Traversal(graph, "backward", "*"); - GraphTest.assertEqualsAnyOrder(expectedNodes, traversal4.neighborsEndpoint(src4)); + Endpoint endpoint4 = new Endpoint(graph, "backward", "*"); + GraphTest.assertEqualsAnyOrder(expectedNodes, endpoint4.neighbors(src4)); SwhId src5 = new SwhId("swh:1:dir:0000000000000000000000000000000000000008"); - Traversal traversal5 = new Traversal(graph, "forward", "snp:*,rev:*,rel:*"); - GraphTest.assertEqualsAnyOrder(expectedNodes, traversal5.neighborsEndpoint(src5)); + Endpoint endpoint5 = new Endpoint(graph, "forward", "snp:*,rev:*,rel:*"); + GraphTest.assertEqualsAnyOrder(expectedNodes, endpoint5.neighbors(src5)); } @Test public void oneNeighbor() { Graph graph = getGraph(); SwhId src1 = new SwhId("swh:1:rev:0000000000000000000000000000000000000003"); - Traversal traversal1 = new Traversal(graph, "forward", "*"); + Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); ArrayList expectedNodes1 = new ArrayList<>(); expectedNodes1.add(new SwhId("swh:1:dir:0000000000000000000000000000000000000002")); - GraphTest.assertEqualsAnyOrder(expectedNodes1, traversal1.neighborsEndpoint(src1)); + GraphTest.assertEqualsAnyOrder(expectedNodes1, endpoint1.neighbors(src1)); SwhId src2 = new SwhId("swh:1:dir:0000000000000000000000000000000000000017"); - Traversal traversal2 = new Traversal(graph, "forward", "dir:cnt"); + Endpoint endpoint2 = new Endpoint(graph, "forward", "dir:cnt"); ArrayList expectedNodes2 = new ArrayList<>(); expectedNodes2.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000014")); - GraphTest.assertEqualsAnyOrder(expectedNodes2, traversal2.neighborsEndpoint(src2)); + GraphTest.assertEqualsAnyOrder(expectedNodes2, endpoint2.neighbors(src2)); SwhId src3 = new SwhId("swh:1:dir:0000000000000000000000000000000000000012"); - Traversal traversal3 = new Traversal(graph, "backward", "*"); + Endpoint endpoint3 = new Endpoint(graph, "backward", "*"); ArrayList expectedNodes3 = new ArrayList<>(); expectedNodes3.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000013")); - GraphTest.assertEqualsAnyOrder(expectedNodes3, traversal3.neighborsEndpoint(src3)); + GraphTest.assertEqualsAnyOrder(expectedNodes3, endpoint3.neighbors(src3)); SwhId src4 = new SwhId("swh:1:rev:0000000000000000000000000000000000000009"); - Traversal traversal4 = new Traversal(graph, "backward", "rev:rev"); + Endpoint endpoint4 = new Endpoint(graph, "backward", "rev:rev"); ArrayList expectedNodes4 = new ArrayList<>(); expectedNodes4.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000013")); - GraphTest.assertEqualsAnyOrder(expectedNodes4, traversal4.neighborsEndpoint(src4)); + GraphTest.assertEqualsAnyOrder(expectedNodes4, endpoint4.neighbors(src4)); } @Test public void twoNeighbors() { Graph graph = getGraph(); SwhId src1 = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal1 = new Traversal(graph, "forward", "*"); + Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); ArrayList expectedNodes1 = new ArrayList<>(); expectedNodes1.add(new SwhId("swh:1:rel:0000000000000000000000000000000000000010")); expectedNodes1.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000009")); - GraphTest.assertEqualsAnyOrder(expectedNodes1, traversal1.neighborsEndpoint(src1)); + GraphTest.assertEqualsAnyOrder(expectedNodes1, endpoint1.neighbors(src1)); SwhId src2 = new SwhId("swh:1:dir:0000000000000000000000000000000000000008"); - Traversal traversal2 = new Traversal(graph, "forward", "dir:cnt"); + Endpoint endpoint2 = new Endpoint(graph, "forward", "dir:cnt"); ArrayList expectedNodes2 = new ArrayList<>(); expectedNodes2.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000001")); expectedNodes2.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000007")); - GraphTest.assertEqualsAnyOrder(expectedNodes2, traversal2.neighborsEndpoint(src2)); + GraphTest.assertEqualsAnyOrder(expectedNodes2, endpoint2.neighbors(src2)); SwhId src3 = new SwhId("swh:1:cnt:0000000000000000000000000000000000000001"); - Traversal traversal3 = new Traversal(graph, "backward", "*"); + Endpoint endpoint3 = new Endpoint(graph, "backward", "*"); ArrayList expectedNodes3 = new ArrayList<>(); expectedNodes3.add(new SwhId("swh:1:dir:0000000000000000000000000000000000000008")); expectedNodes3.add(new SwhId("swh:1:dir:0000000000000000000000000000000000000002")); - GraphTest.assertEqualsAnyOrder(expectedNodes3, traversal3.neighborsEndpoint(src3)); + GraphTest.assertEqualsAnyOrder(expectedNodes3, endpoint3.neighbors(src3)); SwhId src4 = new SwhId("swh:1:rev:0000000000000000000000000000000000000009"); - Traversal traversal4 = new Traversal(graph, "backward", "rev:snp,rev:rel"); + Endpoint endpoint4 = new Endpoint(graph, "backward", "rev:snp,rev:rel"); ArrayList expectedNodes4 = new ArrayList<>(); expectedNodes4.add(new SwhId("swh:1:snp:0000000000000000000000000000000000000020")); expectedNodes4.add(new SwhId("swh:1:rel:0000000000000000000000000000000000000010")); - GraphTest.assertEqualsAnyOrder(expectedNodes4, traversal4.neighborsEndpoint(src4)); + GraphTest.assertEqualsAnyOrder(expectedNodes4, endpoint4.neighbors(src4)); } @Test public void threeNeighbors() { Graph graph = getGraph(); SwhId src1 = new SwhId("swh:1:dir:0000000000000000000000000000000000000008"); - Traversal traversal1 = new Traversal(graph, "forward", "*"); + Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); ArrayList expectedNodes1 = new ArrayList<>(); expectedNodes1.add(new SwhId("swh:1:dir:0000000000000000000000000000000000000006")); expectedNodes1.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000001")); expectedNodes1.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000007")); - GraphTest.assertEqualsAnyOrder(expectedNodes1, traversal1.neighborsEndpoint(src1)); + GraphTest.assertEqualsAnyOrder(expectedNodes1, endpoint1.neighbors(src1)); SwhId src2 = new SwhId("swh:1:rev:0000000000000000000000000000000000000009"); - Traversal traversal2 = new Traversal(graph, "backward", "*"); + Endpoint endpoint2 = new Endpoint(graph, "backward", "*"); ArrayList expectedNodes2 = new ArrayList<>(); expectedNodes2.add(new SwhId("swh:1:snp:0000000000000000000000000000000000000020")); expectedNodes2.add(new SwhId("swh:1:rel:0000000000000000000000000000000000000010")); expectedNodes2.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000013")); - GraphTest.assertEqualsAnyOrder(expectedNodes2, traversal2.neighborsEndpoint(src2)); + GraphTest.assertEqualsAnyOrder(expectedNodes2, endpoint2.neighbors(src2)); } } diff --git a/api/server/src/test/java/org/softwareheritage/graph/VisitTest.java b/api/server/src/test/java/org/softwareheritage/graph/VisitTest.java index 4f2336d..2f9a731 100644 --- a/api/server/src/test/java/org/softwareheritage/graph/VisitTest.java +++ b/api/server/src/test/java/org/softwareheritage/graph/VisitTest.java @@ -1,519 +1,520 @@ package org.softwareheritage.graph; import java.util.ArrayList; -import java.util.LinkedHashSet; +import java.util.Set; +import java.util.HashSet; import org.junit.Test; +import org.softwareheritage.graph.Endpoint; import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.GraphTest; import org.softwareheritage.graph.SwhId; import org.softwareheritage.graph.SwhPath; -import org.softwareheritage.graph.algo.Traversal; public class VisitTest extends GraphTest { - private void assertSameNodesFromPaths(ArrayList paths, LinkedHashSet nodes) { - LinkedHashSet expectedNodes = new LinkedHashSet(); + private void assertSameNodesFromPaths(ArrayList paths, ArrayList nodes) { + Set expectedNodes = new HashSet(); for (SwhPath path : paths) { for (SwhId node : path.getPath()) { expectedNodes.add(node); } } GraphTest.assertEqualsAnyOrder(expectedNodes, nodes); } @Test public void forwardFromRoot() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal = new Traversal(graph, "forward", "*"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", "*"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000007" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000001" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000004" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000005" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000003", "swh:1:dir:0000000000000000000000000000000000000002", "swh:1:cnt:0000000000000000000000000000000000000001" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rel:0000000000000000000000000000000000000010", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000007" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rel:0000000000000000000000000000000000000010", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000001" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rel:0000000000000000000000000000000000000010", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000004" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rel:0000000000000000000000000000000000000010", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000005" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rel:0000000000000000000000000000000000000010", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000003", "swh:1:dir:0000000000000000000000000000000000000002", "swh:1:cnt:0000000000000000000000000000000000000001" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void forwardFromMiddle() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:dir:0000000000000000000000000000000000000012"); - Traversal traversal = new Traversal(graph, "forward", "*"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", "*"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000007" )); expectedPaths.add( new SwhPath( "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000001" )); expectedPaths.add( new SwhPath( "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000004" )); expectedPaths.add( new SwhPath( "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000005" )); expectedPaths.add( new SwhPath( "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:cnt:0000000000000000000000000000000000000011" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void forwardFromLeaf() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:cnt:0000000000000000000000000000000000000004"); - Traversal traversal = new Traversal(graph, "forward", "*"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", "*"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:cnt:0000000000000000000000000000000000000004" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void backwardFromRoot() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal = new Traversal(graph, "backward", "*"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "backward", "*"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void backwardFromMiddle() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:dir:0000000000000000000000000000000000000012"); - Traversal traversal = new Traversal(graph, "backward", "*"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "backward", "*"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000018", "swh:1:rel:0000000000000000000000000000000000000019" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void backwardFromLeaf() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:cnt:0000000000000000000000000000000000000004"); - Traversal traversal = new Traversal(graph, "backward", "*"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "backward", "*"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:cnt:0000000000000000000000000000000000000004", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000018", "swh:1:rel:0000000000000000000000000000000000000019" )); expectedPaths.add( new SwhPath( "swh:1:cnt:0000000000000000000000000000000000000004", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000018", "swh:1:rel:0000000000000000000000000000000000000019" )); expectedPaths.add( new SwhPath( "swh:1:cnt:0000000000000000000000000000000000000004", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:snp:0000000000000000000000000000000000000020" )); expectedPaths.add( new SwhPath( "swh:1:cnt:0000000000000000000000000000000000000004", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rel:0000000000000000000000000000000000000010", "swh:1:snp:0000000000000000000000000000000000000020" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void forwardSnpToRev() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal = new Traversal(graph, "forward", "snp:rev"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", "snp:rev"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void forwardRelToRevRevToRev() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:rel:0000000000000000000000000000000000000010"); - Traversal traversal = new Traversal(graph, "forward", "rel:rev,rev:rev"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", "rel:rev,rev:rev"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:rel:0000000000000000000000000000000000000010", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000003" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void forwardRevToAllDirToAll() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:rev:0000000000000000000000000000000000000013"); - Traversal traversal = new Traversal(graph, "forward", "rev:*,dir:*"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", "rev:*,dir:*"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000005" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000005" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000004" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000004" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000007" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000007" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:cnt:0000000000000000000000000000000000000011" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000003", "swh:1:dir:0000000000000000000000000000000000000002", "swh:1:cnt:0000000000000000000000000000000000000001" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000001" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:cnt:0000000000000000000000000000000000000001" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void forwardSnpToAllRevToAll() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal = new Traversal(graph, "forward", "snp:*,rev:*"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", "snp:*,rev:*"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000003", "swh:1:dir:0000000000000000000000000000000000000002" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008" )); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rel:0000000000000000000000000000000000000010" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void forwardNoEdges() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal = new Traversal(graph, "forward", ""); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", ""); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void backwardRevToRevRevToRel() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:rev:0000000000000000000000000000000000000003"); - Traversal traversal = new Traversal(graph, "backward", "rev:rev,rev:rel"); - ArrayList paths = traversal.visitPathsEndpoint(swhId); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "backward", "rev:rev,rev:rel"); + ArrayList paths = endpoint.visitPaths(swhId); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedPaths = new ArrayList(); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000003", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000018", "swh:1:rel:0000000000000000000000000000000000000019" )); expectedPaths.add( new SwhPath( "swh:1:rev:0000000000000000000000000000000000000003", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rel:0000000000000000000000000000000000000010" )); GraphTest.assertEqualsAnyOrder(expectedPaths, paths); assertSameNodesFromPaths(expectedPaths, nodes); } @Test public void forwardFromRootNodesOnly() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); - Traversal traversal = new Traversal(graph, "forward", "*"); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "forward", "*"); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedNodes = new ArrayList(); expectedNodes.add(new SwhId("swh:1:snp:0000000000000000000000000000000000000020")); expectedNodes.add(new SwhId("swh:1:rel:0000000000000000000000000000000000000010")); expectedNodes.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000009")); expectedNodes.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000003")); expectedNodes.add(new SwhId("swh:1:dir:0000000000000000000000000000000000000002")); expectedNodes.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000001")); expectedNodes.add(new SwhId("swh:1:dir:0000000000000000000000000000000000000008")); expectedNodes.add(new SwhId("swh:1:dir:0000000000000000000000000000000000000006")); expectedNodes.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000004")); expectedNodes.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000005")); expectedNodes.add(new SwhId("swh:1:cnt:0000000000000000000000000000000000000007")); GraphTest.assertEqualsAnyOrder(expectedNodes, nodes); } @Test public void backwardRevToAllNodesOnly() { Graph graph = getGraph(); SwhId swhId = new SwhId("swh:1:rev:0000000000000000000000000000000000000003"); - Traversal traversal = new Traversal(graph, "backward", "rev:*"); - ArrayList nodes = traversal.visitNodesEndpoint(swhId); + Endpoint endpoint = new Endpoint(graph, "backward", "rev:*"); + ArrayList nodes = endpoint.visitNodes(swhId); ArrayList expectedNodes = new ArrayList(); expectedNodes.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000003")); expectedNodes.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000009")); expectedNodes.add(new SwhId("swh:1:snp:0000000000000000000000000000000000000020")); expectedNodes.add(new SwhId("swh:1:rel:0000000000000000000000000000000000000010")); expectedNodes.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000013")); expectedNodes.add(new SwhId("swh:1:rev:0000000000000000000000000000000000000018")); expectedNodes.add(new SwhId("swh:1:rel:0000000000000000000000000000000000000019")); GraphTest.assertEqualsAnyOrder(expectedNodes, nodes); } } diff --git a/api/server/src/test/java/org/softwareheritage/graph/WalkTest.java b/api/server/src/test/java/org/softwareheritage/graph/WalkTest.java index 4f43367..445a706 100644 --- a/api/server/src/test/java/org/softwareheritage/graph/WalkTest.java +++ b/api/server/src/test/java/org/softwareheritage/graph/WalkTest.java @@ -1,169 +1,169 @@ package org.softwareheritage.graph; import java.util.ArrayList; import java.util.LinkedHashSet; import org.junit.Assert; import org.junit.Test; import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; +import org.softwareheritage.graph.Endpoint; import org.softwareheritage.graph.Graph; import org.softwareheritage.graph.GraphTest; import org.softwareheritage.graph.SwhId; import org.softwareheritage.graph.SwhPath; -import org.softwareheritage.graph.algo.Traversal; public class WalkTest extends GraphTest { @Test public void forwardRootToLeaf() { Graph graph = getGraph(); - Traversal traversal = new Traversal(graph, "forward", "*"); + Endpoint endpoint = new Endpoint(graph, "forward", "*"); SwhId src = new SwhId("swh:1:snp:0000000000000000000000000000000000000020"); String dstFmt = "swh:1:cnt:0000000000000000000000000000000000000005"; - SwhPath dfsPath = traversal.walkEndpoint(src, dstFmt, "dfs"); + SwhPath dfsPath = endpoint.walk(src, dstFmt, "dfs"); SwhPath dfsExpectedPath = new SwhPath( "swh:1:snp:0000000000000000000000000000000000000020", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:dir:0000000000000000000000000000000000000006", "swh:1:cnt:0000000000000000000000000000000000000005" ); Assert.assertEquals(dfsExpectedPath, dfsPath); - // Most of DFS and BFS traversal outputs are the same because it is a small test graph - SwhPath bfsPath = traversal.walkEndpoint(src, dstFmt, "bfs"); + // Most of DFS and BFS endpoint outputs are the same because it is a small test graph + SwhPath bfsPath = endpoint.walk(src, dstFmt, "bfs"); Assert.assertEquals(dfsExpectedPath, bfsPath); } @Test public void forwardLeafToLeaf() { Graph graph = getGraph(); - Traversal traversal = new Traversal(graph, "forward", "*"); + Endpoint endpoint = new Endpoint(graph, "forward", "*"); SwhId src = new SwhId("swh:1:cnt:0000000000000000000000000000000000000007"); String dstFmt = "cnt"; - SwhPath dfsPath = traversal.walkEndpoint(src, dstFmt, "dfs"); + SwhPath dfsPath = endpoint.walk(src, dstFmt, "dfs"); SwhPath dfsExpectedPath = new SwhPath( "swh:1:cnt:0000000000000000000000000000000000000007" ); Assert.assertEquals(dfsExpectedPath, dfsPath); - SwhPath bfsPath = traversal.walkEndpoint(src, dstFmt, "bfs"); + SwhPath bfsPath = endpoint.walk(src, dstFmt, "bfs"); Assert.assertEquals(dfsExpectedPath, bfsPath); } @Test public void forwardRevToRev() { Graph graph = getGraph(); - Traversal traversal = new Traversal(graph, "forward", "rev:rev"); + Endpoint endpoint = new Endpoint(graph, "forward", "rev:rev"); SwhId src = new SwhId("swh:1:rev:0000000000000000000000000000000000000018"); String dstFmt = "swh:1:rev:0000000000000000000000000000000000000003"; - SwhPath dfsPath = traversal.walkEndpoint(src, dstFmt, "dfs"); + SwhPath dfsPath = endpoint.walk(src, dstFmt, "dfs"); SwhPath dfsExpectedPath = new SwhPath( "swh:1:rev:0000000000000000000000000000000000000018", "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000003" ); Assert.assertEquals(dfsExpectedPath, dfsPath); - SwhPath bfsPath = traversal.walkEndpoint(src, dstFmt, "bfs"); + SwhPath bfsPath = endpoint.walk(src, dstFmt, "bfs"); Assert.assertEquals(dfsExpectedPath, bfsPath); } @Test public void backwardRevToRev() { Graph graph = getGraph(); - Traversal traversal = new Traversal(graph, "backward", "rev:rev"); + Endpoint endpoint = new Endpoint(graph, "backward", "rev:rev"); SwhId src = new SwhId("swh:1:rev:0000000000000000000000000000000000000003"); String dstFmt = "swh:1:rev:0000000000000000000000000000000000000018"; - SwhPath dfsPath = traversal.walkEndpoint(src, dstFmt, "dfs"); + SwhPath dfsPath = endpoint.walk(src, dstFmt, "dfs"); SwhPath dfsExpectedPath = new SwhPath( "swh:1:rev:0000000000000000000000000000000000000003", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:rev:0000000000000000000000000000000000000018" ); Assert.assertEquals(dfsExpectedPath, dfsPath); - SwhPath bfsPath = traversal.walkEndpoint(src, dstFmt, "bfs"); + SwhPath bfsPath = endpoint.walk(src, dstFmt, "bfs"); Assert.assertEquals(dfsExpectedPath, bfsPath); } @Test public void backwardCntToFirstSnp() { Graph graph = getGraph(); - Traversal traversal = new Traversal(graph, "backward", "*"); + Endpoint endpoint = new Endpoint(graph, "backward", "*"); SwhId src = new SwhId("swh:1:cnt:0000000000000000000000000000000000000001"); String dstFmt = "snp"; - SwhPath dfsPath = traversal.walkEndpoint(src, dstFmt, "dfs"); + SwhPath dfsPath = endpoint.walk(src, dstFmt, "dfs"); SwhPath dfsExpectedPath = new SwhPath( "swh:1:cnt:0000000000000000000000000000000000000001", "swh:1:dir:0000000000000000000000000000000000000002", "swh:1:rev:0000000000000000000000000000000000000003", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:snp:0000000000000000000000000000000000000020" ); Assert.assertEquals(dfsExpectedPath, dfsPath); - SwhPath bfsPath = traversal.walkEndpoint(src, dstFmt, "bfs"); + SwhPath bfsPath = endpoint.walk(src, dstFmt, "bfs"); SwhPath bfsExpectedPath = new SwhPath( "swh:1:cnt:0000000000000000000000000000000000000001", "swh:1:dir:0000000000000000000000000000000000000008", "swh:1:rev:0000000000000000000000000000000000000009", "swh:1:snp:0000000000000000000000000000000000000020" ); Assert.assertEquals(bfsExpectedPath, bfsPath); } @Test public void forwardRevToFirstCnt() { Graph graph = getGraph(); - Traversal traversal = new Traversal(graph, "forward", "rev:*,dir:*"); + Endpoint endpoint = new Endpoint(graph, "forward", "rev:*,dir:*"); SwhId src = new SwhId("swh:1:rev:0000000000000000000000000000000000000013"); String dstFmt = "cnt"; - SwhPath dfsPath = traversal.walkEndpoint(src, dstFmt, "dfs"); + SwhPath dfsPath = endpoint.walk(src, dstFmt, "dfs"); SwhPath dfsExpectedPath = new SwhPath( "swh:1:rev:0000000000000000000000000000000000000013", "swh:1:dir:0000000000000000000000000000000000000012", "swh:1:cnt:0000000000000000000000000000000000000011" ); Assert.assertEquals(dfsExpectedPath, dfsPath); - SwhPath bfsPath = traversal.walkEndpoint(src, dstFmt, "bfs"); + SwhPath bfsPath = endpoint.walk(src, dstFmt, "bfs"); Assert.assertEquals(dfsExpectedPath, bfsPath); } @Test public void backwardDirToFirstRel() { Graph graph = getGraph(); - Traversal traversal = new Traversal(graph, "backward", "dir:dir,dir:rev,rev:*"); + Endpoint endpoint = new Endpoint(graph, "backward", "dir:dir,dir:rev,rev:*"); SwhId src = new SwhId("swh:1:dir:0000000000000000000000000000000000000016"); String dstFmt = "rel"; - SwhPath dfsPath = traversal.walkEndpoint(src, dstFmt, "dfs"); + SwhPath dfsPath = endpoint.walk(src, dstFmt, "dfs"); SwhPath dfsExpectedPath = new SwhPath( "swh:1:dir:0000000000000000000000000000000000000016", "swh:1:dir:0000000000000000000000000000000000000017", "swh:1:rev:0000000000000000000000000000000000000018", "swh:1:rel:0000000000000000000000000000000000000019" ); Assert.assertEquals(dfsExpectedPath, dfsPath); - SwhPath bfsPath = traversal.walkEndpoint(src, dstFmt, "bfs"); + SwhPath bfsPath = endpoint.walk(src, dstFmt, "bfs"); Assert.assertEquals(dfsExpectedPath, bfsPath); } }