ProjectManager is now partially unit tested.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@1015 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
f690c55fab
commit
0d7b3b0e9c
@ -6,6 +6,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@ -19,7 +20,11 @@ import com.metaweb.gridworks.model.Project;
|
|||||||
import com.metaweb.gridworks.preference.PreferenceStore;
|
import com.metaweb.gridworks.preference.PreferenceStore;
|
||||||
import com.metaweb.gridworks.preference.TopList;
|
import com.metaweb.gridworks.preference.TopList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProjectManager is responsible for loading and saving the workspace and projects.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
public abstract class ProjectManager {
|
public abstract class ProjectManager {
|
||||||
// last n expressions used across all projects
|
// last n expressions used across all projects
|
||||||
static protected final int s_expressionHistoryMax = 100;
|
static protected final int s_expressionHistoryMax = 100;
|
||||||
@ -49,6 +54,14 @@ public abstract class ProjectManager {
|
|||||||
|
|
||||||
static public ProjectManager singleton;
|
static public ProjectManager singleton;
|
||||||
|
|
||||||
|
protected ProjectManager(){
|
||||||
|
_projectsMetadata = new HashMap<Long, ProjectMetadata>();
|
||||||
|
_preferenceStore = new PreferenceStore();
|
||||||
|
_projects = new HashMap<Long, Project>();
|
||||||
|
|
||||||
|
preparePreferenceStore(_preferenceStore);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the project in the memory of the current session
|
* Registers the project in the memory of the current session
|
||||||
* @param project
|
* @param project
|
||||||
@ -102,26 +115,28 @@ public abstract class ProjectManager {
|
|||||||
*/
|
*/
|
||||||
public void ensureProjectSaved(long id) {
|
public void ensureProjectSaved(long id) {
|
||||||
synchronized(this){
|
synchronized(this){
|
||||||
ProjectMetadata metadata = _projectsMetadata.get(id);
|
ProjectMetadata metadata = this.getProjectMetadata(id);
|
||||||
if (metadata != null) {
|
if (metadata != null) {
|
||||||
try {
|
try {
|
||||||
saveMetadata(metadata, id);
|
saveMetadata(metadata, id);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}//FIXME what should be the behaviour if metadata is null? i.e. not found
|
||||||
|
|
||||||
Project project = _projects.get(id);
|
Project project = getProject(id);
|
||||||
if (project != null && metadata.getModified().after(project.lastSave)) {
|
if (project != null && metadata != null && metadata.getModified().after(project.getLastSave())) {
|
||||||
try {
|
try {
|
||||||
saveProject(project);
|
saveProject(project);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}//FIXME what should be the behaviour if project is null? i.e. not found or loaded.
|
||||||
|
//FIXME what should happen if the metadata is found, but not the project? or vice versa?
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save project metadata to the data store
|
* Save project metadata to the data store
|
||||||
* @param metadata
|
* @param metadata
|
||||||
@ -138,7 +153,7 @@ public abstract class ProjectManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Save workspace and all projects to data store
|
* Save workspace and all projects to data store
|
||||||
* @param b
|
* @param allModified
|
||||||
*/
|
*/
|
||||||
public void save(boolean allModified) {
|
public void save(boolean allModified) {
|
||||||
if (allModified || _busy == 0) {
|
if (allModified || _busy == 0) {
|
||||||
@ -175,23 +190,23 @@ public abstract class ProjectManager {
|
|||||||
*/
|
*/
|
||||||
protected void saveProjects(boolean allModified) {
|
protected void saveProjects(boolean allModified) {
|
||||||
List<SaveRecord> records = new ArrayList<SaveRecord>();
|
List<SaveRecord> records = new ArrayList<SaveRecord>();
|
||||||
Date now = new Date();
|
Date startTimeOfSave = new Date();
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
for (long id : _projectsMetadata.keySet()) {
|
for (long id : _projectsMetadata.keySet()) {
|
||||||
ProjectMetadata metadata = _projectsMetadata.get(id);
|
ProjectMetadata metadata = getProjectMetadata(id);
|
||||||
Project project = _projects.get(id);
|
Project project = getProject(id);
|
||||||
|
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
boolean hasUnsavedChanges =
|
boolean hasUnsavedChanges =
|
||||||
metadata.getModified().getTime() > project.lastSave.getTime();
|
metadata.getModified().getTime() > project.getLastSave().getTime();
|
||||||
|
|
||||||
if (hasUnsavedChanges) {
|
if (hasUnsavedChanges) {
|
||||||
long msecsOverdue = now.getTime() - project.lastSave.getTime();
|
long msecsOverdue = startTimeOfSave.getTime() - project.getLastSave().getTime();
|
||||||
|
|
||||||
records.add(new SaveRecord(project, msecsOverdue));
|
records.add(new SaveRecord(project, msecsOverdue));
|
||||||
|
|
||||||
} else if (now.getTime() - project.lastSave.getTime() > s_projectFlushDelay) {
|
} else if (startTimeOfSave.getTime() - project.getLastSave().getTime() > s_projectFlushDelay) {
|
||||||
/*
|
/*
|
||||||
* It's been a while since the project was last saved and it hasn't been
|
* It's been a while since the project was last saved and it hasn't been
|
||||||
* modified. We can safely remove it from the cache to save some memory.
|
* modified. We can safely remove it from the cache to save some memory.
|
||||||
@ -222,7 +237,7 @@ public abstract class ProjectManager {
|
|||||||
|
|
||||||
for (int i = 0;
|
for (int i = 0;
|
||||||
i < records.size() &&
|
i < records.size() &&
|
||||||
(allModified || (new Date().getTime() - now.getTime() < s_quickSaveTimeout));
|
(allModified || (new Date().getTime() - startTimeOfSave.getTime() < s_quickSaveTimeout));
|
||||||
i++) {
|
i++) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -8,7 +8,6 @@ import java.io.FileWriter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
@ -27,14 +26,13 @@ import com.metaweb.gridworks.ProjectManager;
|
|||||||
import com.metaweb.gridworks.ProjectMetadata;
|
import com.metaweb.gridworks.ProjectMetadata;
|
||||||
import com.metaweb.gridworks.history.HistoryEntryManager;
|
import com.metaweb.gridworks.history.HistoryEntryManager;
|
||||||
import com.metaweb.gridworks.model.Project;
|
import com.metaweb.gridworks.model.Project;
|
||||||
import com.metaweb.gridworks.preference.PreferenceStore;
|
|
||||||
import com.metaweb.gridworks.preference.TopList;
|
import com.metaweb.gridworks.preference.TopList;
|
||||||
|
|
||||||
public class FileProjectManager extends ProjectManager {
|
public class FileProjectManager extends ProjectManager {
|
||||||
|
|
||||||
protected File _workspaceDir;
|
protected File _workspaceDir;
|
||||||
|
|
||||||
final static Logger logger = LoggerFactory.getLogger("file_project_manager");
|
final static Logger logger = LoggerFactory.getLogger("FileProjectManager");
|
||||||
|
|
||||||
static public synchronized void initialize(File dir) {
|
static public synchronized void initialize(File dir) {
|
||||||
if (singleton == null) {
|
if (singleton == null) {
|
||||||
@ -45,15 +43,10 @@ public class FileProjectManager extends ProjectManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected FileProjectManager(File dir) {
|
protected FileProjectManager(File dir) {
|
||||||
|
super();
|
||||||
_workspaceDir = dir;
|
_workspaceDir = dir;
|
||||||
_workspaceDir.mkdirs();
|
_workspaceDir.mkdirs();
|
||||||
|
|
||||||
_projectsMetadata = new HashMap<Long, ProjectMetadata>();
|
|
||||||
_preferenceStore = new PreferenceStore();
|
|
||||||
_projects = new HashMap<Long, Project>();
|
|
||||||
|
|
||||||
preparePreferenceStore(_preferenceStore);
|
|
||||||
|
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.LineNumberReader;
|
import java.io.LineNumberReader;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
@ -47,7 +46,7 @@ public class ProjectUtilities {
|
|||||||
oldFile.delete();
|
oldFile.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
project.lastSave = new Date();
|
project.setLastSave();
|
||||||
|
|
||||||
logger.info("Saved project '{}'",id);
|
logger.info("Saved project '{}'",id);
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ public class Project {
|
|||||||
|
|
||||||
final public History history;
|
final public History history;
|
||||||
transient public ProcessManager processManager = new ProcessManager();
|
transient public ProcessManager processManager = new ProcessManager();
|
||||||
transient public Date lastSave = new Date();
|
transient private Date _lastSave = new Date();
|
||||||
|
|
||||||
final static Logger logger = LoggerFactory.getLogger("project");
|
final static Logger logger = LoggerFactory.getLogger("project");
|
||||||
|
|
||||||
@ -49,6 +49,16 @@ public class Project {
|
|||||||
this.history = new History(this);
|
this.history = new History(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Date getLastSave(){
|
||||||
|
return this._lastSave;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the lastSave time to now
|
||||||
|
*/
|
||||||
|
public void setLastSave(){
|
||||||
|
this._lastSave = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
public ProjectMetadata getMetadata() {
|
public ProjectMetadata getMetadata() {
|
||||||
return ProjectManager.singleton.getProjectMetadata(id);
|
return ProjectManager.singleton.getProjectMetadata(id);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.metaweb.gridworks.tests;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.apache.tools.tar.TarOutputStream;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.ProjectManager;
|
||||||
|
import com.metaweb.gridworks.ProjectMetadata;
|
||||||
|
import com.metaweb.gridworks.history.HistoryEntryManager;
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stub used to make protected methods public for testing
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProjectManagerStub extends ProjectManager {
|
||||||
|
|
||||||
|
public ProjectManagerStub(){
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteProject(long projectID) {
|
||||||
|
// empty
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exportProject(long projectId, TarOutputStream tos) throws IOException {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HistoryEntryManager getHistoryEntryManager() {
|
||||||
|
// empty
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void importProject(long projectID, InputStream inputStream, boolean gziped) throws IOException {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Project loadProject(long id) {
|
||||||
|
// empty
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean loadProjectMetadata(long projectID) {
|
||||||
|
// empty
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveMetadata(ProjectMetadata metadata, long projectId) throws Exception {
|
||||||
|
// empty
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveProject(Project project) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
//Overridden to make public for testing
|
||||||
|
@Override
|
||||||
|
public void saveProjects(boolean allModified){
|
||||||
|
super.saveProjects(allModified);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void saveWorkspace() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,212 @@
|
|||||||
|
package com.metaweb.gridworks.tests;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.testng.Assert;
|
||||||
|
import org.testng.annotations.AfterMethod;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.BeforeTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.ProjectMetadata;
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
import com.metaweb.gridworks.tests.model.ProjectStub;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
|
||||||
|
public class ProjectManagerTests extends GridworksTest {
|
||||||
|
ProjectManagerStub pm;
|
||||||
|
ProjectManagerStub SUT;
|
||||||
|
Project project;
|
||||||
|
ProjectMetadata metadata;
|
||||||
|
|
||||||
|
@BeforeTest
|
||||||
|
public void init() {
|
||||||
|
logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void SetUp(){
|
||||||
|
pm = new ProjectManagerStub();
|
||||||
|
SUT = spy(pm);
|
||||||
|
project = mock(Project.class);
|
||||||
|
metadata = mock(ProjectMetadata.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterMethod
|
||||||
|
public void TearDown(){
|
||||||
|
metadata = null;
|
||||||
|
project = null;
|
||||||
|
SUT = null;
|
||||||
|
pm = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canRegisterProject(){
|
||||||
|
|
||||||
|
SUT.registerProject(project, metadata);
|
||||||
|
|
||||||
|
AssertProjectRegistered();
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(project);
|
||||||
|
verifyNoMoreInteractions(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO test registerProject in race condition
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canEnsureProjectSave(){
|
||||||
|
whenGetSaveTimes(project, metadata);
|
||||||
|
registerProject();
|
||||||
|
|
||||||
|
//run test
|
||||||
|
SUT.ensureProjectSaved(project.id);
|
||||||
|
|
||||||
|
//assert and verify
|
||||||
|
AssertProjectRegistered();
|
||||||
|
try {
|
||||||
|
verify(SUT, times(1)).saveMetadata(metadata, project.id);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Assert.fail();
|
||||||
|
}
|
||||||
|
this.verifySaveTimeCompared(1);
|
||||||
|
verify(SUT, times(1)).saveProject(project);
|
||||||
|
|
||||||
|
//ensure end
|
||||||
|
verifyNoMoreInteractions(project);
|
||||||
|
verifyNoMoreInteractions(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO test ensureProjectSave in race condition
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canSaveAllModified(){
|
||||||
|
whenGetSaveTimes(project, metadata); //5 minute difference
|
||||||
|
registerProject(project, metadata);
|
||||||
|
|
||||||
|
//add a second project to the cache
|
||||||
|
Project project2 = spy(new ProjectStub(2));
|
||||||
|
ProjectMetadata metadata2 = mock(ProjectMetadata.class);
|
||||||
|
whenGetSaveTimes(project2, metadata2, 10); //not modified since the last save but within 30 seconds flush limit
|
||||||
|
registerProject(project2, metadata2);
|
||||||
|
|
||||||
|
//check that the two projects are not the same
|
||||||
|
Assert.assertFalse(project.id == project2.id);
|
||||||
|
|
||||||
|
SUT.save(true);
|
||||||
|
|
||||||
|
verifySaved(project, metadata);
|
||||||
|
|
||||||
|
verifySaved(project2, metadata2);
|
||||||
|
|
||||||
|
verify(SUT, times(1)).saveWorkspace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canFlushFromCache(){
|
||||||
|
|
||||||
|
whenGetSaveTimes(project, metadata, -10 );//already saved (10 seconds before)
|
||||||
|
registerProject(project, metadata);
|
||||||
|
Assert.assertSame(SUT.getProject(0), project);
|
||||||
|
|
||||||
|
SUT.save(true);
|
||||||
|
|
||||||
|
verify(metadata, times(1)).getModified();
|
||||||
|
verify(project, times(2)).getLastSave();
|
||||||
|
verify(SUT, never()).saveProject(project);
|
||||||
|
Assert.assertEquals(SUT.getProject(0), null);
|
||||||
|
verifyNoMoreInteractions(project);
|
||||||
|
verifyNoMoreInteractions(metadata);
|
||||||
|
|
||||||
|
verify(SUT, times(1)).saveWorkspace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void cannotSaveWhenBusy(){
|
||||||
|
registerProject();
|
||||||
|
SUT.setBusy(true);
|
||||||
|
|
||||||
|
SUT.save(false);
|
||||||
|
|
||||||
|
verify(SUT, never()).saveProjects(Mockito.anyBoolean());
|
||||||
|
verify(SUT, never()).saveWorkspace();
|
||||||
|
verifyNoMoreInteractions(project);
|
||||||
|
verifyNoMoreInteractions(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO test canSaveAllModifiedWithRaceCondition
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canSaveSomeModified(){
|
||||||
|
registerProject();
|
||||||
|
whenGetSaveTimes(project, metadata );
|
||||||
|
|
||||||
|
SUT.save(false); //not busy
|
||||||
|
|
||||||
|
verifySaved(project, metadata);
|
||||||
|
verify(SUT, times(1)).saveWorkspace();
|
||||||
|
|
||||||
|
}
|
||||||
|
//TODO test canSaveAllModifiedWithRaceCondition
|
||||||
|
|
||||||
|
//-------------helpers-------------
|
||||||
|
|
||||||
|
protected void registerProject(){
|
||||||
|
this.registerProject(project, metadata);
|
||||||
|
}
|
||||||
|
protected void registerProject(Project proj, ProjectMetadata meta){
|
||||||
|
SUT.registerProject(proj, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void AssertProjectRegistered(){
|
||||||
|
Assert.assertEquals(SUT.getProject(project.id), project);
|
||||||
|
Assert.assertEquals(SUT.getProjectMetadata(project.id), metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void whenGetSaveTimes(Project proj, ProjectMetadata meta){
|
||||||
|
whenGetSaveTimes(proj, meta, 5);
|
||||||
|
}
|
||||||
|
protected void whenGetSaveTimes(Project proj, ProjectMetadata meta, int secondsDifference){
|
||||||
|
whenProjectGetLastSave(proj);
|
||||||
|
whenMetadataGetModified(meta, secondsDifference);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void whenProjectGetLastSave(Project proj){
|
||||||
|
Date projectLastSaveDate = new GregorianCalendar(1970,01,02,00,30,00).getTime();
|
||||||
|
when(proj.getLastSave()).thenReturn(projectLastSaveDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void whenMetadataGetModified(ProjectMetadata meta){
|
||||||
|
whenMetadataGetModified(meta, 5*60);
|
||||||
|
}
|
||||||
|
protected void whenMetadataGetModified(ProjectMetadata meta, int secondsDifference){
|
||||||
|
Date metadataModifiedDate = new GregorianCalendar(1970,01,02,00, 30, secondsDifference).getTime();
|
||||||
|
when(meta.getModified()).thenReturn(metadataModifiedDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifySaveTimeCompared(int times){
|
||||||
|
verifySaveTimeCompared(project, metadata, times);
|
||||||
|
}
|
||||||
|
protected void verifySaveTimeCompared(Project project, ProjectMetadata metadata, int times){
|
||||||
|
verify(metadata, times(times)).getModified();
|
||||||
|
verify(project, times(times)).getLastSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifySaved(Project proj, ProjectMetadata meta){
|
||||||
|
verify(meta, times(1)).getModified();
|
||||||
|
verify(proj, times(2)).getLastSave();
|
||||||
|
verify(SUT, times(1)).saveProject(proj);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(proj);
|
||||||
|
verifyNoMoreInteractions(meta);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.metaweb.gridworks.tests.model;
|
||||||
|
|
||||||
|
import com.metaweb.gridworks.model.Project;
|
||||||
|
|
||||||
|
|
||||||
|
public class ProjectStub extends Project {
|
||||||
|
public ProjectStub(long id){
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user