// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.server;
import static com.google.appinventor.shared.rpc.project.youngandroid.NewYoungAndroidProjectParameters.YOUNG_ANDROID_FORM_NAME;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import com.google.appinventor.common.testutils.TestUtils;
import com.google.appinventor.components.common.YaVersion;
import com.google.appinventor.server.encryption.KeyczarEncryptor;
import com.google.appinventor.server.storage.StorageIo;
import com.google.appinventor.server.storage.StorageIoInstanceHolder;
import com.google.appinventor.shared.rpc.BlocksTruncatedException;
import com.google.appinventor.shared.rpc.project.FileDescriptor;
import com.google.appinventor.shared.rpc.project.FileDescriptorWithContent;
import com.google.appinventor.shared.rpc.project.ProjectNode;
import com.google.appinventor.shared.rpc.project.ProjectRootNode;
import com.google.appinventor.shared.rpc.project.UserProject;
import com.google.appinventor.shared.rpc.project.youngandroid.NewYoungAndroidProjectParameters;
import com.google.appinventor.shared.rpc.project.youngandroid.YoungAndroidProjectNode;
import com.google.appinventor.shared.rpc.user.User;
import com.google.appinventor.shared.settings.SettingsConstants;
import com.google.appinventor.shared.storage.StorageUtil;
import com.google.appinventor.shared.youngandroid.YoungAndroidSourceAnalyzer;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import static junit.framework.Assert.*;
import junitx.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Tests for {@link ProjectServiceImpl}.
*
*/
@PowerMockIgnore({"javax.crypto.*" })
@RunWith(PowerMockRunner.class)
@PrepareForTest({ LocalUser.class })
public class ProjectServiceTest {
// If ProjectServiceTest (which uses PowerMock.mockStatic) extends LocalDatastoreTestCase, then
// it will fail with Ant version 1.8.2.
private final LocalDatastoreTestCase helper = LocalDatastoreTestCase.createHelper();
private static final String USER_ID_ONE = "id1";
private static final String USER_ID_TWO = "id2";
private static final String USER_EMAIL_ONE = "noname1@domain.com";
private static final String USER_EMAIL_TWO = "noname2@domain.com";
private static final String PROJECT1_NAME = "Project1";
private static final String PROJECT2_NAME = "Project2";
private static final String PROJECT3_NAME = "Project3";
private static final String PACKAGE_BASE = "com.domain.noname.";
private static final String YOUNG_ANDROID_COMMENT = ";;; Cat In The Hat by Dr. Seuss\n";
private static final String YOUNG_ANDROID_COMMENT1 = ";;; Don't Hop on Pop by Dr. Seuss\n";
private static final String YOUNG_ANDROID_COMMENT2 = ";;; Green Eggs and Ham by Dr. Seuss\n";
private static final int NUMBER_OF_SIMULTANEOUS_NEW_PROJECTS = 50;
private static final String YOUNG_ANDROID_PROJECT_SCM_SOURCE = "\n" +
"#|\n" +
"$JSON\n" +
"{\"Source\":\"Form\",\"Properties\":{\"$Name\":\"Screen1\",\"$Type\":\"Form\"," +
"\"Uuid\":\"0\",\"Title\":\"Screen1\",\"AppName\":\"noname\",\"$Components\":[" +
"{\"$Name\":\"Button1\",\"$Type\":\"Button\",\"Uuid\":\"123\",\"Text\":\"Button1\"," +
"\"Width\":\"80\"}," +
"{\"$Name\":\"Label1\",\"$Type\":\"Label\",\"Uuid\":\"-456\",\"Text\":\"Liz\"}" +
"]}}\n" +
"|#";
private StorageIo storageIo;
private ProjectServiceImpl projectServiceImpl; // for USER_ID_ONE
private ProjectServiceImpl projectServiceImpl2; // for USER_ID_TWO
private Map<String, ProjectServiceImpl> projectServiceImpls;
private LocalUser localUserMock;
public static final String KEYSTORE_ROOT_PATH = TestUtils.APP_INVENTOR_ROOT_DIR +
"/appengine/build/war/"; // must end with a slash
@Before
public void setUp() throws Exception {
helper.setUp();
storageIo = StorageIoInstanceHolder.INSTANCE;
PowerMock.mockStatic(LocalUser.class);
localUserMock = PowerMock.createMock(LocalUser.class);
expect(localUserMock.getSessionId()).andReturn("test-session").anyTimes();
localUserMock.setSessionId("test-session");
expectLastCall().times(1);
expect(LocalUser.getInstance()).andReturn(localUserMock).anyTimes();
localUserMock.set(new User("1", "NonSuch", "NoName", null, 0, false, false, 0, null));
expectLastCall().anyTimes();
KeyczarEncryptor.rootPath.setForTest(KEYSTORE_ROOT_PATH);
}
void do_init() {
storageIo.getUser(USER_ID_ONE, USER_EMAIL_ONE);
projectServiceImpl = new ProjectServiceImpl();
storageIo.getUser(USER_ID_TWO, USER_EMAIL_TWO);
projectServiceImpl2 = new ProjectServiceImpl();
projectServiceImpls = Maps.newHashMap();
projectServiceImpls.put(USER_ID_ONE, projectServiceImpl);
projectServiceImpls.put(USER_ID_TWO, projectServiceImpl2);
localUserMock.set(new User("1", "NonSuch", "NoName", null, 0, false, false, 0, null));
localUserMock.setSessionId("test-session");
}
@After
public void tearDown() throws Exception {
helper.tearDown();
PowerMock.resetAll();
}
private void checkModificationDateMatchesStored(long oldModificationDate, String userId,
long projectId) throws Exception {
long modificationDate = storageIo.getProjectDateModified(userId, projectId);
assertEquals(oldModificationDate, modificationDate);
}
@Test
public void testProjectService() throws Exception {
expect(localUserMock.getUserId()).andReturn(USER_ID_ONE).times(2);
expect(localUserMock.getUserId()).andReturn(USER_ID_TWO).times(2);
expect(localUserMock.getUserId()).andReturn(USER_ID_ONE).times(4);
expect(localUserMock.getUserId()).andReturn(USER_ID_TWO).times(2);
expect(localUserMock.getUserId()).andReturn(USER_ID_ONE).times(11);
PowerMock.replayAll();
do_init();
// Create a new young android project
NewYoungAndroidProjectParameters params = new NewYoungAndroidProjectParameters(
PACKAGE_BASE + PROJECT1_NAME);
long user1Project1 = projectServiceImpl.newProject(
YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE, PROJECT1_NAME, params).getProjectId();
long[] user1Projects = projectServiceImpl.getProjects();
assertTrue(user1Projects.length == 1 && user1Projects[0] == user1Project1);
// Create another young android project with the same name for another user
long user2Project1 = projectServiceImpl2.newProject(
YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE, PROJECT1_NAME, params).getProjectId();
long[] user2Projects = projectServiceImpl2.getProjects();
assertEquals(1, user2Projects.length);
assertEquals(user2Project1, user2Projects[0]);
// Change the source file in the second users project and make sure only that file
// got changed (and not the one of the same name owned by the first user)
ProjectRootNode user1Project1Root = projectServiceImpl.getProject(user1Project1);
String user1Project1Source1FileId = findFileIdByName(user1Project1Root,
YOUNG_ANDROID_FORM_NAME + YoungAndroidSourceAnalyzer.FORM_PROPERTIES_EXTENSION);
assertNotNull(user1Project1Source1FileId);
String user1Project1Source1 = projectServiceImpl.load(user1Project1,
user1Project1Source1FileId);
long oldModificationDate = storageIo.getProjectDateModified(USER_ID_ONE, user1Project1);
long modificationDate = projectServiceImpl.save("test-session", user1Project1, user1Project1Source1FileId,
YOUNG_ANDROID_COMMENT + user1Project1Source1);
assertEquals(YOUNG_ANDROID_COMMENT + user1Project1Source1,
projectServiceImpl.load(user1Project1, user1Project1Source1FileId));
assertTrue(oldModificationDate <= modificationDate);
checkModificationDateMatchesStored(modificationDate, USER_ID_ONE, user1Project1);
oldModificationDate = modificationDate;
ProjectRootNode user2Project1Root = projectServiceImpl2.getProject(user2Project1);
String user2Project1Source1FileId = findFileIdByName(user2Project1Root,
YOUNG_ANDROID_FORM_NAME + YoungAndroidSourceAnalyzer.FORM_PROPERTIES_EXTENSION);
assertNotNull(user2Project1Source1FileId);
Assert.assertNotEquals(YOUNG_ANDROID_COMMENT, projectServiceImpl2.load(user2Project1,
user2Project1Source1FileId));
// Create another new project for user1
params = new NewYoungAndroidProjectParameters(
PACKAGE_BASE + PROJECT2_NAME);
long user1Project2 = projectServiceImpl.newProject(
YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE, PROJECT2_NAME, params).getProjectId();
user1Projects = projectServiceImpl.getProjects();
assertTrue(user1Projects.length == 2);
ProjectRootNode user1Project2Root = projectServiceImpl.getProject(user1Project2);
String user1Project2Source1FileId = findFileIdByName(user1Project2Root,
YOUNG_ANDROID_FORM_NAME + YoungAndroidSourceAnalyzer.FORM_PROPERTIES_EXTENSION);
assertNotNull(user1Project2Source1FileId);
// Load and save multiple files
String u1p1s1 =
projectServiceImpl.load(user1Project1, user1Project1Source1FileId) + YOUNG_ANDROID_COMMENT1;
String u1p2s1 =
projectServiceImpl.load(user1Project2, user1Project2Source1FileId) + YOUNG_ANDROID_COMMENT2;
List<FileDescriptorWithContent> filesWithContent = Lists.newArrayList();
filesWithContent.add(new FileDescriptorWithContent(user1Project1, user1Project1Source1FileId,
u1p1s1));
filesWithContent.add(new FileDescriptorWithContent(user1Project2, user1Project2Source1FileId,
u1p2s1));
checkModificationDateMatchesStored(oldModificationDate, USER_ID_ONE, user1Project1);
modificationDate = projectServiceImpl.save("test-session", filesWithContent);
assertTrue(oldModificationDate <= modificationDate);
checkModificationDateMatchesStored(modificationDate, USER_ID_ONE, user1Project2);
oldModificationDate = modificationDate;
List<FileDescriptor> files = Lists.newArrayList();
files.add(new FileDescriptor(user1Project1, user1Project1Source1FileId));
files.add(new FileDescriptor(user1Project2, user1Project2Source1FileId));
filesWithContent = projectServiceImpl.load(files);
assertEquals(files.size(), filesWithContent.size());
FileDescriptorWithContent fileWithContent = findFileDescriptorWithContent(filesWithContent,
user1Project1, user1Project1Source1FileId);
assertNotNull(fileWithContent);
assertEquals(u1p1s1, fileWithContent.getContent());
fileWithContent = findFileDescriptorWithContent(filesWithContent, user1Project2,
user1Project2Source1FileId);
assertNotNull(fileWithContent);
assertEquals(u1p2s1, fileWithContent.getContent());
oldModificationDate = storageIo.getProjectDateModified(USER_ID_ONE, user1Project1);
modificationDate = projectServiceImpl.deleteFile("test-session", user1Project1, user1Project1Source1FileId);
assertTrue(oldModificationDate <= modificationDate);
checkModificationDateMatchesStored(modificationDate, USER_ID_ONE, user1Project1);
oldModificationDate = modificationDate;
// Delete the projects of the first user
projectServiceImpl.deleteProject(user1Project1);
projectServiceImpl.deleteProject(user1Project2);
user1Projects = projectServiceImpl.getProjects();
assertTrue(user1Projects.length == 0);
PowerMock.verifyAll();
}
@Test
public void testNewYoungAndroidProject() throws Exception {
// Since only USER_ID_ONE is used, we don't care how many times
// getUserId is called
expect(localUserMock.getUserId()).andReturn(USER_ID_ONE).anyTimes();
PowerMock.replayAll();
do_init();
// First create a Young Android project.
NewYoungAndroidProjectParameters params = new NewYoungAndroidProjectParameters(
PACKAGE_BASE + PROJECT1_NAME);
long yaProject =
projectServiceImpl.newProject(YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE,
PROJECT1_NAME, params).getProjectId();
// Check the contents of each file in the new project.
Map<String, String> expectedYaFiles = new HashMap<String, String>();
expectedYaFiles.put("src/com/domain/noname/Project1/Screen1.bky", "");
expectedYaFiles.put("src/com/domain/noname/Project1/Screen1.yail", "");
expectedYaFiles.put("youngandroidproject/project.properties",
"main=com.domain.noname.Project1.Screen1\n" +
"name=Project1\n" +
"assets=../assets\n" +
"source=../src\n" +
"build=../build\n");
expectedYaFiles.put("src/com/domain/noname/Project1/Screen1.scm",
"#|\n$JSON\n" +
"{\"authURL\":[]," +
"\"YaVersion\":\"" + YaVersion.YOUNG_ANDROID_VERSION + "\",\"Source\":\"Form\"," +
"\"Properties\":{\"$Name\":\"Screen1\",\"$Type\":\"Form\"," +
"\"$Version\":\"" + YaVersion.FORM_COMPONENT_VERSION + "\",\"Uuid\":\"0\"," +
"\"Title\":\"Screen1\","+"\"AppName\":\"noname\"}}\n|#");
assertEquals(expectedYaFiles, getTextFiles(USER_ID_ONE, yaProject));
assertTrue(getNonTextFiles(USER_ID_ONE, yaProject).isEmpty());
checkUserProjects(projectServiceImpl.getProjectInfos(),
new UserProject(yaProject, PROJECT1_NAME,
YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE, System.currentTimeMillis(), System.currentTimeMillis(), 0L, 0L));
PowerMock.verifyAll();
}
@Test
public void testCopyProject() throws Exception {
// Since only USER_ID_ONE is used in this test, we don't care how
// many times getUser or getUserId are called; they'll always
// return the same result
expect(localUserMock.getUserId()).andReturn(USER_ID_ONE).anyTimes();
expect(localUserMock.getUser()).andReturn(storageIo.getUser(USER_ID_ONE, USER_EMAIL_ONE)).anyTimes();
PowerMock.replayAll();
do_init();
// First create a Young Android project.
long yaProject1 = getBuildableYoungAndroidProjectId(USER_ID_ONE, PROJECT1_NAME);
// Check the contents of each file in the new project.
Map<String, String> expectedYaFiles1 = new HashMap<String, String>();
expectedYaFiles1.put("src/com/domain/noname/Project1/Screen1.bky", "");
expectedYaFiles1.put("src/com/domain/noname/Project1/Screen1.yail", "");
expectedYaFiles1.put("youngandroidproject/project.properties",
"main=com.domain.noname.Project1.Screen1\n" +
"name=Project1\n" +
"assets=../assets\n" +
"source=../src\n" +
"build=../build\n");
expectedYaFiles1.put("src/com/domain/noname/Project1/Screen1.scm",
YOUNG_ANDROID_PROJECT_SCM_SOURCE);
assertEquals(expectedYaFiles1, getTextFiles(USER_ID_ONE, yaProject1));
assertTrue(getNonTextFiles(USER_ID_ONE, yaProject1).isEmpty());
// No user files yet (e.g. the keystore)
assertTrue(getUserFiles(USER_ID_ONE).isEmpty());
UserProject uproject = storageIo.getUserProject(USER_ID_ONE, yaProject1);
long project1CreationDate = uproject.getDateCreated();
long project1ModificationDate = uproject.getDateModified();
assertTrue(project1ModificationDate >= project1CreationDate);
// Make a copy of project 1.
long yaProject2 = projectServiceImpl.copyProject(yaProject1, PROJECT2_NAME).
getProjectId();
// Check the contents of each file in the new project.
Map<String, String> expectedYaFiles2 = new HashMap<String, String>();
expectedYaFiles2.put("src/com/domain/noname/Project2/Screen1.bky", "");
expectedYaFiles2.put("src/com/domain/noname/Project2/Screen1.yail", "");
expectedYaFiles2.put("youngandroidproject/project.properties",
"main=appinventor.ai_noname1.Project2.Screen1\n" +
"name=Project2\n" +
"assets=../assets\n" +
"source=../src\n" +
"build=../build\n" +
"versioncode=1\n" +
"versionname=1.0\n" +
"useslocation=false\n" +
"aname=Project1\n" +
"sizing=Fixed\n" +
"showlistsasjson=false\n");
expectedYaFiles2.put("src/com/domain/noname/Project2/Screen1.scm",
YOUNG_ANDROID_PROJECT_SCM_SOURCE);
assertEquals(expectedYaFiles2, getTextFiles(USER_ID_ONE, yaProject2));
assertTrue(getNonTextFiles(USER_ID_ONE, yaProject2).isEmpty());
assertTrue(getUserFiles(USER_ID_ONE).isEmpty());
UserProject uproject1 = storageIo.getUserProject(USER_ID_ONE, yaProject2);
long project1CopyCreationDate = uproject1.getDateCreated();
long project1CopyModificationDate = uproject1.getDateModified();
assertTrue(project1CopyCreationDate > project1CreationDate);
assertTrue(project1CopyCreationDate > project1ModificationDate);
assertTrue(project1CopyModificationDate >= project1CopyCreationDate);
PowerMock.verifyAll();
}
/**
* Creates a new Young Android project with non-empty source
* in the test storage instance and returns its project id.
*
* @param projectName name of the Young Android project.
* @return the project id of the Young Android project in the test storage
* instance.
*/
private long getBuildableYoungAndroidProjectId(String userId, String projectName) {
NewYoungAndroidProjectParameters params = new NewYoungAndroidProjectParameters(
PACKAGE_BASE + projectName);
ProjectServiceImpl impl = projectServiceImpls.get(userId);
long projectId =
impl.newProject(YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE,
projectName, params).getProjectId();
String scmFileId = "src/com/domain/noname/" + projectName + "/"
+ YOUNG_ANDROID_FORM_NAME + ".scm";
try {
storageIo.uploadFile(projectId, scmFileId,
userId, YOUNG_ANDROID_PROJECT_SCM_SOURCE, StorageUtil.DEFAULT_CHARSET);
} catch (BlocksTruncatedException e) {
// Won't happen
}
return projectId;
}
@Test
public void testCreateManyYoungAndroidProjects() throws Exception {
// Since only USER_ID_ONE is used in this test, we don't care how
// many times getUser or getUserId are called; they'll always
// return the same result
expect(localUserMock.getUserId()).andReturn(USER_ID_ONE).anyTimes();
expect(localUserMock.getUser()).andReturn(storageIo.getUser(USER_ID_ONE, USER_EMAIL_ONE)).anyTimes();
PowerMock.replayAll();
do_init();
List<Thread> threads = Lists.newArrayList();
final AtomicInteger ready = new AtomicInteger();
final Object start = new Object();
final AtomicInteger successes = new AtomicInteger();
final AtomicInteger failures = new AtomicInteger();
int numThreads = NUMBER_OF_SIMULTANEOUS_NEW_PROJECTS;
for (int i = 0; i < numThreads; i++) {
final String projectName = "Project" + i;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
// We need to set up the LocalServiceTestHelper here because
// otherwise each thread tries to access the real storage.
// TODO(user): Does this test still test the right
// thing, given that?
helper.setUpThread();
// The first thing each thread does is signal that it is ready and then wait for the
// start notification.
synchronized (start) {
ready.incrementAndGet();
try {
start.wait();
} catch (InterruptedException e) {
// do nothing
}
}
NewYoungAndroidProjectParameters params = new NewYoungAndroidProjectParameters(
PACKAGE_BASE + projectName);
long projectId =
projectServiceImpl.newProject(YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE,
projectName, params).getProjectId();
if (projectId < 0) {
failures.incrementAndGet();
} else {
successes.incrementAndGet();
}
}
});
threads.add(t);
t.start();
}
// Tell all threads to start.
// We can't enter the synchronized (start) block until all the threads have told us they are
// ready. Otherwise, a thread could miss the notification and wait forever.
while (ready.get() < numThreads) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// do nothing
}
}
synchronized (start) {
start.notifyAll();
}
// Wait for all threads to finish.
for (Thread t : threads) {
t.join();
}
assertEquals(numThreads, successes.get());
assertEquals(0, failures.get());
PowerMock.verifyAll();
}
@Test
public void testLoadAndStoreProjectSettings() throws Exception {
// Since only USER_ID_ONE is used in this test, we don't care how
// many times getUser or getUserId are called; they'll always
// return the same result
expect(localUserMock.getUserId()).andReturn(USER_ID_ONE).anyTimes();
expect(localUserMock.getUser()).andReturn(storageIo.getUser(USER_ID_ONE, USER_EMAIL_ONE)).anyTimes();
PowerMock.replayAll();
do_init();
NewYoungAndroidProjectParameters params = new NewYoungAndroidProjectParameters(
PACKAGE_BASE + PROJECT1_NAME);
long projectId = projectServiceImpl.newProject(
YoungAndroidProjectNode.YOUNG_ANDROID_PROJECT_TYPE, PROJECT1_NAME, params).getProjectId();
String loadedSettings = projectServiceImpl.loadProjectSettings(projectId);
assertEquals(
"{\"" + SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS + "\":" +
"{\"" + SettingsConstants.YOUNG_ANDROID_SETTINGS_ICON + "\":\"\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_VERSION_CODE + "\":\"1\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_VERSION_NAME + "\":\"1.0\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_USES_LOCATION + "\":\"false\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_APP_NAME + "\":\"Project1\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_SIZING + "\":\"Fixed\",\"" +
SettingsConstants.YOUNG_ANDROID_SETTINGS_SHOW_LISTS_AS_JSON + "\":\"false\"}}",
loadedSettings);
String storedSettings =
"{\"" + SettingsConstants.PROJECT_YOUNG_ANDROID_SETTINGS + "\":" +
"{\"" + SettingsConstants.YOUNG_ANDROID_SETTINGS_ICON + "\":\"KittyIcon.png\"}}";
projectServiceImpl.storeProjectSettings("test-session", projectId, storedSettings);
loadedSettings = projectServiceImpl.loadProjectSettings(projectId);
assertEquals(storedSettings, loadedSettings);
PowerMock.verifyAll();
}
private Map<String, String> getTextFiles(String userId, long projectId) {
Map<String, String> textFiles = new HashMap<String, String>();
for (String fileId : storageIo.getProjectSourceFiles(userId, projectId)) {
if (StorageUtil.isTextFile(fileId)) {
// TODO(user): We should get rid of DEFAULT_CHARSET and use UTF-8 everywhere.
textFiles.put(fileId,
storageIo.downloadFile(userId, projectId, fileId,
StorageUtil.DEFAULT_CHARSET));
}
}
return textFiles;
}
private Map<String, byte[]> getNonTextFiles(String userId, long projectId) {
Map<String, byte[]> nonTextFiles = new HashMap<String, byte[]>();
for (String fileId : storageIo.getProjectSourceFiles(userId, projectId)) {
if (!StorageUtil.isTextFile(fileId)) {
nonTextFiles.put(fileId,
storageIo.downloadRawFile(userId, projectId, fileId));
}
}
return nonTextFiles;
}
private Map<String, byte[]> getUserFiles(String userId) {
Map<String, byte[]> userFiles = new HashMap<String, byte[]>();
for (String fileId : storageIo.getUserFiles(userId)) {
userFiles.put(fileId,
storageIo.downloadRawUserFile(userId, fileId));
}
return userFiles;
}
private static String findFileIdByName(ProjectNode parent, String name) {
if (parent.getName().equals(name)) {
return parent.getFileId();
}
for (ProjectNode node : parent.getChildren()) {
String fileId = findFileIdByName(node, name);
if (fileId != null) {
return fileId;
}
}
return null;
}
private static FileDescriptorWithContent findFileDescriptorWithContent(
List<FileDescriptorWithContent> filesWithContent, long projectId, String fileId) {
for (FileDescriptorWithContent fileWithContent : filesWithContent) {
if (fileWithContent.getProjectId() == projectId &&
fileWithContent.getFileId().equals(fileId)) {
return fileWithContent;
}
}
return null;
}
private void checkUserProjects(List<UserProject> actual, UserProject... expected)
throws Exception {
if (actual.size() != expected.length) {
fail("expected <" + expected.length + "> UserProjects but was:<" + actual.size() + '>');
}
// Build a map from project id to UserProject for the actual projects so we won't nested
// for loops below.
// Also, build a String to describe the actual UserProjects that we can use in failure messages.
Map<Long, UserProject> actualByProjectId = Maps.newHashMap();
StringBuilder actualDesc = new StringBuilder();
String delimiter = "";
for (UserProject actualUserProject : actual) {
actualByProjectId.put(actualUserProject.getProjectId(), actualUserProject);
actualDesc.append(delimiter).append(getUserProjectDesc(actualUserProject));
delimiter = ",";
}
for (UserProject expectedUserProject : expected) {
long projectId = expectedUserProject.getProjectId();
UserProject actualUserProject = actualByProjectId.get(projectId);
if (actualUserProject == null) {
fail("expected to contain:<" + getUserProjectDesc(expectedUserProject) +
"> but was:<" + actualDesc + '>');
}
if (!Objects.equal(expectedUserProject.getProjectName(),
actualUserProject.getProjectName())) {
fail("expected project name:<" + expectedUserProject.getProjectName() + "> but was:<" +
actualUserProject.getProjectName() + '>');
}
if (!Objects.equal(expectedUserProject.getProjectType(),
actualUserProject.getProjectType())) {
fail("expected project type:<" + expectedUserProject.getProjectType() + "> but was:<" +
actualUserProject.getProjectType() + '>');
}
// Expected user project date was created after actual user project
if (expectedUserProject.getDateCreated() < actualUserProject.getDateCreated()) {
fail("expected date:<" + expectedUserProject.getDateCreated() + "> but was:<" +
actualUserProject.getDateCreated() + '>');
}
}
}
private static String getUserProjectDesc(UserProject userProject) {
return "UserProject(" + userProject.getProjectId() + ",\"" +
userProject.getProjectName() + "\")";
}
}