|
From: <ian...@us...> - 2007-07-09 00:52:53
|
Revision: 219
http://ogoglio.svn.sourceforge.net/ogoglio/?rev=219&view=rev
Author: iansmith
Date: 2007-07-08 17:52:54 -0700 (Sun, 08 Jul 2007)
Log Message:
-----------
Began support for adding/deleting templates from the server
based on the state of the local disk in the template
sync tool. This is a defensive checkin.
Modified Paths:
--------------
spaces/trunk/src/com/ogoglio/client/WebAPIClient.java
spaces/trunk/src/com/ogoglio/persist/TemplatePersistTasks.java
spaces/trunk/src/com/ogoglio/templatesync/SyncTool.java
spaces/trunk/src/com/ogoglio/templatesync/SyncToolSpec.java
spaces/trunk/src/com/ogoglio/templatesync/SyncToolTest.java
spaces/trunk/src/com/ogoglio/xml/TemplateDocument.java
Modified: spaces/trunk/src/com/ogoglio/client/WebAPIClient.java
===================================================================
--- spaces/trunk/src/com/ogoglio/client/WebAPIClient.java 2007-07-06 23:11:25 UTC (rev 218)
+++ spaces/trunk/src/com/ogoglio/client/WebAPIClient.java 2007-07-09 00:52:54 UTC (rev 219)
@@ -547,7 +547,7 @@
}
}
- private XMLElement postAuthenticatedXML(URI uri, String body) throws IOException {
+ protected XMLElement postAuthenticatedXML(URI uri, String body) throws IOException {
return sendAuthenticatedXML(uri, body, "POST", authCookie);
}
@@ -840,4 +840,7 @@
public String toString() {
return "<WebAPI:" + serviceURI + ">";
}
+ public boolean deleteTemplate(long templateID) throws IOException {
+ return sendDelete(getTemplateURI(getAuthDocument(true).getUsername(), templateID),authCookie);
+ }
}
Modified: spaces/trunk/src/com/ogoglio/persist/TemplatePersistTasks.java
===================================================================
--- spaces/trunk/src/com/ogoglio/persist/TemplatePersistTasks.java 2007-07-06 23:11:25 UTC (rev 218)
+++ spaces/trunk/src/com/ogoglio/persist/TemplatePersistTasks.java 2007-07-09 00:52:54 UTC (rev 219)
@@ -110,4 +110,5 @@
return (TemplateRecord) task.execute();
}
+
}
Modified: spaces/trunk/src/com/ogoglio/templatesync/SyncTool.java
===================================================================
--- spaces/trunk/src/com/ogoglio/templatesync/SyncTool.java 2007-07-06 23:11:25 UTC (rev 218)
+++ spaces/trunk/src/com/ogoglio/templatesync/SyncTool.java 2007-07-09 00:52:54 UTC (rev 219)
@@ -6,6 +6,7 @@
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -22,11 +23,18 @@
"usage SyncTool username password serviceURI";
public static final String ABORT_BAD_PW =
"username/password pair unable to authenticate to that service";
+ public static final String ABORT_FILE_WHERE_DIR = "Expected directory but found file";
+ public static final String ABORT_USER_REQUEST = "Aborting. Please check to be sure you want templates to be deleted.";
public static final String ABORT_DUP_TEMPLATE_NAMES = "Aborting: Found templates with the same name!";
+ public static final String VERIFY_DEL_ON_SERVER="Ok to delete template off of server [y/N]?";
+ public static final String VERIFY_ADD_TO_SERVER = "Ok to create template on server [Y/n]?";
+ public static final String ABORT_DEL_FAILED = "Aborting. Delete of template failed on server.";
+ public static final String ABORT_IO_EX = "Aborting. IO Exception";
- private WebAPIAuthenticator theDecider=new WebAPIAuthenticator();
+ WebAPIAuthenticator theDecider=new WebAPIAuthenticator();
String cookie;
- Map serverTemplateNamesToIds;
+ Map serverTemplateNamesToIds,serverTemplatesToDelete = new HashMap();
+ List serverTemplatesToAdd= new ArrayList();
//Troubling: Can't test this the way I want to because the OS calls main and there is no
//Troubling: no way to introduce things in-between the two
@@ -34,9 +42,10 @@
SyncTool self = new SyncTool();
try {
self.start(args);
- } catch (Throwable t) {
- t.printStackTrace();
- System.out.println("ERROR WAS:"+t.getMessage());
+ } catch (URISyntaxException t) {
+ System.out.println("URISyntaxException was "+t.getMessage());
+ } catch (IOException t) {
+ System.out.println("IOException WAS:"+t.getMessage());
}
}
@@ -101,7 +110,7 @@
return; //if you don't understand why this is here, don't mess with it
}
serviceURI = new URI(argv[2]);
- cookie = getAuthenticator().authenticate(serviceURI, argv[0], argv[1]);
+ cookie = theDecider.authenticate(serviceURI, argv[0], argv[1]);
if (cookie==null) {
abort(ABORT_BAD_PW);
return; //if you don't understand why this is here, don't mess with it
@@ -116,7 +125,7 @@
serverTemplateNamesToIds = getServerTemplateList(client);
for (int i=0; i<templateNames.size();++i) {
- syncTemplate((String)templateNames.get(i),client);
+ syncAllTemplatesToSvc(new File((String)templateNames.get(i)),client);
}
}
@@ -137,11 +146,9 @@
for (int i=0; i<docs.length; ++i) {
TemplateDocument doc=docs[i];
if (result.containsKey(doc.getDisplayName())) {
- System.out.println("document "+i+" true path");
abort(ABORT_DUP_TEMPLATE_NAMES);
return null; //please don't mess with this
} else {
- System.out.println("document "+i+" false path "+result.size());
String key = doc.getDisplayName();
Long value = new Long(doc.getTemplateID());
result.put(key,value);
@@ -150,11 +157,70 @@
return result;
}
- public void syncTemplate(String name,WebAPIClient client) {
-
+ public void syncAllTemplatesToSvc(File dir,WebAPIClient client) {
+ computeServerTemplatesToDelete(dir, serverTemplateNamesToIds.keySet().iterator());
+ computeServerTemplatesToAdd(dir);
+ try {
+ addAndDeleteServerTemplates(client);
+ } catch (IOException e) {
+ abort(ABORT_IO_EX+":"+e.getMessage());
+ }
}
-
- public WebAPIAuthenticator getAuthenticator() {
- return theDecider;
+
+ public void addAndDeleteServerTemplates(WebAPIClient client) throws IOException {
+ for (int i=0; i<serverTemplatesToAdd.size();++i) {
+ String templName=((File)serverTemplatesToAdd.get(i)).getName();
+ client.createTemplate(templName);
+ }
+ Iterator i=serverTemplatesToDelete.keySet().iterator();
+ while (i.hasNext()) {
+ long l = ((Long)i.next()).longValue();
+ if (!client.deleteTemplate(l)) {
+ abort(ABORT_DEL_FAILED);
+ }
+ }
}
+
+ public void computeServerTemplatesToDelete(File dir, Iterator i) {
+ String key;
+ String warningMsg;
+ File candidate;
+ Long id;
+ while (i.hasNext()) {
+ key = (String)i.next();
+ id=(Long)serverTemplateNamesToIds.get(key);
+ candidate = new File(dir,key);
+ if (candidate.isDirectory()==false) {
+ if (candidate.isFile()) {
+ abort(candidate.getAbsolutePath()+":"+ABORT_FILE_WHERE_DIR);
+ }
+ warningMsg = "Template " + key + " not found as expected in "+candidate.getAbsolutePath();
+ if (!verifyWithUser(warningMsg,VERIFY_DEL_ON_SERVER)) {
+ abort(ABORT_USER_REQUEST);
+ } else {
+ serverTemplatesToDelete.put(id,key);
+ }
+ }
+ }
+ }
+
+ public boolean verifyWithUser(String info, String prompt) {
+ return false;
+ }
+
+ public void computeServerTemplatesToAdd(File dir) {
+ File[] children = dir.listFiles();
+ for (int i=0; i<children.length;++i) {
+ File candidate = children[i];
+ if (!candidate.isDirectory()) {
+ abort(candidate.getAbsolutePath()+":"+ABORT_FILE_WHERE_DIR);
+ }
+ if (!serverTemplateNamesToIds.containsKey(candidate.getName())) {
+ if (verifyWithUser(candidate.getAbsolutePath(), VERIFY_ADD_TO_SERVER)==true) {
+ serverTemplatesToAdd.add(candidate);
+ }
+ }
+
+ }
+ }
}
Modified: spaces/trunk/src/com/ogoglio/templatesync/SyncToolSpec.java
===================================================================
--- spaces/trunk/src/com/ogoglio/templatesync/SyncToolSpec.java 2007-07-06 23:11:25 UTC (rev 218)
+++ spaces/trunk/src/com/ogoglio/templatesync/SyncToolSpec.java 2007-07-09 00:52:54 UTC (rev 219)
@@ -1,9 +1,12 @@
package com.ogoglio.templatesync;
+import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -82,8 +85,7 @@
mockSyncTool.start(CMD_LINE_ARGS);
modify().forward();
- mockSyncTool.getAuthenticator();
- modify().returnValue(authMock);
+ mockSyncTool.theDecider = authMock;
authMock.authenticate(new URI(SVC), USER, PW);
modify().returnValue(cookieValue);
@@ -110,9 +112,9 @@
beginSection(s.ordered("templates called in order found"));
{
- mockSyncTool.syncTemplate((String)fakeTemplates.get(0),null);
+ mockSyncTool.syncAllTemplatesToSvc(new File((String)fakeTemplates.get(0)),null);
modify().args(is.AS_RECORDED,is.instanceOf(WebAPIClient.class));
- mockSyncTool.syncTemplate((String)fakeTemplates.get(1),null);
+ mockSyncTool.syncAllTemplatesToSvc(new File((String)fakeTemplates.get(1)),null);
modify().args(is.AS_RECORDED,is.instanceOf(WebAPIClient.class));
}
endSection();
@@ -154,7 +156,7 @@
throws IOException, URISyntaxException{
String USER = "some user";
- AuthDocument authDoc = (AuthDocument)mock(AuthDocument.class,"authDoc");
+ AuthDocument authDoc = (AuthDocument)mock(AuthDocument.class);
api.getAuthDocument(true);
modify().returnValue(authDoc);
@@ -226,6 +228,119 @@
startVerification();
mockSyncTool.getServerTemplateList(client);
+ }
+
+ public void testSyncWithFileNotPresent() {
+ File FAKE_PATH=new File("/foo/bar");
+ String MONSTER="monsterTemplate",HERO="heroTemplate";
+ Long MONSTER_ID=new Long(5222L),HERO_ID=new Long(209L);
+ List serverTemplatesFromXML = new ArrayList();
+ Map fakeMap = new HashMap();
+ fakeMap.put(MONSTER, MONSTER_ID);
+ fakeMap.put(HERO, HERO_ID);
+
+ serverTemplatesFromXML.add(MONSTER);
+ serverTemplatesFromXML.add(HERO);
+
+ mockSyncTool.computeServerTemplatesToDelete(FAKE_PATH,null);
+ modify().args(is.instanceOf(File.class),is.instanceOf(Iterator.class)).forward();
+
+ mockSyncTool.serverTemplateNamesToIds = fakeMap;
+
+ mockSyncTool.verifyWithUser("tell user bad stuff about to happen",
+ SyncTool.VERIFY_DEL_ON_SERVER);
+ modify().args(is.instanceOf(String.class)).returnValue(false);
+ modify().multiplicity(expect.exactly(fakeMap.size()));
+
+ mockSyncTool.abort(SyncTool.ABORT_USER_REQUEST); //tricky: mock doesn't terminate program!
+ modify().multiplicity(expect.exactly(fakeMap.size()));
+
+ startVerification();
+ mockSyncTool.computeServerTemplatesToDelete(FAKE_PATH, fakeMap.keySet().iterator());
+ assertThat(mockSyncTool.serverTemplatesToDelete.isEmpty(),is.TRUE); //mildly functional
}
+
+ private File makeMockForDir(String dirPath,String name) {
+ return (File)mock(File.class,new Object[]{dirPath},name);
+ }
+ public void testSyncWithTemplateNotPresent() {
+ String foobar = "/foo/bar", child1Path=foobar+"/child1",child2Path=foobar+"/child2";
+ File parentDir=makeMockForDir(foobar, "parentDir");
+ File child1=makeMockForDir(child1Path, "child1");
+ File child2=makeMockForDir(child2Path, "child2");
+ File[] bogusChildren=new File[] { child1, child2};
+ mockSyncTool.serverTemplateNamesToIds=new HashMap(); //indicates empty server
+
+ parentDir.equals(new File(foobar)); //generated by RMOCK!
+ modify().returnValue(true);
+
+ parentDir.getPath(); //generated by RMOCK!
+ modify().returnValue(foobar);
+
+ mockSyncTool.computeServerTemplatesToAdd(parentDir);
+ modify().forward();
+
+ parentDir.listFiles();
+ modify().returnValue(bogusChildren);
+
+ prepareChildMock(child1Path, child1, "child1");
+ prepareChildMock(child2Path, child2, "child2");
+
+ mockSyncTool.verifyWithUser("create template warning", SyncTool.VERIFY_ADD_TO_SERVER);
+ modify().args(is.instanceOf(String.class),is.AS_RECORDED).returnValue(false);
+ mockSyncTool.verifyWithUser("create template warning", SyncTool.VERIFY_ADD_TO_SERVER);
+ modify().args(is.instanceOf(String.class),is.AS_RECORDED).returnValue(true);
+
+ startVerification();
+ mockSyncTool.computeServerTemplatesToAdd(parentDir);
+ assertThat(mockSyncTool.serverTemplatesToAdd.isEmpty(),is.FALSE); //mildly functional
+ }
+
+ public void testAddAndDelCallsAPI() throws IOException {
+ File FIRST=new File("/some/path/first"), SECOND=new File("/other/path/second");
+ Long L1=new Long(789L), L2=new Long(123L), L3=new Long(456L);
+ mockSyncTool.serverTemplatesToAdd.add(FIRST);
+ mockSyncTool.serverTemplatesToAdd.add(SECOND);
+ mockSyncTool.serverTemplatesToDelete.put(L1,"name ignored");
+ mockSyncTool.serverTemplatesToDelete.put(L2,"name ignored again");
+ mockSyncTool.serverTemplatesToDelete.put(L3,"yet again, ignored");
+
+ mockSyncTool.addAndDeleteServerTemplates(client);
+ modify().forward();
+
+ client.createTemplate(FIRST.getName());
+ client.createTemplate(SECOND.getName());
+
+ client.deleteTemplate(L1.longValue());
+ modify().returnValue(true);
+
+ client.deleteTemplate(L2.longValue());
+ modify().returnValue(true);
+
+ client.deleteTemplate(L3.longValue());
+ modify().returnValue(false);
+
+ mockSyncTool.abort(SyncTool.ABORT_DEL_FAILED);
+
+ client.equals(null); //generated by RMOCK!
+ modify().args(is.ANYTHING).returnValue(true);
+
+
+ startVerification();
+ mockSyncTool.addAndDeleteServerTemplates(client);
+
+ }
+
+ public void prepareChildMock(String path, File child, String name) {
+ child.isDirectory();
+ modify().returnValue(true);
+
+ child.getAbsolutePath();
+ modify().returnValue(path);
+
+ child.getName();
+ modify().returnValue(name);
+ }
+
}
Modified: spaces/trunk/src/com/ogoglio/templatesync/SyncToolTest.java
===================================================================
--- spaces/trunk/src/com/ogoglio/templatesync/SyncToolTest.java 2007-07-06 23:11:25 UTC (rev 218)
+++ spaces/trunk/src/com/ogoglio/templatesync/SyncToolTest.java 2007-07-09 00:52:54 UTC (rev 219)
@@ -4,6 +4,8 @@
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import com.agical.rmock.extension.junit.RMockTestCase;
@@ -12,6 +14,8 @@
SyncTool tool; // setup makes a new instance of this every time
+ public static final String TEMP_DIR_FOR_ADD_DEL = "/tmp/addDelTestOfOG";
+
public void setUp() {
tool = new SyncTool();
}
@@ -64,12 +68,74 @@
public void testBadURIFormat() throws IOException, URISyntaxException{
expectThatExceptionThrown(is.instanceOf(java.net.MalformedURLException.class));
- tool.getAuthenticator().authenticate(new URI("noproto:/garbage"), "iansmith", "no");
+ tool.theDecider.authenticate(new URI("noproto:/garbage"), "iansmith", "no");
}
public void testBadLoginFormat() throws IOException,URISyntaxException {
expectThatExceptionThrown(is.instanceOf(IOException.class));
- tool.getAuthenticator().authenticate(new URI("http://transmutable.com"), "", "no");
- tool.getAuthenticator().authenticate(new URI("http://transmutable.com"), null, "no");
+ tool.theDecider.authenticate(new URI("http://transmutable.com"), "", "no");
+ tool.theDecider.authenticate(new URI("http://transmutable.com"), null, "no");
}
+ public void testAddAndDeleteWorkProperlyForTemplates() {
+ File dir = createTempDirWithThreeSubdirs();
+ String DEAD_WEIGHT = "dead-weight-on-server";
+ String NOT_NEEDED = "no-longer-needed-on-server";
+
+ //don't like to use mocks in a functional test but need to thwart the interactive
+ //question about do you want to delete templates...without this would have to introduce
+ //a whole class to just handle user verification...sigh.
+ SyncTool toolMock = (SyncTool)mock(SyncTool.class);
+
+ //for the two methods under test, we just basically forward them to the orig instance
+ toolMock.computeServerTemplatesToAdd(new File("/"));
+ modify().args(is.instanceOf(File.class));
+ modify().forward();
+
+ toolMock.computeServerTemplatesToDelete(new File(""), null);
+ modify().args(is.instanceOf(File.class),is.instanceOf(Iterator.class));
+ modify().forward();
+
+ //need to fake this to avoid console input
+ toolMock.verifyWithUser("some info message", "some y/n question");
+ modify().args(is.instanceOf(String.class),is.instanceOf(String.class));
+ modify().multiplicity(expect.exactly(4)); //two dels and two adds
+ modify().returnValue(true);
+
+ toolMock.serverTemplateNamesToIds=new HashMap();
+ Long DW_ID =new Long(9920L);
+ Long NN_ID =new Long(298L);
+
+ toolMock.serverTemplateNamesToIds.put(NOT_NEEDED, NN_ID);
+ toolMock.serverTemplateNamesToIds.put(DEAD_WEIGHT, DW_ID);
+ toolMock.serverTemplateNamesToIds.put("three", new Long(915L));
+
+ startVerification();
+ toolMock.computeServerTemplatesToDelete(dir, toolMock.serverTemplateNamesToIds.keySet().iterator());
+ toolMock.computeServerTemplatesToAdd(dir);
+
+ assertThat(toolMock.serverTemplateNamesToIds.size(),is.eq(3)); //no change?
+
+ assertThat(toolMock.serverTemplatesToAdd.size(),is.eq(2));
+ assertThat(toolMock.serverTemplatesToAdd.contains(new File(TEMP_DIR_FOR_ADD_DEL,"one")),is.TRUE);
+ assertThat(toolMock.serverTemplatesToAdd.contains(new File(TEMP_DIR_FOR_ADD_DEL,"two")),is.TRUE);
+
+ assertThat(toolMock.serverTemplatesToDelete.size(),is.eq(2));
+ assertThat(toolMock.serverTemplatesToDelete.containsKey(NN_ID),is.TRUE);
+ assertThat(toolMock.serverTemplatesToDelete.containsKey(DW_ID),is.TRUE);
+
+ }
+ public File createTempDirWithThreeSubdirs() {
+ File result = new File(TEMP_DIR_FOR_ADD_DEL);
+ result.mkdir();
+
+ new File(result,"one").mkdir();
+ new File(result,"two").mkdir();
+ new File(result,"three").mkdir();
+
+ return result;
+ }
+ public void testShouldTestThatCreateAndDeleteClientSideCallsGenerateXMLProperly()
+ {
+ System.out.println("WARNING: Not testing client side XML generation (TODO)");
+ }
}
Modified: spaces/trunk/src/com/ogoglio/xml/TemplateDocument.java
===================================================================
--- spaces/trunk/src/com/ogoglio/xml/TemplateDocument.java 2007-07-06 23:11:25 UTC (rev 218)
+++ spaces/trunk/src/com/ogoglio/xml/TemplateDocument.java 2007-07-09 00:52:54 UTC (rev 219)
@@ -53,10 +53,10 @@
public TemplateDocument(XMLElement data) {
if (data == null) {
- throw new IllegalArgumentException("SimDocument data is null");
+ throw new IllegalArgumentException("TemplateDocument data is null");
}
if (!NAME.equals(data.getName())) {
- throw new IllegalArgumentException("SimDocument data is not named Auth: " + data);
+ throw new IllegalArgumentException("TemplateDocument data is not named template: " + data);
}
ArgumentUtils.assertNotEmpty(data.getStringAttribute(DISPLAY_NAME));
ArgumentUtils.assertNotEmpty(data.getStringAttribute(OWNER_USERNAME));
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|