diff --git a/java/README.md b/java/README.md index 8d7edf7..7276284 100644 --- a/java/README.md +++ b/java/README.md @@ -1,51 +1,49 @@ Graph service - Java backend ============================ Server side Java RPC API. Build ----- ```bash $ mvn compile assembly:single ``` Start RPC API ------------- ```bash $ java -cp target/swh-graph-*.jar \ - org.softwareheritage.graph.server.App \ + org.softwareheritage.graph.rpc.GraphServer \ ``` -Default port is 5009 (use the `--port` option to change port number). If you -need timings metadata send back to the client in addition to the result, use the -`--timings` flag. +Default port is 50091 (use the `--port` option to change port number). Tests ----- Unit tests rely on test data that are already available in the Git repository (under `src/swh/graph/tests/dataset/`). You generally only need to run them using Maven: ```bash $ mvn test ``` In case you want to regenerate the test data: ```bash # Graph compression $ cd src/swh/graph/tests/dataset $ ./generate_graph.sh $ cd ../../../.. $ mvn compile assembly:single # Dump mapping files $ java -cp target/swh-graph-*.jar \ org.softwareheritage.graph.compress.NodeMapBuilder \ src/swh/graph/tests/dataset/example.nodes.csv.gz \ src/swh/graph/tests/dataset/output/example ``` diff --git a/java/pom.xml b/java/pom.xml index 3c2ab60..d51e6e2 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -1,429 +1,398 @@ 4.0.0 org.softwareheritage.graph swh-graph ${git.closest.tag.name} swh-graph https://forge.softwareheritage.org/source/swh-graph/ UTF-8 11 3.20.1 1.46.0 ch.qos.logback logback-classic 1.2.3 org.junit.jupiter junit-jupiter-api 5.7.0 test - - org.junit.vintage - junit-vintage-engine - 5.7.0 - - - junit - junit - 4.12 - org.junit.jupiter junit-jupiter-engine 5.7.0 test - - org.hamcrest - hamcrest - 2.2 - test - - - io.javalin - javalin - 3.0.0 - org.slf4j slf4j-simple 1.7.26 - - com.fasterxml.jackson.core - jackson-databind - 2.13.0 - it.unimi.dsi webgraph-big 3.6.7 it.unimi.dsi fastutil 8.5.8 it.unimi.dsi dsiutils 2.7.1 it.unimi.dsi sux4j 5.3.1 it.unimi.dsi law 2.7.2 org.apache.hadoop hadoop-common org.umlgraph umlgraph org.eclipse.jetty.aggregate jetty-all it.unimi.di mg4j it.unimi.di mg4j-big com.martiansoftware jsap 2.1 - - net.sf.py4j - py4j - 0.10.9.3 - commons-codec commons-codec 1.15 com.github.luben zstd-jni 1.5.1-1 org.apache.orc orc-core 1.7.1 org.apache.hadoop hadoop-common 3.3.1 org.apache.hadoop hadoop-client-runtime 3.3.1 com.google.protobuf protobuf-java ${protobuf.version} io.grpc grpc-netty-shaded ${grpc.version} io.grpc grpc-protobuf ${grpc.version} io.grpc grpc-stub ${grpc.version} io.grpc grpc-services ${grpc.version} io.grpc grpc-testing ${grpc.version} javax.annotation javax.annotation-api 1.3.2 maven-clean-plugin 3.1.0 maven-resources-plugin 3.0.2 maven-compiler-plugin 3.8.0 11 11 -verbose -Xlint:all maven-surefire-plugin 2.22.2 maven-failsafe-plugin 2.22.2 maven-jar-plugin 3.0.2 maven-install-plugin 2.5.2 maven-deploy-plugin 2.8.2 maven-site-plugin 3.7.1 maven-project-info-reports-plugin 3.0.0 maven-dependency-plugin 3.1.2 maven-assembly-plugin 3.3.0 - org.softwareheritage.graph.server.App + org.softwareheritage.graph.rpc.GraphServer jar-with-dependencies false make-assembly package single com.diffplug.spotless spotless-maven-plugin 2.22.1 *.md .gitignore true 4 4.16.0 .coding-style.xml pl.project13.maven git-commit-id-plugin 3.0.1 get-the-git-infos revision initialize true true true true v* git.closest.tag.name ^v true maven-source-plugin 2.1.1 bundle-sources package jar-no-fork test-jar-no-fork org.apache.maven.plugins maven-javadoc-plugin 3.3.1 resource-bundles package resource-bundle test-resource-bundle false javadoc-jar package jar true it.unimi.dsi:webgraph-big:* https://webgraph.di.unimi.it/docs-big/ https://dsiutils.di.unimi.it/docs/ https://fastutil.di.unimi.it/docs/ https://law.di.unimi.it/software/law-docs/ implSpec a Implementation Requirements: implNote a Implementation Note: org.xolstice.maven.plugins protobuf-maven-plugin 0.6.1 com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier} grpc-java io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} compile compile-custom test-compile test-compile-custom kr.motd.maven os-maven-plugin 1.6.2 diff --git a/java/src/main/java/org/softwareheritage/graph/Entry.java b/java/src/main/java/org/softwareheritage/graph/Entry.java deleted file mode 100644 index e6f4494..0000000 --- a/java/src/main/java/org/softwareheritage/graph/Entry.java +++ /dev/null @@ -1,193 +0,0 @@ -package org.softwareheritage.graph; - -import java.io.*; -import java.util.ArrayList; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; - -public class Entry { - private SwhBidirectionalGraph graph; - - public void load_graph(String graphBasename) throws IOException { - System.err.println("Loading graph " + graphBasename + " ..."); - this.graph = SwhBidirectionalGraph.loadMapped(graphBasename); - System.err.println("Graph loaded."); - } - - public SwhBidirectionalGraph get_graph() { - return graph.copy(); - } - - public String stats() { - try { - Stats stats = new Stats(graph.getPath()); - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); - return objectMapper.writeValueAsString(stats); - } catch (IOException e) { - throw new RuntimeException("Cannot read stats: " + e); - } - } - - public void check_swhid(String src) { - graph.getNodeId(new SWHID(src)); - } - - private int count_visitor(NodeCountVisitor f, long srcNodeId) { - int[] count = {0}; - f.accept(srcNodeId, (node) -> { - count[0]++; - }); - return count[0]; - } - - public int count_leaves(String direction, String edgesFmt, String src, long maxEdges) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - Traversal t = new Traversal(graph.copy(), direction, edgesFmt, maxEdges); - return count_visitor(t::leavesVisitor, srcNodeId); - } - - public int count_neighbors(String direction, String edgesFmt, String src, long maxEdges) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - Traversal t = new Traversal(graph.copy(), direction, edgesFmt, maxEdges); - return count_visitor(t::neighborsVisitor, srcNodeId); - } - - public int count_visit_nodes(String direction, String edgesFmt, String src, long maxEdges) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - Traversal t = new Traversal(graph.copy(), direction, edgesFmt, maxEdges); - return count_visitor(t::visitNodesVisitor, srcNodeId); - } - - public QueryHandler get_handler(String clientFIFO) { - return new QueryHandler(graph.copy(), clientFIFO); - } - - private interface NodeCountVisitor { - void accept(long nodeId, Traversal.NodeIdConsumer consumer); - } - - public class QueryHandler { - SwhBidirectionalGraph graph; - BufferedWriter out; - String clientFIFO; - - public QueryHandler(SwhBidirectionalGraph graph, String clientFIFO) { - this.graph = graph; - this.clientFIFO = clientFIFO; - this.out = null; - } - - public void writeNode(SWHID swhid) { - try { - out.write(swhid.toString() + "\n"); - } catch (IOException e) { - throw new RuntimeException("Cannot write response to client: " + e); - } - } - - public void writeEdge(SWHID src, SWHID dst) { - try { - out.write(src.toString() + " " + dst.toString() + "\n"); - } catch (IOException e) { - throw new RuntimeException("Cannot write response to client: " + e); - } - } - - public void open() { - try { - FileOutputStream file = new FileOutputStream(this.clientFIFO); - this.out = new BufferedWriter(new OutputStreamWriter(file)); - } catch (IOException e) { - throw new RuntimeException("Cannot open client FIFO: " + e); - } - } - - public void close() { - try { - out.close(); - } catch (IOException e) { - throw new RuntimeException("Cannot write response to client: " + e); - } - } - - public void leaves(String direction, String edgesFmt, String src, long maxEdges, String returnTypes) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - open(); - Traversal t = new Traversal(graph, direction, edgesFmt, maxEdges, returnTypes); - for (Long nodeId : t.leaves(srcNodeId)) { - writeNode(graph.getSWHID(nodeId)); - } - close(); - } - - public void neighbors(String direction, String edgesFmt, String src, long maxEdges, String returnTypes) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - open(); - Traversal t = new Traversal(graph, direction, edgesFmt, maxEdges, returnTypes); - for (Long nodeId : t.neighbors(srcNodeId)) { - writeNode(graph.getSWHID(nodeId)); - } - close(); - } - - public void visit_nodes(String direction, String edgesFmt, String src, long maxEdges, String returnTypes) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - open(); - Traversal t = new Traversal(graph, direction, edgesFmt, maxEdges, returnTypes); - for (Long nodeId : t.visitNodes(srcNodeId)) { - writeNode(graph.getSWHID(nodeId)); - } - close(); - } - - public void visit_edges(String direction, String edgesFmt, String src, long maxEdges, String returnTypes) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - open(); - Traversal t = new Traversal(graph, direction, edgesFmt, maxEdges); - t.visitNodesVisitor(srcNodeId, null, (srcId, dstId) -> { - writeEdge(graph.getSWHID(srcId), graph.getSWHID(dstId)); - }); - close(); - } - - public void walk(String direction, String edgesFmt, String algorithm, String src, String dst, long maxEdges, - String returnTypes) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - open(); - ArrayList res; - Traversal t = new Traversal(graph, direction, edgesFmt, maxEdges, returnTypes); - if (dst.matches("ori|snp|rel|rev|dir|cnt")) { - Node.Type dstType = Node.Type.fromStr(dst); - res = t.walk(srcNodeId, dstType, algorithm); - } else { - long dstNodeId = graph.getNodeId(new SWHID(dst)); - res = t.walk(srcNodeId, dstNodeId, algorithm); - } - for (Long nodeId : res) { - writeNode(graph.getSWHID(nodeId)); - } - close(); - } - - public void random_walk(String direction, String edgesFmt, int retries, String src, String dst, long maxEdges, - String returnTypes) { - long srcNodeId = graph.getNodeId(new SWHID(src)); - open(); - ArrayList res; - Traversal t = new Traversal(graph, direction, edgesFmt, maxEdges, returnTypes); - if (dst.matches("ori|snp|rel|rev|dir|cnt")) { - Node.Type dstType = Node.Type.fromStr(dst); - res = t.randomWalk(srcNodeId, dstType, retries); - } else { - long dstNodeId = graph.getNodeId(new SWHID(dst)); - res = t.randomWalk(srcNodeId, dstNodeId, retries); - } - for (Long nodeId : res) { - writeNode(graph.getSWHID(nodeId)); - } - close(); - } - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/Stats.java b/java/src/main/java/org/softwareheritage/graph/Stats.java deleted file mode 100644 index 1c1cb0f..0000000 --- a/java/src/main/java/org/softwareheritage/graph/Stats.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.softwareheritage.graph; - -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; - -/** - * Statistics on the compressed graph. - *

