/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.jstestdriver.server;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Singleton;
import com.google.jstestdriver.FileInfo;
import com.google.jstestdriver.FilesCache;
import com.google.jstestdriver.model.JstdTestCase;
import com.google.jstestdriver.model.JstdTestCaseDelta;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* A store for JstdTestCases.
* @author corysmith@google.com (Cory Smith)
*
*/
@Singleton
public class JstdTestCaseStore {
private static final Logger logger = LoggerFactory.getLogger(JstdTestCaseStore.class);
private final ConcurrentMap<String, JstdTestCase> cases =
new ConcurrentHashMap<String, JstdTestCase>();
private final FilesCache files = new FilesCache(Maps.<String, FileInfo>newHashMap());
/**
* Adds a testcase to the store, returning a delta of files that need to be
* loaded.
*/
public JstdTestCaseDelta addCase(JstdTestCase testCase) {
JstdTestCase updatedTestCase;
synchronized (files) {
updatedTestCase = testCase.applyDelta(new JstdTestCaseDelta(
updateCache(testCase.getDependencies()),
updateCache(testCase.getTests()),
updateCache(testCase.getPlugins())));
}
logger.info("adding TestCase {} to {}", testCase.getId(), this);
cases.put(testCase.getId(), updatedTestCase);
return updatedTestCase.createUnloadedDelta();
}
/**
* Updates the files cache with files and returns ones that are already to
* update the testcase with.
*/
private List<FileInfo> updateCache(List<FileInfo> newFiles) {
List<FileInfo> replace = Lists.newArrayList();
for (FileInfo file : newFiles) {
FileInfo oldFile = files.getFile(file.getDisplayPath());
if (oldFile == null) {
files.addFile(file);
logger.debug("adding {}", file.getDisplayPath());
} else if (oldFile.shouldReplaceWith(file)) {
logger.debug("replacing {}", oldFile.getDisplayPath());
files.addFile(file);
} else if (file.isLoaded()) {
logger.debug("updating {} (loaded)", file.getDisplayPath());
files.addFile(file);
} else if (oldFile.isLoaded() && !file.isLoaded()){
logger.debug("not replacing {}", file.getDisplayPath());
// the old file the same as the new, except the old is loaded.
replace.add(oldFile);
} else {
logger.debug("files are equal {}", file.getDisplayPath());
}
}
return replace;
}
/**
* Returns a collection of all the test cases.
*/
public Collection<JstdTestCase> getCases() {
return cases.values();
}
/**
* Retrieve a test case from the store.
*/
public JstdTestCase getCase(String testCaseId) {
if (testCaseId == null) {
return null;
}
return cases.get(testCaseId);
}
/**
* Returns the contents of a given filename.
*/
// TODO(corysmith): Workaround until the semantics of loading files are worked
// out. Ideally, there should be some way of associating a file with a slaved browser.
public String getFileContent(String path) {
return files.getFileContent(path);
}
/**
* Applies a JstdTestCaseDelta to the file cache and all test cases.
*/
public void applyDelta(JstdTestCaseDelta delta) {
synchronized (files) {
updateCache(delta.getDependencies());
updateCache(delta.getTests());
updateCache(delta.getPlugins());
}
synchronized (cases) {
Map<String, JstdTestCase> applied = Maps.newHashMap();
for (Entry<String, JstdTestCase> entry : cases.entrySet()) {
applied.put(entry.getKey(), entry.getValue().applyDelta(delta));
}
cases.putAll(applied);
}
}
}