-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JsonExporter changes #409
base: master
Are you sure you want to change the base?
JsonExporter changes #409
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has all this new code been tested? I don't see any changes to tests as part of this pull request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First round of comments, sending because the code is getting a little messy for me to look through, so I'll wait for you to address this first round before I do a second round of comments. If you notice that one of my comments also applies to other areas of your code I didn't explicitly comment on, please make the relevant changes in those spots as well to prevent me from needing to make the same comments again next round. Also, please add tests as Ivan suggested (although I realize that my original JsonExporter code erroneously was untested as well). Thanks for doing this!
// EvBasedGraph evGraph = new EvBasedGraph(pGraph); | ||
// System.out.println("evGraph:\n" + evGraph); | ||
EvBasedGraph evGraph = new EvBasedGraph(pGraph); | ||
System.out.println("evGraph:\n" + evGraph); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this for debugging and illustration purposes only. Remove this line.
List<Map<String, Integer>> edgesList = makeEdgesJSON(evGraph); | ||
finalModelMap.put("edges", edgesList); | ||
|
||
finalModelMap.put("displayables", displayablesList); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this up to where displayablesList is declared and assigned.
|
||
// Add invariants to final model map | ||
List<Map<String, Object>> invariantList = makeInvariantsJSON(pGraph); | ||
finalModelMap.put("invariants", invariantList); | ||
List<Map<String, Object>> invariantsList = makeNewInvariantsJSON( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the method name have New
in its name? Unless this means something, remove it.
private static List<Map<String, Integer>> makeNodesJSON( | ||
EvBasedGraph evGraph) { | ||
|
||
// List of Nodes to go into the JSON object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nodes -> nodes
// List of Nodes to go into the JSON object | ||
List<Map<String, Integer>> nodeList = new LinkedList<Map<String, Integer>>(); | ||
|
||
// add the initial node first |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add -> Add
singleEventMap.put("eventType", evType.toString()); | ||
singleEventMap.put("logLine", event.getLineNum()); | ||
// Map of edges and their respective global ID's | ||
static Map<EvBasedEdge, Integer> edgesIDMap = new LinkedHashMap<EvBasedEdge, Integer>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the same thing I mentioned above for nodesIDMap.
// Contains all edges used to avoid duplicates | ||
Set<EvBasedEdge> usedEdges = new HashSet<EvBasedEdge>(); | ||
|
||
for (EvBasedNode node : allNodes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just put evGraph.getNodes()
directly within this foreach statement, since allNodes isn't used anywhere but here. Make the same change in all other methods that follow this same pattern.
// Get the edges for each node | ||
Set<EvBasedEdge> allEdges = node.outEdges; | ||
|
||
for (EvBasedEdge edge : allEdges) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as for the allNodes foreach above.
edgesMap.put("destNodeID", nodesIDMap.get(edge.destNode)); | ||
String displayableValue = edge.eType.getETypeLabel() + " [" | ||
+ edge.resMin + ", " + edge.resMax + "]"; | ||
if (edge.resMin == null && edge.resMax == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means displayableValue will be set twice for every edge for Synoptic models and still twice for a few edges touching initial or terminal in Perfume models. Instead, just assign displayableValue once based on whether this condition is true (so basically do an if/else
instead of just an if
).
// Add this event to this trace's list of events | ||
singleTraceEventsList.add(singleEventMap); | ||
// Map of displayables and their respective global ID's | ||
static Map<String, Integer> displayablesIDMap = new LinkedHashMap<String, Integer>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above global maps.
// Map of nodes and their respective global ID's | ||
private static Map<EvBasedNode, Integer> nodesIDMap; | ||
// Map of edges and their respective global ID's | ||
static Map<EvBasedEdge, Integer> edgesIDMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make the rest of these global maps private, and initialize all of them to null.
List<Map<String, Integer>> nodeList = new LinkedList<>(); | ||
|
||
// Add the initial node first | ||
Map<String, Integer> iniNodeMap = makeNode(evGraph, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ini -> init
You can manually run the whole Perfume algorithm to get a partition graph for your tests. Try this skeleton test class I made, and you can add your actual tests to it. Please don't actually use file i/o like my fake renameMeTest does. Change JsonExporter so that you can test it without actually outputting a file (just refactor it so that you aren't forced to generate the json and output a file, since this is currently all within the only entry point, exportJsonObject()). package synoptic.tests.units;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import synoptic.main.AbstractMain;
import synoptic.main.PerfumeMain;
import synoptic.main.options.PerfumeOptions;
import synoptic.model.PartitionGraph;
import synoptic.model.export.DotExportFormatter;
import synoptic.model.export.JsonExporter;
/**
* TODO
*/
public class JsonExporterTests {
private PerfumeMain main;
private PartitionGraph pGraph;
@Before
public void setUp() throws Exception {
// Set up Perfume options
PerfumeOptions perfOpts = new PerfumeOptions();
perfOpts.regExps = Arrays.asList(
new String[] { "(?<ip>.+), (?<TYPE>.+), (?<DTIME>.+)" });
perfOpts.partitionRegExp = "\\k<ip>";
perfOpts.logFilenames.add(
"../traces/abstract/perfume-survey/browser-caching-traces.txt");
// Create a Perfume instance
AbstractMain.instance = null;
main = new PerfumeMain(perfOpts.toAbstractOptions(),
new DotExportFormatter());
// Run Perfume
pGraph = main.createInitialPartitionGraph();
main.runSynoptic(pGraph);
}
/**
* TODO
*/
@Test
public void renameMeTest() throws Exception {
JsonExporter.exportJsonObject("/tmp/JsonExporterTest", pGraph);
}
} |
…rted an option back to false in PerfumeOptions
@@ -137,5 +137,4 @@ public void mainTest() throws Exception { | |||
AbstractMain.instance = null; | |||
SynopticMain.main(args); | |||
} | |||
|
|||
} | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hg revert
this file
@@ -175,4 +175,4 @@ public void basicDistEventTypeTest() { | |||
assertTrue(e1.compareTo(e2) == 0); | |||
assertTrue(e2.compareTo(e1) == 0); | |||
} | |||
} | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hg revert
this file
private Object expectedJSON = null; | ||
private JSONObject expectedJSONObject = null; | ||
private JSONParser parser = null; | ||
private String dispJString = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general (but almost always), global variables should be avoided when possible. Almost all of these should not be global and should be private, method-level variables. For example, main
is only used within setUp()
. The only reason a global variable should be used is if the state of an object needs to be shared between methods (not just the variable being re-initialized with the same name in different methods but actually the same object) and if there is no other convenient way to pass that object between the methods (e.g., parameters, return values). Please make these local variables instead of global.
new String[] { "(?<ip>.+), (?<TYPE>.+), (?<DTIME>.+)" }); | ||
perfOpts.partitionRegExp = "\\k<ip>"; | ||
perfOpts.logFilenames.add( | ||
"./traces/abstract/perfume-survey/browser-caching-traces.txt"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed over email, different methods of running these unit tests result in different behaviors when using relative paths like this one (the current directory when running the tests is either $repo/synoptic/synoptic or $repo/synoptic/synoptic/bin). Therefore, this test will fail when run in some ways and pass in others.
Add a static method somewhere (perhaps SynopticTest) that resolves paths for files used by unit tests. Make the method something like getTestPath(String path)
that takes a relative path like this--but probably omit the ./
--and checks if the file as written works. If not, it checks if ../$pathAsWritten
works. If neither work, it throws an exception. Call that new method from here to get the path for this txt file.
… JsonExporterTests, and added getTestPath method to SynopticTest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comments. Also remove file abc
*/ | ||
@Test | ||
public void displayableTest() throws Exception { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some of the commented-out test code below looks useful. You could verify that each of the expected displayable values (e.g., "cache-page [9,17]") is present, right? The latter could be done quickly by populating a set of all the displayable values in expected vs. in reality and then simply checking expectedSet.equals(actualSet)
(but perhaps with better variable names). That lets you make java Set equality do all the work. You could do similar check for other lists that have meaningful string values, like invariantTypes and logStatements.
However, I totally understand your desire to avoid doing a very long and complex check that the entire graph of edges and nodes match up. :) I think my suggestions above hit a nice compromise, since they shouldn't be too difficult or long, but they still verify real expected values rather than only verifying that the produced JSON has the right lists that we expect and doesn't have nulls.
idCount++; | ||
} else if (m.containsKey("id") && m.get("id") == null) { | ||
res = false; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is redundancy here (the m.containsKey("id")
check), plus you should fail immediately when you encounter a problem rather than using res
. Basically:
if (m.containsKey("id")) {
if (m.get("id") == null) {
fail("Displayable contains null id");
}
idCount++;
}
Remove res
entirely from this test and others, and change all of the conditionals to check this way. I'm not sure if you need to import anything or do the fail()
call slightly differently, perhaps Assert.fail()
instead, basically, use this.
*/ | ||
public static String getTestPath(String path) throws Exception { | ||
|
||
// original path passed in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Capitalize to keep comments consistent with the rest of the codebase ("Original path passed in"). Same for other comments
// parent directory of the path passed in | ||
File parentPath = new File("../" + path); | ||
// removing parent directory (../) from path passed in | ||
File parentRemovedPath = new File(path.substring(3)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… corrected comments, and changed testPath method.
@wborkofsky I apologize that I forgot about this pull request. Did your changes after my March 29 comments address all of my comments, i.e., am I up to bat on this? I saw that at least some of the comments were addressed, but I saw that you didn't remove the If everything is addressed or you have responses to any comments you didn't address, please let me know, and I'll take another look! |
@wborkofsky Just a quick ping on my question from above: "Did your changes after my March 29 comments address all of my comments, i.e., am I up to bat on this?" |
@ohmann It appears that I did add in all the test code for set equality. For the file "abc", in my commit, it shows as all lines removed so I believe it should have been removed as well and it does not appear in the synoptic version on my computer. |
No description provided.