- * These statistics are not computed but directly read from - * WebGraph generated .stats and .properties files. - * - * @author The Software Heritage developers - */ - -public class Stats { - public Counts counts; - public Ratios ratios; - public Degree indegree; - public Degree outdegree; - /** - * Constructor. - * - * @param graphPath path and basename of compressed graph - */ - public Stats(String graphPath) throws IOException { - Properties properties = new Properties(); - properties.load(new FileInputStream(graphPath + ".properties")); - properties.load(new FileInputStream(graphPath + ".stats")); - - this.counts = new Counts(); - this.ratios = new Ratios(); - this.indegree = new Degree(); - this.outdegree = new Degree(); - - this.counts.nodes = Long.parseLong(properties.getProperty("nodes")); - this.counts.edges = Long.parseLong(properties.getProperty("arcs")); - this.ratios.compression = Double.parseDouble(properties.getProperty("compratio")); - this.ratios.bitsPerNode = Double.parseDouble(properties.getProperty("bitspernode")); - this.ratios.bitsPerEdge = Double.parseDouble(properties.getProperty("bitsperlink")); - this.ratios.avgLocality = Double.parseDouble(properties.getProperty("avglocality")); - this.indegree.min = Long.parseLong(properties.getProperty("minindegree")); - this.indegree.max = Long.parseLong(properties.getProperty("maxindegree")); - this.indegree.avg = Double.parseDouble(properties.getProperty("avgindegree")); - this.outdegree.min = Long.parseLong(properties.getProperty("minoutdegree")); - this.outdegree.max = Long.parseLong(properties.getProperty("maxoutdegree")); - this.outdegree.avg = Double.parseDouble(properties.getProperty("avgoutdegree")); - } - - public static class Counts { - public long nodes; - public long edges; - } - - public static class Ratios { - public double compression; - public double bitsPerNode; - public double bitsPerEdge; - public double avgLocality; - } - - public static class Degree { - public long min; - public long max; - public double avg; - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/SwhPath.java b/java/src/main/java/org/softwareheritage/graph/SwhPath.java deleted file mode 100644 index 8693e02..0000000 --- a/java/src/main/java/org/softwareheritage/graph/SwhPath.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.softwareheritage.graph; - -import com.fasterxml.jackson.annotation.JsonValue; - -import java.util.ArrayList; - -/** - * Wrapper class to store a list of {@link SWHID}. - * - * @author The Software Heritage developers - * @see SWHID - */ - -public class SwhPath { - /** Internal list of {@link SWHID} */ - ArrayList path; - - /** - * Constructor. - */ - public SwhPath() { - this.path = new ArrayList<>(); - } - - /** - * Constructor. - * - * @param swhids variable number of string SWHIDs to initialize this path with - */ - public SwhPath(String... swhids) { - this(); - for (String swhid : swhids) { - add(new SWHID(swhid)); - } - } - - /** - * Constructor. - * - * @param swhids variable number of {@link SWHID} to initialize this path with - * @see SWHID - */ - public SwhPath(SWHID... swhids) { - this(); - for (SWHID swhid : swhids) { - add(swhid); - } - } - - /** - * Returns this path as a list of {@link SWHID}. - * - * @return list of {@link SWHID} constituting the path - * @see SWHID - */ - @JsonValue - public ArrayList getPath() { - return path; - } - - /** - * Adds a {@link SWHID} to this path. - * - * @param swhid {@link SWHID} to add to this path - * @see SWHID - */ - public void add(SWHID swhid) { - path.add(swhid); - } - - /** - * Returns the {@link SWHID} at the specified position in this path. - * - * @param index position of the {@link SWHID} to return - * @return {@link SWHID} at the specified position - * @see SWHID - */ - public SWHID get(int index) { - return path.get(index); - } - - /** - * Returns the number of elements in this path. - * - * @return number of elements in this path - */ - public int size() { - return path.size(); - } - - @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() { - StringBuilder str = new StringBuilder(); - for (SWHID swhid : path) { - str.append(swhid).append("/"); - } - return str.toString(); - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/Traversal.java b/java/src/main/java/org/softwareheritage/graph/Traversal.java index 2ce9e4a..1b4c7d8 100644 --- a/java/src/main/java/org/softwareheritage/graph/Traversal.java +++ b/java/src/main/java/org/softwareheritage/graph/Traversal.java @@ -1,614 +1,609 @@ package org.softwareheritage.graph; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.Random; import java.util.Stack; import java.util.function.Consumer; import java.util.function.LongConsumer; -import org.softwareheritage.graph.server.Endpoint; - import it.unimi.dsi.big.webgraph.LazyLongIterator; /** * Traversal algorithms on the compressed graph. *

- * Internal implementation of the traversal API endpoints. These methods only input/output internal - * long ids, which are converted in the {@link Endpoint} higher-level class to {@link SWHID}. * * @author The Software Heritage developers - * @see Endpoint */ public class Traversal { /** Graph used in the traversal */ SwhBidirectionalGraph graph; /** Type filter on the returned nodes */ AllowedNodes nodesFilter; /** Restrictions on which edges can be traversed */ AllowedEdges edgesRestrictions; /** Hash set storing if we have visited a node */ HashSet visited; /** Hash map storing parent node id for each nodes during a traversal */ Map parentNode; /** Number of edges accessed during traversal */ long nbEdgesAccessed; /** The anti Dos limit of edges traversed while a visit */ long maxEdges; /** random number generator, for random walks */ Random rng; /** * Constructor. * * @param graph graph used in the traversal * @param direction a string (either "forward" or "backward") specifying edge orientation * @param edgesFmt a formatted string describing allowed * edges */ public Traversal(SwhBidirectionalGraph graph, String direction, String edgesFmt) { this(graph, direction, edgesFmt, 0); } public Traversal(SwhBidirectionalGraph graph, String direction, String edgesFmt, long maxEdges) { this(graph, direction, edgesFmt, maxEdges, "*"); } public Traversal(SwhBidirectionalGraph graph, String direction, String edgesFmt, long maxEdges, String returnTypes) { if (!direction.matches("forward|backward")) { throw new IllegalArgumentException("Unknown traversal direction: " + direction); } if (direction.equals("backward")) { this.graph = graph.transpose(); } else { this.graph = graph; } this.nodesFilter = new AllowedNodes(returnTypes); this.edgesRestrictions = new AllowedEdges(edgesFmt); this.visited = new HashSet<>(); this.parentNode = new HashMap<>(); this.nbEdgesAccessed = 0; this.maxEdges = maxEdges; this.rng = new Random(); } /** * Returns number of accessed edges during traversal. * * @return number of edges accessed in last traversal */ public long getNbEdgesAccessed() { return nbEdgesAccessed; } /** * Returns number of accessed nodes during traversal. * * @return number of nodes accessed in last traversal */ public long getNbNodesAccessed() { return this.visited.size(); } /** * Returns lazy iterator of successors of a node while following a specific set of edge types. * * @param g input graph * @param nodeId node specified as a long id * @param allowedEdges the specification of which edges can be traversed * @return lazy iterator of successors of the node, specified as a * WebGraph LazyLongIterator */ public static LazyLongIterator filterSuccessors(SwhBidirectionalGraph g, long nodeId, AllowedEdges allowedEdges) { if (allowedEdges.restrictedTo == null) { // All edges are allowed, bypass edge check return g.successors(nodeId); } else { LazyLongIterator allSuccessors = g.successors(nodeId); return new LazyLongIterator() { @Override public long nextLong() { long neighbor; while ((neighbor = allSuccessors.nextLong()) != -1) { if (allowedEdges.isAllowed(g.getNodeType(nodeId), g.getNodeType(neighbor))) { return neighbor; } } return -1; } @Override public long skip(final long n) { long i; for (i = 0; i < n && nextLong() != -1; i++) ; return i; } }; } } private LazyLongIterator filterSuccessors(long nodeId, AllowedEdges allowedEdges) { return filterSuccessors(graph, nodeId, allowedEdges); } /** * Push version of {@link #leaves} will fire passed callback for each leaf. */ public void leavesVisitor(long srcNodeId, NodeIdConsumer cb) { Stack stack = new Stack<>(); this.nbEdgesAccessed = 0; stack.push(srcNodeId); visited.add(srcNodeId); while (!stack.isEmpty()) { long currentNodeId = stack.pop(); long neighborsCnt = 0; nbEdgesAccessed += graph.outdegree(currentNodeId); if (this.maxEdges > 0) { if (nbEdgesAccessed >= this.maxEdges) { break; } } LazyLongIterator it = filterSuccessors(currentNodeId, edgesRestrictions); for (long neighborNodeId; (neighborNodeId = it.nextLong()) != -1;) { neighborsCnt++; if (!visited.contains(neighborNodeId)) { stack.push(neighborNodeId); visited.add(neighborNodeId); } } if (neighborsCnt == 0) { if (nodesFilter.isAllowed(graph.getNodeType(currentNodeId))) { cb.accept(currentNodeId); } } } } /** * Returns the leaves of a subgraph rooted at the specified source node. * * @param srcNodeId source node * @return list of node ids corresponding to the leaves */ public ArrayList leaves(long srcNodeId) { ArrayList nodeIds = new ArrayList(); leavesVisitor(srcNodeId, nodeIds::add); return nodeIds; } /** * Push version of {@link #neighbors}: will fire passed callback on each neighbor. */ public void neighborsVisitor(long srcNodeId, NodeIdConsumer cb) { this.nbEdgesAccessed = graph.outdegree(srcNodeId); if (this.maxEdges > 0) { if (nbEdgesAccessed >= this.maxEdges) { return; } } LazyLongIterator it = filterSuccessors(srcNodeId, edgesRestrictions); for (long neighborNodeId; (neighborNodeId = it.nextLong()) != -1;) { if (nodesFilter.isAllowed(graph.getNodeType(neighborNodeId))) { cb.accept(neighborNodeId); } } } /** * Returns node direct neighbors (linked with exactly one edge). * * @param srcNodeId source node * @return list of node ids corresponding to the neighbors */ public ArrayList neighbors(long srcNodeId) { ArrayList nodeIds = new ArrayList<>(); neighborsVisitor(srcNodeId, nodeIds::add); return nodeIds; } /** * Push version of {@link #visitNodes}: will fire passed callback on each visited node. */ public void visitNodesVisitor(long srcNodeId, NodeIdConsumer nodeCb, EdgeIdConsumer edgeCb) { Stack stack = new Stack<>(); this.nbEdgesAccessed = 0; stack.push(srcNodeId); visited.add(srcNodeId); while (!stack.isEmpty()) { long currentNodeId = stack.pop(); if (nodeCb != null) { if (nodesFilter.isAllowed(graph.getNodeType(currentNodeId))) { nodeCb.accept(currentNodeId); } } nbEdgesAccessed += graph.outdegree(currentNodeId); if (this.maxEdges > 0) { if (nbEdgesAccessed >= this.maxEdges) { break; } } LazyLongIterator it = filterSuccessors(currentNodeId, edgesRestrictions); for (long neighborNodeId; (neighborNodeId = it.nextLong()) != -1;) { if (edgeCb != null) { if (nodesFilter.isAllowed(graph.getNodeType(currentNodeId))) { edgeCb.accept(currentNodeId, neighborNodeId); } } if (!visited.contains(neighborNodeId)) { stack.push(neighborNodeId); visited.add(neighborNodeId); } } } } /** One-argument version to handle callbacks properly */ public void visitNodesVisitor(long srcNodeId, NodeIdConsumer cb) { visitNodesVisitor(srcNodeId, cb, null); } /** * Performs a graph traversal and returns explored nodes. * * @param srcNodeId source node * @return list of explored node ids */ public ArrayList visitNodes(long srcNodeId) { ArrayList nodeIds = new ArrayList<>(); visitNodesVisitor(srcNodeId, nodeIds::add); return nodeIds; } /** * Push version of {@link #visitPaths}: will fire passed callback on each discovered (complete) * path. */ public void visitPathsVisitor(long srcNodeId, PathConsumer cb) { Stack currentPath = new Stack<>(); this.nbEdgesAccessed = 0; visitPathsInternalVisitor(srcNodeId, currentPath, cb); } /** * Performs a graph traversal and returns explored paths. * * @param srcNodeId source node * @return list of explored paths (represented as a list of node ids) */ public ArrayList> visitPaths(long srcNodeId) { ArrayList> paths = new ArrayList<>(); visitPathsVisitor(srcNodeId, paths::add); return paths; } private void visitPathsInternalVisitor(long currentNodeId, Stack currentPath, PathConsumer cb) { currentPath.push(currentNodeId); long visitedNeighbors = 0; nbEdgesAccessed += graph.outdegree(currentNodeId); if (this.maxEdges > 0) { if (nbEdgesAccessed >= this.maxEdges) { currentPath.pop(); return; } } LazyLongIterator it = filterSuccessors(currentNodeId, edgesRestrictions); for (long neighborNodeId; (neighborNodeId = it.nextLong()) != -1;) { visitPathsInternalVisitor(neighborNodeId, currentPath, cb); visitedNeighbors++; } if (visitedNeighbors == 0) { ArrayList path = new ArrayList<>(currentPath); cb.accept(path); } currentPath.pop(); } /** * Performs a graph traversal with backtracking, and returns the first found path from source to * destination. * * @param srcNodeId source node * @param dst destination (either a node or a node type) * @return found path as a list of node ids */ public ArrayList walk(long srcNodeId, T dst, String visitOrder) { long dstNodeId; if (visitOrder.equals("dfs")) { dstNodeId = walkInternalDFS(srcNodeId, dst); } else if (visitOrder.equals("bfs")) { dstNodeId = walkInternalBFS(srcNodeId, dst); } else { throw new IllegalArgumentException("Unknown visit order: " + visitOrder); } if (dstNodeId == -1) { throw new IllegalArgumentException("Cannot find destination: " + dst); } return backtracking(srcNodeId, dstNodeId); } /** * Performs a random walk (picking a random successor at each step) from source to destination. * * @param srcNodeId source node * @param dst destination (either a node or a node type) * @return found path as a list of node ids or an empty path to indicate that no suitable path have * been found */ public ArrayList randomWalk(long srcNodeId, T dst) { return randomWalk(srcNodeId, dst, 0); } /** * Performs a stubborn random walk (picking a random successor at each step) from source to * destination. The walk is "stubborn" in the sense that it will not give up the first time if a * satisfying target node is found, but it will retry up to a limited amount of times. * * @param srcNodeId source node * @param dst destination (either a node or a node type) * @param retries number of times to retry; 0 means no retries (single walk) * @return found path as a list of node ids or an empty path to indicate that no suitable path have * been found */ public ArrayList randomWalk(long srcNodeId, T dst, int retries) { long curNodeId = srcNodeId; ArrayList path = new ArrayList<>(); this.nbEdgesAccessed = 0; boolean found; if (retries < 0) { throw new IllegalArgumentException("Negative number of retries given: " + retries); } while (true) { path.add(curNodeId); LazyLongIterator successors = filterSuccessors(curNodeId, edgesRestrictions); curNodeId = randomPick(successors); if (curNodeId < 0) { found = false; break; } if (isDstNode(curNodeId, dst)) { path.add(curNodeId); found = true; break; } } if (found) { return path; } else if (retries > 0) { // try again return randomWalk(srcNodeId, dst, retries - 1); } else { // not found and no retries left path.clear(); return path; } } /** * Randomly choose an element from an iterator over Longs using reservoir sampling * * @param elements iterator over selection domain * @return randomly chosen element or -1 if no suitable element was found */ private long randomPick(LazyLongIterator elements) { long curPick = -1; long seenCandidates = 0; for (long element; (element = elements.nextLong()) != -1;) { seenCandidates++; if (Math.round(rng.nextFloat() * (seenCandidates - 1)) == 0) { curPick = element; } } return curPick; } /** * Internal DFS function of {@link #walk}. * * @param srcNodeId source node * @param dst destination (either a node or a node type) * @return final destination node or -1 if no path found */ private long walkInternalDFS(long srcNodeId, T dst) { Stack stack = new Stack<>(); this.nbEdgesAccessed = 0; stack.push(srcNodeId); visited.add(srcNodeId); while (!stack.isEmpty()) { long currentNodeId = stack.pop(); if (isDstNode(currentNodeId, dst)) { return currentNodeId; } nbEdgesAccessed += graph.outdegree(currentNodeId); LazyLongIterator it = filterSuccessors(currentNodeId, edgesRestrictions); for (long neighborNodeId; (neighborNodeId = it.nextLong()) != -1;) { if (!visited.contains(neighborNodeId)) { stack.push(neighborNodeId); visited.add(neighborNodeId); parentNode.put(neighborNodeId, currentNodeId); } } } return -1; } /** * Internal BFS function of {@link #walk}. * * @param srcNodeId source node * @param dst destination (either a node or a node type) * @return final destination node or -1 if no path found */ private long walkInternalBFS(long srcNodeId, T dst) { Queue queue = new LinkedList<>(); this.nbEdgesAccessed = 0; queue.add(srcNodeId); visited.add(srcNodeId); while (!queue.isEmpty()) { long currentNodeId = queue.poll(); if (isDstNode(currentNodeId, dst)) { return currentNodeId; } nbEdgesAccessed += graph.outdegree(currentNodeId); LazyLongIterator it = filterSuccessors(currentNodeId, edgesRestrictions); for (long neighborNodeId; (neighborNodeId = it.nextLong()) != -1;) { if (!visited.contains(neighborNodeId)) { queue.add(neighborNodeId); visited.add(neighborNodeId); parentNode.put(neighborNodeId, currentNodeId); } } } return -1; } /** * Internal function of {@link #walk} to check if a node corresponds to the destination. * * @param nodeId current node * @param dst destination (either a node or a node type) * @return true if the node is a destination, or false otherwise */ 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; } } /** * Internal backtracking function of {@link #walk}. * * @param srcNodeId source node * @param dstNodeId destination node * @return the found path, as a list of node ids */ private ArrayList backtracking(long srcNodeId, long dstNodeId) { ArrayList path = new ArrayList<>(); long currentNodeId = dstNodeId; while (currentNodeId != srcNodeId) { path.add(currentNodeId); currentNodeId = parentNode.get(currentNodeId); } path.add(srcNodeId); Collections.reverse(path); return path; } /** * Find a common descendant between two given nodes using two parallel BFS * * @param lhsNode the first node * @param rhsNode the second node * @return the found path, as a list of node ids */ public Long findCommonDescendant(long lhsNode, long rhsNode) { Queue lhsStack = new ArrayDeque<>(); Queue rhsStack = new ArrayDeque<>(); HashSet lhsVisited = new HashSet<>(); HashSet rhsVisited = new HashSet<>(); lhsStack.add(lhsNode); rhsStack.add(rhsNode); lhsVisited.add(lhsNode); rhsVisited.add(rhsNode); this.nbEdgesAccessed = 0; Long curNode; while (!lhsStack.isEmpty() || !rhsStack.isEmpty()) { if (!lhsStack.isEmpty()) { curNode = lhsStack.poll(); nbEdgesAccessed += graph.outdegree(curNode); LazyLongIterator it = filterSuccessors(curNode, edgesRestrictions); for (long neighborNodeId; (neighborNodeId = it.nextLong()) != -1;) { if (!lhsVisited.contains(neighborNodeId)) { if (rhsVisited.contains(neighborNodeId)) return neighborNodeId; lhsStack.add(neighborNodeId); lhsVisited.add(neighborNodeId); } } } if (!rhsStack.isEmpty()) { curNode = rhsStack.poll(); nbEdgesAccessed += graph.outdegree(curNode); LazyLongIterator it = filterSuccessors(curNode, edgesRestrictions); for (long neighborNodeId; (neighborNodeId = it.nextLong()) != -1;) { if (!rhsVisited.contains(neighborNodeId)) { if (lhsVisited.contains(neighborNodeId)) return neighborNodeId; rhsStack.add(neighborNodeId); rhsVisited.add(neighborNodeId); } } } } return null; } public interface NodeIdConsumer extends LongConsumer { /** * Callback for incrementally receiving node identifiers during a graph visit. */ void accept(long nodeId); } public interface EdgeIdConsumer { /** * Callback for incrementally receiving edge identifiers during a graph visit. */ void accept(long srcId, long dstId); } public interface PathConsumer extends Consumer> { /** * Callback for incrementally receiving node paths (made of node identifiers) during a graph visit. */ void accept(ArrayList path); } } diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/AccessEdge.java b/java/src/main/java/org/softwareheritage/graph/benchmark/AccessEdge.java deleted file mode 100644 index 7f05184..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/AccessEdge.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.softwareheritage.graph.benchmark; - -import com.martiansoftware.jsap.JSAPException; -import it.unimi.dsi.big.webgraph.LazyLongIterator; -import org.softwareheritage.graph.SwhBidirectionalGraph; -import org.softwareheritage.graph.benchmark.utils.Statistics; -import org.softwareheritage.graph.benchmark.utils.Timing; - -import java.io.IOException; -import java.util.ArrayList; - -/** - * Benchmark to time edge access time. - * - * @author The Software Heritage developers - */ - -public class AccessEdge { - /** - * Main entrypoint. - * - * @param args command line arguments - */ - public static void main(String[] args) throws IOException, JSAPException { - Benchmark bench = new Benchmark(); - bench.parseCommandLineArgs(args); - - SwhBidirectionalGraph graph = SwhBidirectionalGraph.loadMapped(bench.args.graphPath); - - long[] nodeIds = bench.args.random.generateNodeIds(graph, bench.args.nbNodes); - - ArrayList timings = new ArrayList<>(); - for (long nodeId : nodeIds) { - long startTime = Timing.start(); - LazyLongIterator neighbors = graph.successors(nodeId); - long firstNeighbor = neighbors.nextLong(); - double duration = Timing.stop(startTime); - timings.add(duration); - } - - System.out.println("Used " + bench.args.nbNodes + " random edges (results are in seconds):"); - Statistics stats = new Statistics(timings); - stats.printAll(); - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/BFS.java b/java/src/main/java/org/softwareheritage/graph/benchmark/BFS.java deleted file mode 100644 index 2ca9b58..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/BFS.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.softwareheritage.graph.benchmark; - -import com.google.common.primitives.Longs; -import com.martiansoftware.jsap.*; -import it.unimi.dsi.big.webgraph.ImmutableGraph; -import it.unimi.dsi.big.webgraph.LazyLongIterator; -import it.unimi.dsi.bits.LongArrayBitVector; -import it.unimi.dsi.fastutil.Arrays; -import it.unimi.dsi.io.ByteDiskQueue; -import it.unimi.dsi.logging.ProgressLogger; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.softwareheritage.graph.SwhBidirectionalGraph; - -import java.io.File; -import java.io.IOException; - -public class BFS { - private final static Logger LOGGER = LoggerFactory.getLogger(BFS.class); - private final ImmutableGraph graph; - - public BFS(ImmutableGraph graph) { - this.graph = graph; - } - - private static JSAPResult parse_args(String[] args) { - JSAPResult config = null; - try { - SimpleJSAP jsap = new SimpleJSAP(BFS.class.getName(), "", - new Parameter[]{ - new FlaggedOption("graphPath", JSAP.STRING_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, 'g', - "graph", "Basename of the compressed graph"), - - new FlaggedOption("useTransposed", JSAP.BOOLEAN_PARSER, "false", JSAP.NOT_REQUIRED, 'T', - "transposed", "Use transposed graph (default: false)"),}); - - config = jsap.parse(args); - if (jsap.messagePrinted()) { - System.exit(1); - } - } catch (JSAPException e) { - e.printStackTrace(); - } - return config; - } - - public static void main(String[] args) throws IOException { - JSAPResult config = parse_args(args); - String graphPath = config.getString("graphPath"); - boolean useTransposed = config.getBoolean("useTransposed"); - - System.err.println("Loading graph " + graphPath + " ..."); - SwhBidirectionalGraph graph = SwhBidirectionalGraph.loadMapped(graphPath); - System.err.println("Graph loaded."); - - if (useTransposed) - graph = graph.transpose(); - - BFS bfs = new BFS(graph); - bfs.bfsperm(); - } - - // Partly inlined from it.unimi.dsi.law.big.graph.BFS - private void bfsperm() throws IOException { - final long n = graph.numNodes(); - // Allow enough memory to behave like in-memory queue - int bufferSize = (int) Math.min(Arrays.MAX_ARRAY_SIZE & ~0x7, 8L * n); - - // Use a disk based queue to store BFS frontier - final File queueFile = File.createTempFile(BFS.class.getSimpleName(), "queue"); - final ByteDiskQueue queue = ByteDiskQueue.createNew(queueFile, bufferSize, true); - final byte[] byteBuf = new byte[Long.BYTES]; - // WARNING: no 64-bit version of this data-structure, but it can support - // indices up to 2^37 - final LongArrayBitVector visited = LongArrayBitVector.ofLength(n); - final ProgressLogger pl = new ProgressLogger(LOGGER); - pl.expectedUpdates = n; - pl.itemsName = "nodes"; - pl.start("Starting breadth-first visit..."); - - for (long i = 0; i < n; i++) { - if (visited.getBoolean(i)) - continue; - queue.enqueue(Longs.toByteArray(i)); - visited.set(i); - - while (!queue.isEmpty()) { - queue.dequeue(byteBuf); - final long currentNode = Longs.fromByteArray(byteBuf); - - final LazyLongIterator iterator = graph.successors(currentNode); - long succ; - while ((succ = iterator.nextLong()) != -1) { - if (!visited.getBoolean(succ)) { - visited.set(succ); - queue.enqueue(Longs.toByteArray(succ)); - } - } - - pl.update(); - } - } - - pl.done(); - queue.close(); - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/Benchmark.java b/java/src/main/java/org/softwareheritage/graph/benchmark/Benchmark.java deleted file mode 100644 index 591c7d5..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/Benchmark.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.softwareheritage.graph.benchmark; - -import com.martiansoftware.jsap.*; -import org.softwareheritage.graph.SwhBidirectionalGraph; -import org.softwareheritage.graph.SWHID; -import org.softwareheritage.graph.benchmark.utils.Random; -import org.softwareheritage.graph.benchmark.utils.Statistics; -import org.softwareheritage.graph.server.Endpoint; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.StringJoiner; -import java.util.function.Function; - -/** - * Benchmark common utility functions. - * - * @author The Software Heritage developers - */ - -public class Benchmark { - /** CSV separator for log file */ - final String CSV_SEPARATOR = ";"; - /** Command line arguments */ - public Args args; - /** - * Constructor. - */ - public Benchmark() { - this.args = new Args(); - } - - /** - * Parses benchmark command line arguments. - * - * @param args command line arguments - */ - public void parseCommandLineArgs(String[] args) throws JSAPException { - SimpleJSAP jsap = new SimpleJSAP(Benchmark.class.getName(), - "Benchmark tool for Software Heritage use-cases scenarios.", - new Parameter[]{ - new UnflaggedOption("graphPath", JSAP.STRING_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, - JSAP.NOT_GREEDY, "The basename of the compressed graph."), - new FlaggedOption("nbNodes", JSAP.INTEGER_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, 'n', - "nb-nodes", "Number of random nodes used to do the benchmark."), - new FlaggedOption("logFile", JSAP.STRING_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, 'l', - "log-file", "File name to output CSV format benchmark log."), - new FlaggedOption("seed", JSAP.LONG_PARSER, JSAP.NO_DEFAULT, JSAP.NOT_REQUIRED, 's', "seed", - "Random generator seed."),}); - - JSAPResult config = jsap.parse(args); - if (jsap.messagePrinted()) { - System.exit(1); - } - - this.args.graphPath = config.getString("graphPath"); - this.args.nbNodes = config.getInt("nbNodes"); - this.args.logFile = config.getString("logFile"); - this.args.random = config.contains("seed") ? new Random(config.getLong("seed")) : new Random(); - } - - /** - * Creates CSV file for log output. - */ - public void createCSVLogFile() throws IOException { - try (Writer csvLog = new BufferedWriter(new FileWriter(args.logFile))) { - StringJoiner csvHeader = new StringJoiner(CSV_SEPARATOR); - csvHeader.add("use case name").add("SWHID").add("number of edges accessed").add("traversal timing") - .add("swhid2node timing").add("node2swhid timing"); - csvLog.write(csvHeader.toString() + "\n"); - } - } - - /** - * Times a specific endpoint and outputs individual datapoints along with aggregated statistics. - * - * @param useCaseName benchmark use-case name - * @param graph compressed graph used in the benchmark - * @param nodeIds node ids to use as starting point for the endpoint traversal - * @param operation endpoint function to benchmark - * @param dstFmt destination formatted string as described in the - * API - * @param algorithm traversal algorithm used in endpoint call (either "dfs" or "bfs") - */ - public void timeEndpoint(String useCaseName, SwhBidirectionalGraph graph, long[] nodeIds, - Function operation, String dstFmt, String algorithm) throws IOException { - ArrayList timings = new ArrayList<>(); - ArrayList timingsNormalized = new ArrayList<>(); - ArrayList nbEdgesAccessed = new ArrayList<>(); - - final boolean append = true; - try (Writer csvLog = new BufferedWriter(new FileWriter(args.logFile, append))) { - for (long nodeId : nodeIds) { - SWHID swhid = graph.getSWHID(nodeId); - - Endpoint.Output output = (dstFmt == null) - ? operation.apply(new Endpoint.Input(swhid)) - : operation.apply(new Endpoint.Input(swhid, dstFmt, algorithm)); - - StringJoiner csvLine = new StringJoiner(CSV_SEPARATOR); - csvLine.add(useCaseName).add(swhid.toString()).add(Long.toString(output.meta.nbEdgesAccessed)) - .add(Double.toString(output.meta.timings.traversal)) - .add(Double.toString(output.meta.timings.swhid2node)) - .add(Double.toString(output.meta.timings.node2swhid)); - csvLog.write(csvLine.toString() + "\n"); - - timings.add(output.meta.timings.traversal); - nbEdgesAccessed.add((double) output.meta.nbEdgesAccessed); - if (output.meta.nbEdgesAccessed != 0) { - timingsNormalized.add(output.meta.timings.traversal / output.meta.nbEdgesAccessed); - } - } - } - - System.out.println("\n" + useCaseName + " use-case:"); - - System.out.println("timings:"); - Statistics stats = new Statistics(timings); - stats.printAll(); - - System.out.println("timings normalized:"); - Statistics statsNormalized = new Statistics(timingsNormalized); - statsNormalized.printAll(); - - System.out.println("nb edges accessed:"); - Statistics statsNbEdgesAccessed = new Statistics(nbEdgesAccessed); - statsNbEdgesAccessed.printAll(); - } - - /** - * Same as {@link #timeEndpoint} but without destination or algorithm specified to endpoint call. - */ - public void timeEndpoint(String useCaseName, SwhBidirectionalGraph graph, long[] nodeIds, - Function operation) throws IOException { - timeEndpoint(useCaseName, graph, nodeIds, operation, null, null); - } - - /** - * Input arguments. - */ - public class Args { - /** Basename of the compressed graph */ - public String graphPath; - /** Number of random nodes to use for the benchmark */ - public int nbNodes; - /** File name for CSV format benchmark log */ - public String logFile; - /** Random generator */ - public Random random; - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/Browsing.java b/java/src/main/java/org/softwareheritage/graph/benchmark/Browsing.java deleted file mode 100644 index 61b5cbf..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/Browsing.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.softwareheritage.graph.benchmark; - -import com.martiansoftware.jsap.JSAPException; -import org.softwareheritage.graph.SwhBidirectionalGraph; -import org.softwareheritage.graph.Node; -import org.softwareheritage.graph.server.Endpoint; - -import java.io.IOException; - -/** - * Benchmark Software Heritage - * browsing - * use-cases scenarios. - * - * @author The Software Heritage developers - */ - -public class Browsing { - /** - * Main entrypoint. - * - * @param args command line arguments - */ - public static void main(String[] args) throws IOException, JSAPException { - Benchmark bench = new Benchmark(); - bench.parseCommandLineArgs(args); - - SwhBidirectionalGraph graph = SwhBidirectionalGraph.loadMapped(bench.args.graphPath); - - long[] dirNodeIds = bench.args.random.generateNodeIdsOfType(graph, bench.args.nbNodes, Node.Type.DIR); - long[] revNodeIds = bench.args.random.generateNodeIdsOfType(graph, bench.args.nbNodes, Node.Type.REV); - - Endpoint dirEndpoint = new Endpoint(graph, "forward", "dir:cnt,dir:dir"); - Endpoint revEndpoint = new Endpoint(graph, "forward", "rev:rev"); - - System.out.println("Used " + bench.args.nbNodes + " random nodes (results are in seconds):"); - bench.createCSVLogFile(); - bench.timeEndpoint("ls", graph, dirNodeIds, dirEndpoint::neighbors); - bench.timeEndpoint("ls -R", graph, dirNodeIds, dirEndpoint::visitPaths); - bench.timeEndpoint("git log", graph, revNodeIds, revEndpoint::visitNodes); - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/Provenance.java b/java/src/main/java/org/softwareheritage/graph/benchmark/Provenance.java deleted file mode 100644 index 960ef5f..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/Provenance.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.softwareheritage.graph.benchmark; - -import com.martiansoftware.jsap.JSAPException; -import org.softwareheritage.graph.SwhBidirectionalGraph; -import org.softwareheritage.graph.server.Endpoint; - -import java.io.IOException; - -/** - * Benchmark Software Heritage - * provenance - * use-cases scenarios. - * - * @author The Software Heritage developers - */ - -public class Provenance { - /** - * Main entrypoint. - * - * @param args command line arguments - */ - public static void main(String[] args) throws IOException, JSAPException { - Benchmark bench = new Benchmark(); - bench.parseCommandLineArgs(args); - - SwhBidirectionalGraph graph = SwhBidirectionalGraph.loadMapped(bench.args.graphPath); - - long[] nodeIds = bench.args.random.generateNodeIds(graph, bench.args.nbNodes); - - Endpoint commitProvenanceEndpoint = new Endpoint(graph, "backward", "dir:dir,cnt:dir,dir:rev"); - Endpoint originProvenanceEndpoint = new Endpoint(graph, "backward", "*"); - - System.out.println("Used " + bench.args.nbNodes + " random nodes (results are in seconds):"); - bench.createCSVLogFile(); - - bench.timeEndpoint("commit provenance (dfs)", graph, nodeIds, commitProvenanceEndpoint::walk, "rev", "dfs"); - bench.timeEndpoint("commit provenance (bfs)", graph, nodeIds, commitProvenanceEndpoint::walk, "rev", "bfs"); - bench.timeEndpoint("complete commit provenance", graph, nodeIds, commitProvenanceEndpoint::leaves); - - bench.timeEndpoint("origin provenance (dfs)", graph, nodeIds, originProvenanceEndpoint::walk, "ori", "dfs"); - bench.timeEndpoint("origin provenance (bfs)", graph, nodeIds, originProvenanceEndpoint::walk, "ori", "bfs"); - bench.timeEndpoint("complete origin provenance", graph, nodeIds, originProvenanceEndpoint::leaves); - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/Vault.java b/java/src/main/java/org/softwareheritage/graph/benchmark/Vault.java deleted file mode 100644 index 9403047..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/Vault.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.softwareheritage.graph.benchmark; - -import com.martiansoftware.jsap.JSAPException; -import org.softwareheritage.graph.SwhBidirectionalGraph; -import org.softwareheritage.graph.server.Endpoint; - -import java.io.IOException; - -/** - * Benchmark Software Heritage - * vault use-case - * scenario. - * - * @author The Software Heritage developers - */ - -public class Vault { - /** - * Main entrypoint. - * - * @param args command line arguments - */ - public static void main(String[] args) throws IOException, JSAPException { - Benchmark bench = new Benchmark(); - bench.parseCommandLineArgs(args); - - SwhBidirectionalGraph graph = SwhBidirectionalGraph.loadMapped(bench.args.graphPath); - - long[] nodeIds = bench.args.random.generateNodeIds(graph, bench.args.nbNodes); - - Endpoint endpoint = new Endpoint(graph, "forward", "*"); - - System.out.println("Used " + bench.args.nbNodes + " random nodes (results are in seconds):"); - bench.createCSVLogFile(); - bench.timeEndpoint("git bundle", graph, nodeIds, endpoint::visitNodes); - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Random.java b/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Random.java deleted file mode 100644 index 8ee0b63..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Random.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.softwareheritage.graph.benchmark.utils; - -import org.softwareheritage.graph.SwhBidirectionalGraph; -import org.softwareheritage.graph.Node; - -import java.util.PrimitiveIterator; - -/** - * Random related utility class. - * - * @author The Software Heritage developers - */ - -public class Random { - /** Internal pseudorandom generator */ - java.util.Random random; - - /** - * Constructor. - */ - public Random() { - this.random = new java.util.Random(); - } - - /** - * Constructor. - * - * @param seed random generator seed - */ - public Random(long seed) { - this.random = new java.util.Random(seed); - } - - /** - * Generates random node ids. - * - * @param graph graph used to pick node ids - * @param nbNodes number of node ids to generate - * @return an array of random node ids - */ - public long[] generateNodeIds(SwhBidirectionalGraph graph, int nbNodes) { - return random.longs(nbNodes, 0, graph.numNodes()).toArray(); - } - - /** - * Generates random node ids with a specific type. - * - * @param graph graph used to pick node ids - * @param nbNodes number of node ids to generate - * @param expectedType specific node type to pick - * @return an array of random node ids - */ - public long[] generateNodeIdsOfType(SwhBidirectionalGraph graph, int nbNodes, Node.Type expectedType) { - PrimitiveIterator.OfLong nodes = random.longs(0, graph.numNodes()).iterator(); - long[] nodeIds = new long[nbNodes]; - - long nextId; - for (int i = 0; i < nbNodes; i++) { - do { - nextId = nodes.nextLong(); - } while (graph.getNodeType(nextId) != expectedType); - nodeIds[i] = nextId; - } - - return nodeIds; - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Statistics.java b/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Statistics.java deleted file mode 100644 index 96bdfd0..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Statistics.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.softwareheritage.graph.benchmark.utils; - -import java.util.ArrayList; -import java.util.Collections; - -/** - * Compute various statistics on a list of values. - * - * @author The Software Heritage developers - */ - -public class Statistics { - /** Input values */ - ArrayList values; - - /** - * Constructor. - * - * @param values input values - */ - public Statistics(ArrayList values) { - this.values = values; - } - - /** - * Returns the minimum value. - * - * @return minimum value - */ - public double getMin() { - double min = Double.POSITIVE_INFINITY; - for (double v : values) { - min = Math.min(min, v); - } - return min; - } - - /** - * Returns the maximum value. - * - * @return maximum value - */ - public double getMax() { - double max = Double.NEGATIVE_INFINITY; - for (double v : values) { - max = Math.max(max, v); - } - return max; - } - - /** - * Computes the average. - * - * @return average value - */ - public double getAverage() { - double sum = 0; - for (double v : values) { - sum += v; - } - return sum / (double) values.size(); - } - - /** - * Returns the median value. - * - * @return median value - */ - public double getMedian() { - Collections.sort(values); - int length = values.size(); - if (length % 2 == 0) { - return (values.get(length / 2) + values.get(length / 2 - 1)) / 2; - } else { - return values.get(length / 2); - } - } - - /** - * Computes the standard deviation. - * - * @return standard deviation value - */ - public double getStandardDeviation() { - double average = getAverage(); - double variance = 0; - for (double v : values) { - variance += (v - average) * (v - average); - } - variance /= (double) values.size(); - return Math.sqrt(variance); - } - - /** - * Computes and prints all statistical values. - */ - public void printAll() { - System.out.println("min value: " + getMin()); - System.out.println("max value: " + getMax()); - System.out.println("average: " + getAverage()); - System.out.println("median: " + getMedian()); - System.out.println("standard deviation: " + getStandardDeviation()); - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Timing.java b/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Timing.java deleted file mode 100644 index de5de6c..0000000 --- a/java/src/main/java/org/softwareheritage/graph/benchmark/utils/Timing.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.softwareheritage.graph.benchmark.utils; - -/** - * Time measurement utility class. - * - * @author The Software Heritage developers - */ - -public class Timing { - /** - * Returns measurement starting timestamp. - * - * @return timestamp used for time measurement - */ - public static long start() { - return System.nanoTime(); - } - - /** - * Ends timing measurement and returns total duration in seconds. - * - * @param startTime measurement starting timestamp - * @return time in seconds elapsed since starting point - */ - public static double stop(long startTime) { - long endTime = System.nanoTime(); - double duration = (double) (endTime - startTime) / 1_000_000_000; - return duration; - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/experiments/multiplicationfactor/GenDistribution.java b/java/src/main/java/org/softwareheritage/graph/experiments/multiplicationfactor/GenDistribution.java index e3fdb3b..8d5e5fa 100644 --- a/java/src/main/java/org/softwareheritage/graph/experiments/multiplicationfactor/GenDistribution.java +++ b/java/src/main/java/org/softwareheritage/graph/experiments/multiplicationfactor/GenDistribution.java @@ -1,130 +1,130 @@ package org.softwareheritage.graph.experiments.multiplicationfactor; import com.martiansoftware.jsap.*; import org.softwareheritage.graph.SwhBidirectionalGraph; import org.softwareheritage.graph.Node; import org.softwareheritage.graph.Traversal; -import org.softwareheritage.graph.benchmark.utils.Timing; import java.io.IOException; import java.util.Scanner; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class GenDistribution { private SwhBidirectionalGraph graph; private static JSAPResult parse_args(String[] args) { JSAPResult config = null; try { SimpleJSAP jsap = new SimpleJSAP(GenDistribution.class.getName(), "", new Parameter[]{ new FlaggedOption("graphPath", JSAP.STRING_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, 'g', "graph", "Basename of the compressed graph"), new FlaggedOption("srcType", JSAP.STRING_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, 's', "srctype", "Source node type"), new FlaggedOption("dstType", JSAP.STRING_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, 'd', "dsttype", "Destination node type"), new FlaggedOption("edgesFmt", JSAP.STRING_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, 'e', "edges", "Edges constraints"), new FlaggedOption("numThreads", JSAP.INTEGER_PARSER, "128", JSAP.NOT_REQUIRED, 't', "numthreads", "Number of threads"),}); config = jsap.parse(args); if (jsap.messagePrinted()) { System.exit(1); } } catch (JSAPException e) { e.printStackTrace(); } return config; } public static void main(String[] args) { JSAPResult config = parse_args(args); String graphPath = config.getString("graphPath"); Node.Type srcType = Node.Type.fromStr(config.getString("srcType")); Node.Type dstType = Node.Type.fromStr(config.getString("dstType")); String edgesFmt = config.getString("edgesFmt"); int numThreads = config.getInt("numThreads"); GenDistribution tp = new GenDistribution(); try { tp.load_graph(graphPath); } catch (IOException e) { System.out.println("Could not load graph: " + e); System.exit(2); } final long END_OF_QUEUE = -1L; ArrayBlockingQueue queue = new ArrayBlockingQueue<>(numThreads); ExecutorService service = Executors.newFixedThreadPool(numThreads + 1); service.submit(() -> { try { Scanner input = new Scanner(System.in); while (input.hasNextLong()) { long node = input.nextLong(); if (tp.graph.getNodeType(node) == srcType) { queue.put(node); } } } catch (InterruptedException e) { e.printStackTrace(); } finally { for (int i = 0; i < numThreads; ++i) { try { queue.put(END_OF_QUEUE); } catch (InterruptedException e) { e.printStackTrace(); } } } }); for (int i = 0; i < numThreads; ++i) { service.submit(() -> { SwhBidirectionalGraph thread_graph = tp.graph.copy(); long startTime; double totalTime; while (true) { Long node = null; try { node = queue.take(); } catch (InterruptedException e) { e.printStackTrace(); } if (node == null || node == END_OF_QUEUE) { return; } Traversal t = new Traversal(thread_graph, "backward", edgesFmt); int[] count = {0}; - startTime = Timing.start(); + startTime = System.nanoTime(); t.visitNodesVisitor(node, (curnode) -> { if (tp.graph.getNodeType(curnode) == dstType) { count[0]++; } }); - totalTime = Timing.stop(startTime); + long endTime = System.nanoTime(); + totalTime = (double) (endTime - startTime) / 1e9; System.out.format("%d %d %d %d %f\n", node, count[0], t.getNbNodesAccessed(), t.getNbEdgesAccessed(), totalTime); } }); } service.shutdown(); } private void load_graph(String graphBasename) throws IOException { System.err.println("Loading graph " + graphBasename + " ..."); this.graph = SwhBidirectionalGraph.loadMapped(graphBasename); System.err.println("Graph loaded."); } } diff --git a/java/src/main/java/org/softwareheritage/graph/server/App.java b/java/src/main/java/org/softwareheritage/graph/server/App.java deleted file mode 100644 index 9849310..0000000 --- a/java/src/main/java/org/softwareheritage/graph/server/App.java +++ /dev/null @@ -1,196 +0,0 @@ -package org.softwareheritage.graph.server; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; -import com.martiansoftware.jsap.*; -import io.javalin.Javalin; -import io.javalin.http.Context; -import io.javalin.plugin.json.JavalinJackson; -import org.softwareheritage.graph.SwhBidirectionalGraph; -import org.softwareheritage.graph.Stats; -import org.softwareheritage.graph.SWHID; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -/** - * Web framework of the swh-graph server RPC API. - * - * @author The Software Heritage developers - */ - -public class App { - /** - * Main entrypoint. - * - * @param args command line arguments - */ - public static void main(String[] args) throws IOException, JSAPException { - SimpleJSAP jsap = new SimpleJSAP(App.class.getName(), - "Server to load and query a compressed graph representation of Software Heritage archive.", - new Parameter[]{ - new FlaggedOption("port", JSAP.INTEGER_PARSER, "5009", JSAP.NOT_REQUIRED, 'p', "port", - "Binding port of the server."), - new UnflaggedOption("graphPath", JSAP.STRING_PARSER, JSAP.NO_DEFAULT, JSAP.REQUIRED, - JSAP.NOT_GREEDY, "The basename of the compressed graph."), - new Switch("timings", 't', "timings", "Show timings in API result metadata."),}); - - JSAPResult config = jsap.parse(args); - if (jsap.messagePrinted()) { - System.exit(1); - } - - String graphPath = config.getString("graphPath"); - int port = config.getInt("port"); - boolean showTimings = config.getBoolean("timings"); - - startServer(graphPath, port, showTimings); - } - - /** - * Loads compressed graph and starts the web server to query it. - * - * @param graphPath basename of the compressed graph - * @param port binding port of the server - * @param showTimings true if timings should be in results metadata, false otherwise - */ - private static void startServer(String graphPath, int port, boolean showTimings) throws IOException { - SwhBidirectionalGraph graph = SwhBidirectionalGraph.loadMapped(graphPath); - Stats stats = new Stats(graphPath); - - // Clean up on exit - Runtime.getRuntime().addShutdownHook(new Thread() { - public void run() { - try { - graph.close(); - } 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(port); - - 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", "*"); - - Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); - Endpoint.Output output = endpoint.leaves(new Endpoint.Input(src)); - ctx.json(formatEndpointOutput(output, showTimings)); - }); - - app.get("/neighbors/:src", ctx -> { - SWHID src = new SWHID(ctx.pathParam("src")); - String direction = ctx.queryParam("direction", "forward"); - String edgesFmt = ctx.queryParam("edges", "*"); - - Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); - Endpoint.Output output = endpoint.neighbors(new Endpoint.Input(src)); - ctx.json(formatEndpointOutput(output, showTimings)); - }); - - app.get("/visit/nodes/:src", ctx -> { - SWHID src = new SWHID(ctx.pathParam("src")); - String direction = ctx.queryParam("direction", "forward"); - String edgesFmt = ctx.queryParam("edges", "*"); - - Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); - Endpoint.Output output = endpoint.visitNodes(new Endpoint.Input(src)); - ctx.json(formatEndpointOutput(output, showTimings)); - }); - - app.get("/visit/paths/:src", ctx -> { - SWHID src = new SWHID(ctx.pathParam("src")); - String direction = ctx.queryParam("direction", "forward"); - String edgesFmt = ctx.queryParam("edges", "*"); - - Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); - Endpoint.Output output = endpoint.visitPaths(new Endpoint.Input(src)); - ctx.json(formatEndpointOutput(output, showTimings)); - }); - - 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"); - - Endpoint endpoint = new Endpoint(graph, direction, edgesFmt); - Endpoint.Output output = endpoint.walk(new Endpoint.Input(src, dstFmt, algorithm)); - ctx.json(formatEndpointOutput(output, showTimings)); - }); - - app.exception(IllegalArgumentException.class, (e, ctx) -> { - ctx.status(400); - ctx.result(e.getMessage()); - }); - } - - /** - * Checks query strings names provided to the RPC API. - * - * @param ctx Javalin HTTP request context - * @param allowedFmt a regular expression describing allowed query strings names - * @throws IllegalArgumentException unknown query string provided - */ - 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); - } - } - } - - /** - * Formats endpoint result into final JSON for the RPC API. - *

- * Removes unwanted information if necessary, such as timings (to prevent use of side channels - * attacks). - * - * @param output endpoint operation output which needs formatting - * @param showTimings true if timings should be in results metadata, false otherwise - * @return final Object with desired JSON format - */ - private static Object formatEndpointOutput(Endpoint.Output output, boolean showTimings) { - if (showTimings) { - return output; - } else { - Map metaNoTimings = Map.of("nb_edges_accessed", output.meta.nbEdgesAccessed); - Map outputNoTimings = Map.of("result", output.result, "meta", metaNoTimings); - return outputNoTimings; - } - } -} diff --git a/java/src/main/java/org/softwareheritage/graph/server/Endpoint.java b/java/src/main/java/org/softwareheritage/graph/server/Endpoint.java deleted file mode 100644 index d1055e4..0000000 --- a/java/src/main/java/org/softwareheritage/graph/server/Endpoint.java +++ /dev/null @@ -1,309 +0,0 @@ -package org.softwareheritage.graph.server; - -import org.softwareheritage.graph.*; -import org.softwareheritage.graph.benchmark.utils.Timing; - -import java.util.ArrayList; - -/** - * RPC API endpoints wrapper functions. - *

- * Graph operations are segmented between high-level class (this one) and the low-level class - * ({@link Traversal}). The {@link Endpoint} class creates wrappers for each endpoints by performing - * all the input/output node ids conversions and logging timings. - * - * @author The Software Heritage developers - * @see Traversal - */ - -public class Endpoint { - /** Graph where traversal endpoint is performed */ - SwhBidirectionalGraph graph; - /** Internal traversal API */ - Traversal traversal; - - /** - * Constructor. - * - * @param graph the graph used for traversal endpoint - * @param direction a string (either "forward" or "backward") specifying edge orientation - * @param edgesFmt a formatted string describing allowed - * edges - */ - public Endpoint(SwhBidirectionalGraph graph, String direction, String edgesFmt) { - this.graph = graph; - this.traversal = new Traversal(graph, direction, edgesFmt); - } - - /** - * Converts a list of (internal) long node ids to a list of corresponding (external) SWHIDs. - * - * @param nodeIds the list of long node ids - * @return a list of corresponding SWHIDs - */ - private ArrayList convertNodesToSWHIDs(ArrayList nodeIds) { - ArrayList swhids = new ArrayList<>(); - for (long nodeId : nodeIds) { - swhids.add(graph.getSWHID(nodeId)); - } - return swhids; - } - - /** - * Converts a list of (internal) long node ids to the corresponding {@link SwhPath}. - * - * @param nodeIds the list of long node ids - * @return the corresponding {@link SwhPath} - * @see org.softwareheritage.graph.SwhPath - */ - private SwhPath convertNodesToSwhPath(ArrayList nodeIds) { - SwhPath path = new SwhPath(); - for (long nodeId : nodeIds) { - path.add(graph.getSWHID(nodeId)); - } - return path; - } - - /** - * Converts a list of paths made of (internal) long node ids to one made of {@link SwhPath}-s. - * - * @param pathsNodeId the list of paths with long node ids - * @return a list of corresponding {@link SwhPath} - * @see org.softwareheritage.graph.SwhPath - */ - private ArrayList convertPathsToSWHIDs(ArrayList> pathsNodeId) { - ArrayList paths = new ArrayList<>(); - for (ArrayList path : pathsNodeId) { - paths.add(convertNodesToSwhPath(path)); - } - return paths; - } - - /** - * Leaves endpoint wrapper. - * - * @param input input parameters for the underlying endpoint call - * @return the resulting list of {@link SWHID} from endpoint call and operation metadata - * @see SWHID - * @see Traversal#leaves(long) - */ - public Output leaves(Input input) { - Output> output = new Output<>(); - long startTime; - - startTime = Timing.start(); - long srcNodeId = graph.getNodeId(input.src); - output.meta.timings.swhid2node = Timing.stop(startTime); - - startTime = Timing.start(); - ArrayList nodeIds = traversal.leaves(srcNodeId); - output.meta.timings.traversal = Timing.stop(startTime); - output.meta.nbEdgesAccessed = traversal.getNbEdgesAccessed(); - - startTime = Timing.start(); - output.result = convertNodesToSWHIDs(nodeIds); - output.meta.timings.node2swhid = Timing.stop(startTime); - - return output; - } - - /** - * Neighbors endpoint wrapper. - * - * @param input input parameters for the underlying endpoint call - * @return the resulting list of {@link SWHID} from endpoint call and operation metadata - * @see SWHID - * @see Traversal#neighbors(long) - */ - public Output neighbors(Input input) { - Output> output = new Output<>(); - long startTime; - - startTime = Timing.start(); - long srcNodeId = graph.getNodeId(input.src); - output.meta.timings.swhid2node = Timing.stop(startTime); - - startTime = Timing.start(); - ArrayList nodeIds = traversal.neighbors(srcNodeId); - output.meta.timings.traversal = Timing.stop(startTime); - output.meta.nbEdgesAccessed = traversal.getNbEdgesAccessed(); - - startTime = Timing.start(); - output.result = convertNodesToSWHIDs(nodeIds); - output.meta.timings.node2swhid = Timing.stop(startTime); - - return output; - } - - /** - * Walk endpoint wrapper. - * - * @param input input parameters for the underlying endpoint call - * @return the resulting {@link SwhPath} from endpoint call and operation metadata - * @see SWHID - * @see org.softwareheritage.graph.SwhPath - * @see Traversal#walk - */ - public Output walk(Input input) { - Output output = new Output<>(); - long startTime; - - startTime = Timing.start(); - long srcNodeId = graph.getNodeId(input.src); - output.meta.timings.swhid2node = Timing.stop(startTime); - - ArrayList nodeIds = new ArrayList(); - - // Destination is either a SWHID or a node type - try { - SWHID dstSWHID = new SWHID(input.dstFmt); - long dstNodeId = graph.getNodeId(dstSWHID); - - startTime = Timing.start(); - nodeIds = traversal.walk(srcNodeId, dstNodeId, input.algorithm); - output.meta.timings.traversal = Timing.stop(startTime); - } catch (IllegalArgumentException ignored1) { - try { - Node.Type dstType = Node.Type.fromStr(input.dstFmt); - - startTime = Timing.start(); - nodeIds = traversal.walk(srcNodeId, dstType, input.algorithm); - output.meta.timings.traversal = Timing.stop(startTime); - } catch (IllegalArgumentException ignored2) { - } - } - - output.meta.nbEdgesAccessed = traversal.getNbEdgesAccessed(); - - startTime = Timing.start(); - output.result = convertNodesToSwhPath(nodeIds); - output.meta.timings.node2swhid = Timing.stop(startTime); - - return output; - } - - /** - * VisitNodes endpoint wrapper. - * - * @param input input parameters for the underlying endpoint call - * @return the resulting list of {@link SWHID} from endpoint call and operation metadata - * @see SWHID - * @see Traversal#visitNodes(long) - */ - public Output visitNodes(Input input) { - Output> output = new Output<>(); - long startTime; - - startTime = Timing.start(); - long srcNodeId = graph.getNodeId(input.src); - output.meta.timings.swhid2node = Timing.stop(startTime); - - startTime = Timing.start(); - ArrayList nodeIds = traversal.visitNodes(srcNodeId); - output.meta.timings.traversal = Timing.stop(startTime); - output.meta.nbEdgesAccessed = traversal.getNbEdgesAccessed(); - - startTime = Timing.start(); - output.result = convertNodesToSWHIDs(nodeIds); - output.meta.timings.node2swhid = Timing.stop(startTime); - - return output; - } - - /** - * VisitPaths endpoint wrapper. - * - * @param input input parameters for the underlying endpoint call - * @return the resulting list of {@link SwhPath} from endpoint call and operation metadata - * @see SWHID - * @see org.softwareheritage.graph.SwhPath - * @see Traversal#visitPaths(long) - */ - public Output visitPaths(Input input) { - Output> output = new Output<>(); - long startTime; - - startTime = Timing.start(); - long srcNodeId = graph.getNodeId(input.src); - output.meta.timings.swhid2node = Timing.stop(startTime); - - startTime = Timing.start(); - ArrayList> paths = traversal.visitPaths(srcNodeId); - output.meta.timings.traversal = Timing.stop(startTime); - output.meta.nbEdgesAccessed = traversal.getNbEdgesAccessed(); - - startTime = Timing.start(); - output.result = convertPathsToSWHIDs(paths); - output.meta.timings.node2swhid = Timing.stop(startTime); - - return output; - } - - /** - * Wrapper class to unify traversal methods input signatures. - */ - public static class Input { - /** Source node of endpoint call specified as a {@link SWHID} */ - public SWHID src; - /** - * Destination formatted string as described in the - * API - */ - public String dstFmt; - /** Traversal algorithm used in endpoint call (either "dfs" or "bfs") */ - public String algorithm; - - public Input(SWHID src) { - this.src = src; - } - - public Input(SWHID src, String dstFmt, String algorithm) { - this.src = src; - this.dstFmt = dstFmt; - this.algorithm = algorithm; - } - } - - /** - * Wrapper class to return both the endpoint result and metadata (such as timings). - */ - public static class Output { - /** The result content itself */ - public T result; - /** Various metadata about the result */ - public Meta meta; - - public Output() { - this.result = null; - this.meta = new Meta(); - } - - /** - * Endpoint result metadata. - */ - public class Meta { - /** Operations timings */ - public Timings timings; - /** Number of edges accessed during traversal */ - public long nbEdgesAccessed; - - public Meta() { - this.timings = new Timings(); - this.nbEdgesAccessed = 0; - } - - /** - * Wrapper class for JSON output format. - */ - public class Timings { - /** Time in seconds to do the traversal */ - public double traversal; - /** Time in seconds to convert input SWHID to node id */ - public double swhid2node; - /** Time in seconds to convert output node ids to SWHIDs */ - public double node2swhid; - } - } - } -} diff --git a/java/src/test/java/org/softwareheritage/graph/GraphTest.java b/java/src/test/java/org/softwareheritage/graph/GraphTest.java index e047f68..94df365 100644 --- a/java/src/test/java/org/softwareheritage/graph/GraphTest.java +++ b/java/src/test/java/org/softwareheritage/graph/GraphTest.java @@ -1,56 +1,60 @@ package org.softwareheritage.graph; import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.Iterator; import com.github.luben.zstd.ZstdInputStream; import it.unimi.dsi.big.webgraph.LazyLongIterator; import it.unimi.dsi.big.webgraph.LazyLongIterators; -import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.BeforeAll; -import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; +import static org.junit.Assert.assertEquals; public class GraphTest { static SwhBidirectionalGraph graph; final protected String TEST_ORIGIN_ID = "swh:1:ori:83404f995118bd25774f4ac14422a8f175e7a054"; @BeforeAll public static void setUp() throws IOException { graph = SwhBidirectionalGraph.loadLabelled(getGraphPath().toString()); } public static Path getGraphPath() { return Paths.get("..", "swh", "graph", "tests", "dataset", "compressed", "example"); } public static SwhBidirectionalGraph getGraph() { return graph; } public static SWHID fakeSWHID(String type, int num) { return new SWHID(String.format("swh:1:%s:%040d", type, num)); } - public static void assertEqualsAnyOrder(Collection expecteds, Collection actuals) { - MatcherAssert.assertThat(expecteds, containsInAnyOrder(actuals.toArray())); + public static void assertEqualsAnyOrder(Collection expected, Collection actual) { + ArrayList expectedList = new ArrayList<>(expected); + ArrayList actualList = new ArrayList<>(actual); + expectedList.sort(Comparator.comparing(Object::toString)); + actualList.sort(Comparator.comparing(Object::toString)); + assertEquals(expectedList, actualList); } public static ArrayList lazyLongIteratorToList(LazyLongIterator input) { ArrayList inputList = new ArrayList<>(); Iterator inputIt = LazyLongIterators.eager(input); inputIt.forEachRemaining(inputList::add); return inputList; } public static String[] readZstFile(Path zstFile) throws IOException { ZstdInputStream zis = new ZstdInputStream(new FileInputStream(zstFile.toFile())); return (new String(zis.readAllBytes())).split("\n"); } } diff --git a/java/src/test/java/org/softwareheritage/graph/LeavesTest.java b/java/src/test/java/org/softwareheritage/graph/LeavesTest.java deleted file mode 100644 index 1da30ad..0000000 --- a/java/src/test/java/org/softwareheritage/graph/LeavesTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.softwareheritage.graph; - -import java.util.ArrayList; - -import org.junit.jupiter.api.Test; -import org.softwareheritage.graph.server.Endpoint; - -// Avoid warnings concerning Endpoint.Output.result manual cast -@SuppressWarnings("unchecked") -public class LeavesTest extends GraphTest { - @Test - public void forwardFromSnp() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:snp:0000000000000000000000000000000000000020"); - 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")); - - ArrayList actualLeaves = (ArrayList) endpoint.leaves(new Endpoint.Input(src)).result; - GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves); - } - - @Test - public void forwardFromRel() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:rel:0000000000000000000000000000000000000019"); - 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")); - - ArrayList actualLeaves = (ArrayList) endpoint.leaves(new Endpoint.Input(src)).result; - GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves); - } - - @Test - public void backwardFromLeaf() { - SwhBidirectionalGraph graph = getGraph(); - - Endpoint endpoint1 = new Endpoint(graph, "backward", "*"); - SWHID src1 = new SWHID("swh:1:cnt:0000000000000000000000000000000000000015"); - ArrayList expectedLeaves1 = new ArrayList<>(); - expectedLeaves1.add(new SWHID("swh:1:rel:0000000000000000000000000000000000000019")); - ArrayList actualLeaves1 = (ArrayList) endpoint1.leaves(new Endpoint.Input(src1)).result; - GraphTest.assertEqualsAnyOrder(expectedLeaves1, actualLeaves1); - - Endpoint endpoint2 = new Endpoint(graph, "backward", "*"); - SWHID src2 = new SWHID("swh:1:cnt:0000000000000000000000000000000000000004"); - ArrayList expectedLeaves2 = new ArrayList<>(); - expectedLeaves2.add(new SWHID(TEST_ORIGIN_ID)); - expectedLeaves2.add(new SWHID("swh:1:rel:0000000000000000000000000000000000000019")); - ArrayList actualLeaves2 = (ArrayList) endpoint2.leaves(new Endpoint.Input(src2)).result; - GraphTest.assertEqualsAnyOrder(expectedLeaves2, actualLeaves2); - } - - @Test - public void forwardRevToRevOnly() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:rev:0000000000000000000000000000000000000018"); - Endpoint endpoint = new Endpoint(graph, "forward", "rev:rev"); - - ArrayList expectedLeaves = new ArrayList<>(); - expectedLeaves.add(new SWHID("swh:1:rev:0000000000000000000000000000000000000003")); - - ArrayList actualLeaves = (ArrayList) endpoint.leaves(new Endpoint.Input(src)).result; - GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves); - } - - @Test - public void forwardDirToAll() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:dir:0000000000000000000000000000000000000008"); - 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")); - - ArrayList actualLeaves = (ArrayList) endpoint.leaves(new Endpoint.Input(src)).result; - GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves); - } - - @Test - public void backwardCntToDirDirToDir() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:cnt:0000000000000000000000000000000000000005"); - Endpoint endpoint = new Endpoint(graph, "backward", "cnt:dir,dir:dir"); - - ArrayList expectedLeaves = new ArrayList<>(); - expectedLeaves.add(new SWHID("swh:1:dir:0000000000000000000000000000000000000012")); - - ArrayList actualLeaves = (ArrayList) endpoint.leaves(new Endpoint.Input(src)).result; - GraphTest.assertEqualsAnyOrder(expectedLeaves, actualLeaves); - } -} diff --git a/java/src/test/java/org/softwareheritage/graph/NeighborsTest.java b/java/src/test/java/org/softwareheritage/graph/NeighborsTest.java deleted file mode 100644 index 9c6225b..0000000 --- a/java/src/test/java/org/softwareheritage/graph/NeighborsTest.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.softwareheritage.graph; - -import java.util.ArrayList; - -import org.junit.jupiter.api.Test; -import org.softwareheritage.graph.server.Endpoint; - -// Avoid warnings concerning Endpoint.Output.result manual cast -@SuppressWarnings("unchecked") -public class NeighborsTest extends GraphTest { - @Test - public void zeroNeighbor() { - SwhBidirectionalGraph graph = getGraph(); - ArrayList expectedNodes = new ArrayList<>(); - - SWHID src1 = new SWHID(TEST_ORIGIN_ID); - Endpoint endpoint1 = new Endpoint(graph, "backward", "*"); - ArrayList actuals1 = (ArrayList) endpoint1.neighbors(new Endpoint.Input(src1)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes, actuals1); - - SWHID src2 = new SWHID("swh:1:cnt:0000000000000000000000000000000000000004"); - Endpoint endpoint2 = new Endpoint(graph, "forward", "*"); - ArrayList actuals2 = (ArrayList) endpoint2.neighbors(new Endpoint.Input(src2)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes, actuals2); - - SWHID src3 = new SWHID("swh:1:cnt:0000000000000000000000000000000000000015"); - Endpoint endpoint3 = new Endpoint(graph, "forward", "*"); - ArrayList actuals3 = (ArrayList) endpoint3.neighbors(new Endpoint.Input(src3)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes, actuals3); - - SWHID src4 = new SWHID("swh:1:rel:0000000000000000000000000000000000000019"); - Endpoint endpoint4 = new Endpoint(graph, "backward", "*"); - ArrayList actuals4 = (ArrayList) endpoint4.neighbors(new Endpoint.Input(src4)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes, actuals4); - - SWHID src5 = new SWHID("swh:1:dir:0000000000000000000000000000000000000008"); - Endpoint endpoint5 = new Endpoint(graph, "forward", "snp:*,rev:*,rel:*"); - ArrayList actuals5 = (ArrayList) endpoint5.neighbors(new Endpoint.Input(src5)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes, actuals5); - } - - @Test - public void oneNeighbor() { - SwhBidirectionalGraph graph = getGraph(); - - SWHID src1 = new SWHID("swh:1:rev:0000000000000000000000000000000000000003"); - Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); - ArrayList expectedNodes1 = new ArrayList<>(); - expectedNodes1.add(new SWHID("swh:1:dir:0000000000000000000000000000000000000002")); - ArrayList actuals1 = (ArrayList) endpoint1.neighbors(new Endpoint.Input(src1)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes1, actuals1); - - SWHID src2 = new SWHID("swh:1:dir:0000000000000000000000000000000000000017"); - Endpoint endpoint2 = new Endpoint(graph, "forward", "dir:cnt"); - ArrayList expectedNodes2 = new ArrayList<>(); - expectedNodes2.add(new SWHID("swh:1:cnt:0000000000000000000000000000000000000014")); - ArrayList actuals2 = (ArrayList) endpoint2.neighbors(new Endpoint.Input(src2)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes2, actuals2); - - SWHID src3 = new SWHID("swh:1:dir:0000000000000000000000000000000000000012"); - Endpoint endpoint3 = new Endpoint(graph, "backward", "*"); - ArrayList expectedNodes3 = new ArrayList<>(); - expectedNodes3.add(new SWHID("swh:1:rev:0000000000000000000000000000000000000013")); - ArrayList actuals3 = (ArrayList) endpoint3.neighbors(new Endpoint.Input(src3)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes3, actuals3); - - SWHID src4 = new SWHID("swh:1:rev:0000000000000000000000000000000000000009"); - Endpoint endpoint4 = new Endpoint(graph, "backward", "rev:rev"); - ArrayList expectedNodes4 = new ArrayList<>(); - expectedNodes4.add(new SWHID("swh:1:rev:0000000000000000000000000000000000000013")); - ArrayList actuals4 = (ArrayList) endpoint4.neighbors(new Endpoint.Input(src4)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes4, actuals4); - - SWHID src5 = new SWHID("swh:1:snp:0000000000000000000000000000000000000020"); - Endpoint endpoint5 = new Endpoint(graph, "backward", "*"); - ArrayList expectedNodes5 = new ArrayList<>(); - expectedNodes5.add(new SWHID(TEST_ORIGIN_ID)); - ArrayList actuals5 = (ArrayList) endpoint5.neighbors(new Endpoint.Input(src5)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes5, actuals5); - } - - @Test - public void twoNeighbors() { - SwhBidirectionalGraph graph = getGraph(); - - SWHID src1 = new SWHID("swh:1:snp:0000000000000000000000000000000000000020"); - 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")); - ArrayList actuals1 = (ArrayList) endpoint1.neighbors(new Endpoint.Input(src1)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes1, actuals1); - - SWHID src2 = new SWHID("swh:1:dir:0000000000000000000000000000000000000008"); - 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")); - ArrayList actuals2 = (ArrayList) endpoint2.neighbors(new Endpoint.Input(src2)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes2, actuals2); - - SWHID src3 = new SWHID("swh:1:cnt:0000000000000000000000000000000000000001"); - 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")); - ArrayList actuals3 = (ArrayList) endpoint3.neighbors(new Endpoint.Input(src3)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes3, actuals3); - - SWHID src4 = new SWHID("swh:1:rev:0000000000000000000000000000000000000009"); - 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")); - ArrayList actuals4 = (ArrayList) endpoint4.neighbors(new Endpoint.Input(src4)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes4, actuals4); - } - - @Test - public void threeNeighbors() { - SwhBidirectionalGraph graph = getGraph(); - - SWHID src1 = new SWHID("swh:1:dir:0000000000000000000000000000000000000008"); - 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")); - ArrayList actuals1 = (ArrayList) endpoint1.neighbors(new Endpoint.Input(src1)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes1, actuals1); - - SWHID src2 = new SWHID("swh:1:rev:0000000000000000000000000000000000000009"); - 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")); - ArrayList actuals2 = (ArrayList) endpoint2.neighbors(new Endpoint.Input(src2)).result; - GraphTest.assertEqualsAnyOrder(expectedNodes2, actuals2); - } -} diff --git a/java/src/test/java/org/softwareheritage/graph/VisitTest.java b/java/src/test/java/org/softwareheritage/graph/VisitTest.java deleted file mode 100644 index aef4b8d..0000000 --- a/java/src/test/java/org/softwareheritage/graph/VisitTest.java +++ /dev/null @@ -1,408 +0,0 @@ -package org.softwareheritage.graph; - -import java.util.ArrayList; -import java.util.Set; -import java.util.HashSet; - -import org.junit.jupiter.api.Test; -import org.softwareheritage.graph.server.Endpoint; - -// Avoid warnings concerning Endpoint.Output.result manual cast -@SuppressWarnings("unchecked") -public class VisitTest extends GraphTest { - private void assertSameNodesFromPaths(ArrayList paths, ArrayList nodes) { - Set expectedNodes = new HashSet(); - for (SwhPath path : paths) { - expectedNodes.addAll(path.getPath()); - } - GraphTest.assertEqualsAnyOrder(expectedNodes, nodes); - } - - @Test - public void forwardFromRoot() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID(TEST_ORIGIN_ID); - Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "*"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - ArrayList expectedPaths = new ArrayList(); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID, "swh:1:snp:0000000000000000000000000000000000000020", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:cnt:0000000000000000000000000000000000000007")); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID, "swh:1:snp:0000000000000000000000000000000000000020", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:cnt:0000000000000000000000000000000000000001")); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID, "swh:1:snp:0000000000000000000000000000000000000020", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:dir:0000000000000000000000000000000000000006", - "swh:1:cnt:0000000000000000000000000000000000000004")); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID, "swh:1:snp:0000000000000000000000000000000000000020", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:dir:0000000000000000000000000000000000000006", - "swh:1:cnt:0000000000000000000000000000000000000005")); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID, "swh:1:snp:0000000000000000000000000000000000000020", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:rev:0000000000000000000000000000000000000003", - "swh:1:dir:0000000000000000000000000000000000000002", - "swh:1:cnt:0000000000000000000000000000000000000001")); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID, "swh:1:snp:0000000000000000000000000000000000000020", - "swh:1:rel:0000000000000000000000000000000000000010", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:cnt:0000000000000000000000000000000000000007")); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID, "swh:1:snp:0000000000000000000000000000000000000020", - "swh:1:rel:0000000000000000000000000000000000000010", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:cnt:0000000000000000000000000000000000000001")); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID, "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(TEST_ORIGIN_ID, "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(TEST_ORIGIN_ID, "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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:dir:0000000000000000000000000000000000000012"); - Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "*"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - 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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:cnt:0000000000000000000000000000000000000004"); - Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "*"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - ArrayList expectedPaths = new ArrayList(); - expectedPaths.add(new SwhPath("swh:1:cnt:0000000000000000000000000000000000000004")); - - GraphTest.assertEqualsAnyOrder(expectedPaths, paths); - assertSameNodesFromPaths(expectedPaths, nodes); - } - - @Test - public void backwardFromRoot() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID(TEST_ORIGIN_ID); - Endpoint endpoint1 = new Endpoint(graph, "backward", "*"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "backward", "*"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - ArrayList expectedPaths = new ArrayList(); - expectedPaths.add(new SwhPath(TEST_ORIGIN_ID)); - - GraphTest.assertEqualsAnyOrder(expectedPaths, paths); - assertSameNodesFromPaths(expectedPaths, nodes); - } - - @Test - public void backwardFromMiddle() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:dir:0000000000000000000000000000000000000012"); - Endpoint endpoint1 = new Endpoint(graph, "backward", "*"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "backward", "*"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - 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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:cnt:0000000000000000000000000000000000000004"); - Endpoint endpoint1 = new Endpoint(graph, "backward", "*"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "backward", "*"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - 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", TEST_ORIGIN_ID)); - 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", TEST_ORIGIN_ID)); - - GraphTest.assertEqualsAnyOrder(expectedPaths, paths); - assertSameNodesFromPaths(expectedPaths, nodes); - } - - @Test - public void forwardSnpToRev() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:snp:0000000000000000000000000000000000000020"); - Endpoint endpoint1 = new Endpoint(graph, "forward", "snp:rev"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "snp:rev"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - 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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:rel:0000000000000000000000000000000000000010"); - Endpoint endpoint1 = new Endpoint(graph, "forward", "rel:rev,rev:rev"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "rel:rev,rev:rev"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - 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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:rev:0000000000000000000000000000000000000013"); - Endpoint endpoint1 = new Endpoint(graph, "forward", "rev:*,dir:*"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "rev:*,dir:*"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - 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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:snp:0000000000000000000000000000000000000020"); - Endpoint endpoint1 = new Endpoint(graph, "forward", "snp:*,rev:*"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "snp:*,rev:*"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - 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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:snp:0000000000000000000000000000000000000020"); - Endpoint endpoint1 = new Endpoint(graph, "forward", ""); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", ""); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - ArrayList expectedPaths = new ArrayList(); - expectedPaths.add(new SwhPath("swh:1:snp:0000000000000000000000000000000000000020")); - - GraphTest.assertEqualsAnyOrder(expectedPaths, paths); - assertSameNodesFromPaths(expectedPaths, nodes); - } - - @Test - public void backwardRevToRevRevToRel() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:rev:0000000000000000000000000000000000000003"); - Endpoint endpoint1 = new Endpoint(graph, "backward", "rev:rev,rev:rel"); - ArrayList paths = (ArrayList) endpoint1.visitPaths(new Endpoint.Input(swhid)).result; - Endpoint endpoint2 = new Endpoint(graph, "backward", "rev:rev,rev:rel"); - ArrayList nodes = (ArrayList) endpoint2.visitNodes(new Endpoint.Input(swhid)).result; - - 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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID(TEST_ORIGIN_ID); - Endpoint endpoint = new Endpoint(graph, "forward", "*"); - ArrayList nodes = (ArrayList) endpoint.visitNodes(new Endpoint.Input(swhid)).result; - - ArrayList expectedNodes = new ArrayList(); - expectedNodes.add(new SWHID(TEST_ORIGIN_ID)); - 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() { - SwhBidirectionalGraph graph = getGraph(); - SWHID swhid = new SWHID("swh:1:rev:0000000000000000000000000000000000000003"); - Endpoint endpoint = new Endpoint(graph, "backward", "rev:*"); - ArrayList nodes = (ArrayList) endpoint.visitNodes(new Endpoint.Input(swhid)).result; - - 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/java/src/test/java/org/softwareheritage/graph/WalkTest.java b/java/src/test/java/org/softwareheritage/graph/WalkTest.java deleted file mode 100644 index 57dc600..0000000 --- a/java/src/test/java/org/softwareheritage/graph/WalkTest.java +++ /dev/null @@ -1,187 +0,0 @@ -package org.softwareheritage.graph; - -import java.util.Arrays; -import java.util.List; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.softwareheritage.graph.server.Endpoint; - -public class WalkTest extends GraphTest { - @Test - public void forwardRootToLeaf() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:snp:0000000000000000000000000000000000000020"); - String dstFmt = "swh:1:cnt:0000000000000000000000000000000000000005"; - - SwhPath solution1 = new SwhPath("swh:1:snp:0000000000000000000000000000000000000020", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:dir:0000000000000000000000000000000000000006", - "swh:1:cnt:0000000000000000000000000000000000000005"); - SwhPath solution2 = 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"); - - Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); - SwhPath dfsPath = (SwhPath) endpoint1.walk(new Endpoint.Input(src, dstFmt, "dfs")).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "*"); - SwhPath bfsPath = (SwhPath) endpoint2.walk(new Endpoint.Input(src, dstFmt, "bfs")).result; - - List possibleSolutions = Arrays.asList(solution1, solution2); - Assertions.assertTrue(possibleSolutions.contains(dfsPath)); - Assertions.assertTrue(possibleSolutions.contains(bfsPath)); - } - - @Test - public void forwardLeafToLeaf() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:cnt:0000000000000000000000000000000000000007"); - String dstFmt = "cnt"; - - SwhPath expectedPath = new SwhPath("swh:1:cnt:0000000000000000000000000000000000000007"); - - Endpoint endpoint1 = new Endpoint(graph, "forward", "*"); - SwhPath dfsPath = (SwhPath) endpoint1.walk(new Endpoint.Input(src, dstFmt, "dfs")).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "*"); - SwhPath bfsPath = (SwhPath) endpoint2.walk(new Endpoint.Input(src, dstFmt, "bfs")).result; - - Assertions.assertEquals(dfsPath, expectedPath); - Assertions.assertEquals(bfsPath, expectedPath); - } - - @Test - public void forwardRevToRev() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:rev:0000000000000000000000000000000000000018"); - String dstFmt = "swh:1:rev:0000000000000000000000000000000000000003"; - - SwhPath expectedPath = new SwhPath("swh:1:rev:0000000000000000000000000000000000000018", - "swh:1:rev:0000000000000000000000000000000000000013", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:rev:0000000000000000000000000000000000000003"); - - Endpoint endpoint1 = new Endpoint(graph, "forward", "rev:rev"); - SwhPath dfsPath = (SwhPath) endpoint1.walk(new Endpoint.Input(src, dstFmt, "dfs")).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "rev:rev"); - SwhPath bfsPath = (SwhPath) endpoint2.walk(new Endpoint.Input(src, dstFmt, "bfs")).result; - - Assertions.assertEquals(dfsPath, expectedPath); - Assertions.assertEquals(bfsPath, expectedPath); - } - - @Test - public void backwardRevToRev() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:rev:0000000000000000000000000000000000000003"); - String dstFmt = "swh:1:rev:0000000000000000000000000000000000000018"; - - SwhPath expectedPath = new SwhPath("swh:1:rev:0000000000000000000000000000000000000003", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:rev:0000000000000000000000000000000000000013", - "swh:1:rev:0000000000000000000000000000000000000018"); - - Endpoint endpoint1 = new Endpoint(graph, "backward", "rev:rev"); - SwhPath dfsPath = (SwhPath) endpoint1.walk(new Endpoint.Input(src, dstFmt, "dfs")).result; - Endpoint endpoint2 = new Endpoint(graph, "backward", "rev:rev"); - SwhPath bfsPath = (SwhPath) endpoint2.walk(new Endpoint.Input(src, dstFmt, "bfs")).result; - - Assertions.assertEquals(dfsPath, expectedPath); - Assertions.assertEquals(bfsPath, expectedPath); - } - - @Test - public void backwardCntToFirstSnp() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:cnt:0000000000000000000000000000000000000001"); - String dstFmt = "snp"; - - SwhPath solution1 = new SwhPath("swh:1:cnt:0000000000000000000000000000000000000001", - "swh:1:dir:0000000000000000000000000000000000000002", - "swh:1:rev:0000000000000000000000000000000000000003", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:snp:0000000000000000000000000000000000000020"); - SwhPath solution2 = new SwhPath("swh:1:cnt:0000000000000000000000000000000000000001", - "swh:1:dir:0000000000000000000000000000000000000002", - "swh:1:rev:0000000000000000000000000000000000000003", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:rel:0000000000000000000000000000000000000010", - "swh:1:snp:0000000000000000000000000000000000000020"); - SwhPath solution3 = new SwhPath("swh:1:cnt:0000000000000000000000000000000000000001", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:snp:0000000000000000000000000000000000000020"); - SwhPath solution4 = new SwhPath("swh:1:cnt:0000000000000000000000000000000000000001", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:rel:0000000000000000000000000000000000000010", - "swh:1:snp:0000000000000000000000000000000000000020"); - - Endpoint endpoint1 = new Endpoint(graph, "backward", "*"); - SwhPath dfsPath = (SwhPath) endpoint1.walk(new Endpoint.Input(src, dstFmt, "dfs")).result; - Endpoint endpoint2 = new Endpoint(graph, "backward", "*"); - SwhPath bfsPath = (SwhPath) endpoint2.walk(new Endpoint.Input(src, dstFmt, "bfs")).result; - - List possibleSolutions = Arrays.asList(solution1, solution2, solution3, solution4); - Assertions.assertTrue(possibleSolutions.contains(dfsPath)); - Assertions.assertTrue(possibleSolutions.contains(bfsPath)); - } - - @Test - public void forwardRevToFirstCnt() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:rev:0000000000000000000000000000000000000009"); - String dstFmt = "cnt"; - - SwhPath solution1 = new SwhPath("swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:cnt:0000000000000000000000000000000000000007"); - SwhPath solution2 = new SwhPath("swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:dir:0000000000000000000000000000000000000006", - "swh:1:cnt:0000000000000000000000000000000000000005"); - SwhPath solution3 = new SwhPath("swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:dir:0000000000000000000000000000000000000006", - "swh:1:cnt:0000000000000000000000000000000000000004"); - SwhPath solution4 = new SwhPath("swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:dir:0000000000000000000000000000000000000008", - "swh:1:cnt:0000000000000000000000000000000000000001"); - SwhPath solution5 = new SwhPath("swh:1:rev:0000000000000000000000000000000000000009", - "swh:1:rev:0000000000000000000000000000000000000003", - "swh:1:dir:0000000000000000000000000000000000000002", - "swh:1:cnt:0000000000000000000000000000000000000001"); - - Endpoint endpoint1 = new Endpoint(graph, "forward", "rev:*,dir:*"); - SwhPath dfsPath = (SwhPath) endpoint1.walk(new Endpoint.Input(src, dstFmt, "dfs")).result; - Endpoint endpoint2 = new Endpoint(graph, "forward", "rev:*,dir:*"); - SwhPath bfsPath = (SwhPath) endpoint2.walk(new Endpoint.Input(src, dstFmt, "bfs")).result; - - List possibleSolutions = Arrays.asList(solution1, solution2, solution3, solution4, solution5); - Assertions.assertTrue(possibleSolutions.contains(dfsPath)); - Assertions.assertTrue(possibleSolutions.contains(bfsPath)); - } - - @Test - public void backwardDirToFirstRel() { - SwhBidirectionalGraph graph = getGraph(); - SWHID src = new SWHID("swh:1:dir:0000000000000000000000000000000000000016"); - String dstFmt = "rel"; - - SwhPath expectedPath = new SwhPath("swh:1:dir:0000000000000000000000000000000000000016", - "swh:1:dir:0000000000000000000000000000000000000017", - "swh:1:rev:0000000000000000000000000000000000000018", - "swh:1:rel:0000000000000000000000000000000000000019"); - - Endpoint endpoint1 = new Endpoint(graph, "backward", "dir:dir,dir:rev,rev:*"); - SwhPath dfsPath = (SwhPath) endpoint1.walk(new Endpoint.Input(src, dstFmt, "dfs")).result; - Endpoint endpoint2 = new Endpoint(graph, "backward", "dir:dir,dir:rev,rev:*"); - SwhPath bfsPath = (SwhPath) endpoint2.walk(new Endpoint.Input(src, dstFmt, "bfs")).result; - - Assertions.assertEquals(dfsPath, expectedPath); - Assertions.assertEquals(bfsPath, expectedPath); - } -}