/*
* Copyright 2014 Bernd Vogt and others.
*
* 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 org.sourcepit.b2.execution;
import static org.junit.Assert.assertThat;
import static org.sourcepit.b2.directory.parser.internal.module.ModelBuilderTestHarness.createModuleDirectory;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import javax.inject.Inject;
import org.hamcrest.core.Is;
import org.sourcepit.b2.directory.parser.internal.module.ModelBuilderTestHarness;
import org.sourcepit.b2.directory.parser.module.IModuleParsingRequest;
import org.sourcepit.b2.directory.parser.module.ModuleParserLifecycleParticipant;
import org.sourcepit.b2.files.ModuleDirectory;
import org.sourcepit.b2.internal.generator.B2GeneratorLifecycleParticipant;
import org.sourcepit.b2.internal.generator.DefaultTemplateCopier;
import org.sourcepit.b2.model.builder.internal.tests.harness.AbstractB2SessionWorkspaceTest;
import org.sourcepit.b2.model.interpolation.module.ModuleInterpolatorLifecycleParticipant;
import org.sourcepit.b2.model.module.AbstractModule;
import org.sourcepit.common.utils.content.ContentTypes;
import org.sourcepit.common.utils.lang.ThrowablePipe;
import org.sourcepit.common.utils.props.PropertiesSource;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.name.Names;
public class LifecycleParticipantsTest extends AbstractB2SessionWorkspaceTest {
@Inject
private B2LifecycleRunner b2LifecycleRunner;
private LifecycleParticipant participant;
@Override
public void configure(Binder binder) {
super.configure(binder);
participant = new LifecycleParticipant();
binder.bind(newKey(B2SessionLifecycleParticipant.class, participant)).toInstance(participant);
binder.bind(newKey(ModuleParserLifecycleParticipant.class, participant)).toInstance(participant);
binder.bind(newKey(ModuleInterpolatorLifecycleParticipant.class, participant)).toInstance(participant);
binder.bind(newKey(B2GeneratorLifecycleParticipant.class, participant)).toInstance(participant);
}
private <T> Key<T> newKey(Class<T> type, LifecycleParticipant participant) {
return Key.get(type, Names.named(participant.getClass().getName()));
}
@Override
protected String setUpModulePath() {
return "composed-component";
}
public void testAll() throws Exception {
final Map<File, AbstractModule> modules = new LinkedHashMap<File, AbstractModule>();
final B2RequestFactory requestFactory = new B2RequestFactory() {
public B2Request newRequest(List<File> projectDirs, int currentIdx) {
File moduleDir = projectDirs.get(currentIdx);
B2Request request = new B2Request();
request.setModuleDirectory(new ModuleDirectory(moduleDir, null));
request.setModuleProperties(ModelBuilderTestHarness.newProperties(moduleDir));
request.setInterpolate(true);
request.setTemplates(new DefaultTemplateCopier());
request.getModulesCache().putAll(modules);
request.setModuleDirectory(createModuleDirectory(moduleDir,
projectDirs.toArray(new File[projectDirs.size()])));
request.setContentTypes(ContentTypes.DEFAULT);
return request;
}
};
final List<File> projectDirs = getModuleDirs();
for (int i = 0; i < projectDirs.size(); i++) {
final B2Request b2Request = requestFactory.newRequest(projectDirs, i);
final AbstractModule module = b2LifecycleRunner.prepareNext(projectDirs, i, b2Request);
modules.put(module.getDirectory(), module);
}
int idx = 0;
while (b2LifecycleRunner.finalizeNext(projectDirs, idx++)) { // noop
}
List<String> actualCalls = new ArrayList<String>();
List<MethodCall> calls = participant.getCalls();
assertThat(calls.size(), Is.is(34));
final List<String> excpectedCalls = new ArrayList<String>();
excpectedCalls.add("prePrepareProjects ( session )");
for (int i = 0; i < calls.size(); i++) {
String call = toString(calls.get(i));
actualCalls.add(call);
if (i == 1) {
if (call.startsWith("prePrepareProject ( session, simple-layout")) // order not defined :(
{
addPrepareCalls(excpectedCalls, "simple-layout", "simple-layout",
"org.sourcepit.b2.test.resources.simple.layout");
addPrepareCalls(excpectedCalls, "structured-layout", "structured-layout",
"org.sourcepit.b2.test.resources.structured.layout");
}
else {
addPrepareCalls(excpectedCalls, "structured-layout", "structured-layout",
"org.sourcepit.b2.test.resources.structured.layout");
addPrepareCalls(excpectedCalls, "simple-layout", "simple-layout",
"org.sourcepit.b2.test.resources.simple.layout");
}
}
else if (i == 27) {
// project composite-layout
addPrepareCalls(excpectedCalls, "testAll", "composite-layout",
"org.sourcepit.b2.test.resources.composite.layout");
excpectedCalls.add("postPrepareProjects ( session, null )");
// finalize
excpectedCalls.add("preFinalizeProjects ( session )");
if (call.startsWith("preFinalizeProject ( session, simple-layout")) {
// project simple-layout
addFinalizeCalls(excpectedCalls, "simple-layout", "simple-layout",
"org.sourcepit.b2.test.resources.simple.layout");
// project structured-layout
addFinalizeCalls(excpectedCalls, "structured-layout", "structured-layout",
"org.sourcepit.b2.test.resources.structured.layout");
}
else {
// project structured-layout
addFinalizeCalls(excpectedCalls, "structured-layout", "structured-layout",
"org.sourcepit.b2.test.resources.structured.layout");
// project simple-layout
addFinalizeCalls(excpectedCalls, "simple-layout", "simple-layout",
"org.sourcepit.b2.test.resources.simple.layout");
}
// project composite-layout
addFinalizeCalls(excpectedCalls, "testAll", "composite-layout",
"org.sourcepit.b2.test.resources.composite.layout");
excpectedCalls.add("postFinalizeProjects ( session, null )");
}
}
StringBuilder message = new StringBuilder();
Iterator<String> actual = actualCalls.iterator();
Iterator<String> expected = excpectedCalls.iterator();
int i = 0;
while (expected.hasNext()) {
String expectedCall = expected.next();
assertEquals(message.toString(), expectedCall, actual.next());
message.append(i);
message.append(" ");
message.append(expectedCall);
message.append("\n");
i++;
}
assertSame(excpectedCalls.size(), actualCalls.size());
}
private void addFinalizeCalls(List<String> excpectedCalls, String folderName, String artifactId, String moduleId) {
// project composite-layout
excpectedCalls.add("preFinalizeProject ( session, " + folderName + " )");
excpectedCalls.add("postFinalizeProject ( session, " + folderName + ", null )");
}
private void addPrepareCalls(List<String> excpectedCalls, String folderName, String artifactId, String moduleId) {
excpectedCalls.add("prePrepareProject ( session, " + folderName + ", request )");
excpectedCalls.add("preParse ( " + folderName + " )");
excpectedCalls.add("postParse ( " + folderName + ", " + moduleId + ", null )");
excpectedCalls.add("preInterpolation ( " + moduleId + " )");
excpectedCalls.add("postInterpolation ( " + moduleId + ", null )");
excpectedCalls.add("preGenerate ( " + moduleId + " )");
excpectedCalls.add("postGenerate ( " + moduleId + ", null )");
excpectedCalls.add("postPrepareProject ( session, " + folderName + ", request, " + moduleId + ", null )");
}
private String toString(MethodCall call) {
StringBuilder sb = new StringBuilder();
sb.append(call.getMethodName());
sb.append(" ( ");
Object[] args = call.getArgs();
for (Object arg : args) {
sb.append(arg);
sb.append(", ");
}
if (args.length > 0) {
sb.deleteCharAt(sb.length() - 1);
sb.deleteCharAt(sb.length() - 1);
}
sb.append(" )");
return sb.toString();
}
public static class MethodCall {
private String className;
private String methodName;
private Object[] args;
public MethodCall(String className, String methodName, Object[] args) {
this.className = className;
this.methodName = methodName;
this.args = args;
}
public String getClassName() {
return className;
}
public String getMethodName() {
return methodName;
}
public Object[] getArgs() {
return args;
}
}
private static class LifecycleParticipant
implements
B2SessionLifecycleParticipant,
ModuleParserLifecycleParticipant,
ModuleInterpolatorLifecycleParticipant,
B2GeneratorLifecycleParticipant {
private List<MethodCall> calls = new ArrayList<MethodCall>();
private Stack<File> barrier = new Stack<File>();
public List<MethodCall> getCalls() {
return calls;
}
private void recordMethodCall(Object... args) {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
StackTraceElement element = elements[2];
String className = element.getClassName();
String methodName = element.getMethodName();
calls.add(new MethodCall(className, methodName, args));
}
public void prePrepareProjects(List<File> projectDirs) {
recordMethodCall("session");
}
public void prePrepareProject(File projectDir, B2Request request) {
recordMethodCall("session", projectDir.getName(), "request");
}
public void preParse(IModuleParsingRequest request) {
if (!barrier.isEmpty()) {
throw new IllegalStateException("Nested module parsing detected");
}
final File moduleDir = request.getModuleDirectory().getFile();
barrier.push(moduleDir);
assertNotNull(moduleDir);
assertTrue(moduleDir.exists());
recordMethodCall(moduleDir.getName());
}
public void postParse(IModuleParsingRequest request, AbstractModule module, ThrowablePipe errors) {
barrier.pop();
if (!errors.isEmpty()) {
return;
}
final File moduleDir = request.getModuleDirectory().getFile();
assertNotNull(moduleDir);
assertTrue(moduleDir.exists());
assertNotNull(module);
assertEquals(moduleDir, module.getDirectory());
assertNotNull(errors);
recordMethodCall(moduleDir.getName(), module.getId(), errors.isEmpty() ? null : errors);
}
public void preInterpolation(AbstractModule module, PropertiesSource moduleProperties) {
assertNotNull(module);
recordMethodCall(module.getId());
}
public void postInterpolation(AbstractModule module, PropertiesSource moduleProperties, ThrowablePipe errors) {
assertNotNull(module);
assertNotNull(errors);
assertTrue(errors.isEmpty());
recordMethodCall(module.getId(), errors.isEmpty() ? null : errors);
}
public void preGenerate(AbstractModule module) {
assertNotNull(module);
recordMethodCall(module.getId());
}
public void postGenerate(AbstractModule module, ThrowablePipe errors) {
assertNotNull(module);
assertNotNull(errors);
assertTrue(errors.isEmpty());
recordMethodCall(module.getId(), errors.isEmpty() ? null : errors);
}
public void postPrepareProject(File projectDir, B2Request request, AbstractModule module, ThrowablePipe errors) {
recordMethodCall("session", projectDir.getName(), "request", module.getId(), errors.isEmpty() ? null : errors);
}
public void postPrepareProjects(List<File> projectDirs, ThrowablePipe errors) {
recordMethodCall("session", errors.isEmpty() ? null : errors);
}
public void preFinalizeProjects(List<File> projectDirs) {
recordMethodCall("session");
}
public void preFinalizeProject(File projectDir) {
recordMethodCall("session", projectDir.getName());
}
public void postFinalizeProject(File projectDir, ThrowablePipe errors) {
recordMethodCall("session", projectDir.getName(), errors.isEmpty() ? null : errors);
}
public void postFinalizeProjects(List<File> projectDirs, ThrowablePipe errors) {
recordMethodCall("session", errors.isEmpty() ? null : errors);
}
}
}