提交 13ac5a7e 编写于 作者: K kohsuke

perform syntax checks on Jelly scripts

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@21577 71c3de6d-444a-0410-be80-ed276b4c234a
上级 8f45c551
......@@ -11,6 +11,7 @@ import hudson.tasks.Builder;
import hudson.Launcher;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.io.IOException;
/**
......@@ -26,26 +27,12 @@ public abstract class GroovyHudsonTestCase extends HudsonTestCase {
* <p>
* The closure will get the request and response as parameters.
*/
public Object executeOnServer(final Closure c) throws Throwable {
final Throwable[] t = new Throwable[1];
final Object[] r = new Object[1];
ClosureExecuterAction cea = hudson.getExtensionList(RootAction.class).get(ClosureExecuterAction.class);
UUID id = UUID.randomUUID();
cea.add(id,new Runnable() {
public void run() {
try {
r[0] = c.call();
} catch (Throwable e) {
t[0] = e;
}
public Object executeOnServer(final Closure c) throws Exception {
return executeOnServer(new Callable<Object>() {
public Object call() throws Exception {
return c.call();
}
});
createWebClient().goTo("closures/?uuid="+id);
if (t[0]!=null)
throw t[0];
return r[0];
}
/**
......
......@@ -88,6 +88,7 @@ import java.util.Locale;
import java.util.Arrays;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.jar.Manifest;
import java.util.logging.Filter;
import java.util.logging.Level;
......@@ -144,7 +145,6 @@ import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
import com.gargoylesoftware.htmlunit.javascript.host.Stylesheet;
import com.gargoylesoftware.htmlunit.javascript.host.XMLHttpRequest;
import groovy.lang.Closure;
/**
* Base class for all Hudson test cases.
......@@ -727,18 +727,22 @@ public abstract class HudsonTestCase extends TestCase {
protected void recipe() throws Exception {
recipeLoadCurrentPlugin();
// look for recipe meta-annotation
Method runMethod= getClass().getMethod(getName());
for( final Annotation a : runMethod.getAnnotations() ) {
Recipe r = a.annotationType().getAnnotation(Recipe.class);
if(r==null) continue;
final Runner runner = r.value().newInstance();
recipes.add(runner);
tearDowns.add(new LenientRunnable() {
public void run() throws Exception {
runner.tearDown(HudsonTestCase.this,a);
}
});
runner.setup(this,a);
try {
Method runMethod= getClass().getMethod(getName());
for( final Annotation a : runMethod.getAnnotations() ) {
Recipe r = a.annotationType().getAnnotation(Recipe.class);
if(r==null) continue;
final Runner runner = r.value().newInstance();
recipes.add(runner);
tearDowns.add(new LenientRunnable() {
public void run() throws Exception {
runner.tearDown(HudsonTestCase.this,a);
}
});
runner.setup(this,a);
}
} catch (NoSuchMethodException e) {
// not a plain JUnit test.
}
}
......@@ -855,6 +859,7 @@ public abstract class HudsonTestCase extends TestCase {
return this;
}
/**
* Executes the given closure on the server, in the context of an HTTP request.
* This is useful for testing some methods that require {@link StaplerRequest} and {@link StaplerResponse}.
......@@ -862,17 +867,17 @@ public abstract class HudsonTestCase extends TestCase {
* <p>
* The closure will get the request and response as parameters.
*/
public Object executeOnServer(final Closure c) throws Throwable {
final Throwable[] t = new Throwable[1];
final Object[] r = new Object[1];
public <V> V executeOnServer(final Callable<V> c) throws Exception {
final Exception[] t = new Exception[1];
final List<V> r = new ArrayList<V>(1); // size 1 list
ClosureExecuterAction cea = hudson.getExtensionList(RootAction.class).get(ClosureExecuterAction.class);
UUID id = UUID.randomUUID();
cea.add(id,new Runnable() {
public void run() {
try {
r[0] = c.call();
} catch (Throwable e) {
r.add(c.call());
} catch (Exception e) {
t[0] = e;
}
}
......@@ -881,7 +886,7 @@ public abstract class HudsonTestCase extends TestCase {
if (t[0]!=null)
throw t[0];
return r[0];
return r.get(0);
}
/**
......
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.hudson.test;
import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.apache.commons.io.FileUtils;
import org.jvnet.hudson.test.junit.GroupedTest;
import org.kohsuke.stapler.MetaClassLoader;
import org.kohsuke.stapler.jelly.JellyClassLoaderTearOff;
import java.io.File;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.concurrent.Callable;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* Builds up a {@link TestSuite} for performing static syntax checks on Jelly scripts.
*
* @author Kohsuke Kawaguchi
*/
public class JellyTestSuiteBuilder {
/**
* Given a jar file or a class file directory, recursively search all the Jelly files and build a {@link TestSuite}
* that performs static syntax checks.
*/
public static TestSuite build(File res) throws Exception {
TestSuite ts = new JellyTestSuite();
final JellyClassLoaderTearOff jct = new MetaClassLoader(JellyTestSuiteBuilder.class.getClassLoader()).loadTearOff(JellyClassLoaderTearOff.class);
if (res.isDirectory()) {
for (final File jelly : (Collection <File>)FileUtils.listFiles(res,new String[]{"jelly"},true))
ts.addTest(new JellyCheck(jelly.toURI().toURL(), jct));
}
if (res.getName().endsWith(".jar")) {
String jarUrl = res.toURI().toURL().toExternalForm();
JarFile jf = new JarFile(res);
Enumeration<JarEntry> e = jf.entries();
while (e.hasMoreElements()) {
JarEntry ent = e.nextElement();
if (ent.getName().endsWith(".jelly"))
ts.addTest(new JellyCheck(new URL("jar:"+jarUrl+"!/"+ent.getName()), jct));
}
jf.close();
}
return ts;
}
private static class JellyCheck extends TestCase {
private final URL jelly;
private final JellyClassLoaderTearOff jct;
public JellyCheck(URL jelly, JellyClassLoaderTearOff jct) {
super(jelly.getPath());
this.jelly = jelly;
this.jct = jct;
}
@Override
protected void runTest() throws Exception {
jct.createContext().compileScript(jelly);
// TODO: what else can we check statically? use of taglibs?
}
}
/**
* Execute all the Jelly tests in a servlet request handling context. To do so, we reuse HudsonTestCase
*/
private static final class JellyTestSuite extends GroupedTest {
HudsonTestCase h = new HudsonTestCase("Jelly test wrapper") {};
@Override
protected void setUp() throws Exception {
h.setUp();
}
@Override
protected void tearDown() throws Exception {
h.tearDown();
}
private void doTests(TestResult result) throws Exception {
super.runGroupedTests(result);
}
@Override
protected void runGroupedTests(final TestResult result) throws Exception {
h.executeOnServer(new Callable<Object>() {
// this code now inside a request handling thread
public Object call() throws Exception {
doTests(result);
return null;
}
});
}
}
}
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.hudson.test.junit;
import junit.framework.TestCase;
/**
* {@link TestCase} implementation that has already failed.
* Used to represent a problem happened during a test suite construction.
*
* @author Kohsuke Kawaguchi
*/
public class FailedTest extends TestCase {
/**
* The failure. If null, the test will succeed, despite the class name.
*/
private final Exception problem;
public FailedTest(String name, Exception problem) {
super(name);
this.problem = problem;
}
public FailedTest(Class name, Exception problem) {
this(name.getName(),problem);
}
@Override
protected void runTest() throws Throwable {
if (problem!=null)
throw problem;
}
}
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jvnet.hudson.test.junit;
import junit.framework.TestSuite;
import junit.framework.TestResult;
/**
* {@link TestSuite} that requires some set up and tear down for executing nested tests.
*
* <p>
* The failure in the set up or tear down will be reported as a failure.
*
* @author Kohsuke Kawaguchi
*/
public class GroupedTest extends TestSuite {
@Override
public int countTestCases() {
return super.countTestCases()+1;
}
@Override
public void run(TestResult result) {
try {
setUp();
try {
runGroupedTests(result);
} finally {
tearDown();
}
// everything went smoothly. report a successful test to make the ends meet
runTest(new FailedTest(getClass(),null),result);
} catch (Exception e) {
// something went wrong
runTest(new FailedTest(getClass(),e),result);
}
}
/**
* Executes the nested tests.
*/
protected void runGroupedTests(TestResult result) throws Exception {
super.run(result);
}
protected void setUp() throws Exception {
}
protected void tearDown() throws Exception {
}
}
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import hudson.model.Hudson;
import hudson.remoting.Which;
import junit.framework.Test;
import junit.framework.TestCase;
import org.jvnet.hudson.test.JellyTestSuiteBuilder;
/**
* Runs Jelly checks on core.
*
* @author Kohsuke Kawaguchi
*/
public class CoreJellyTest extends TestCase {
public static Test suite() throws Exception {
return JellyTestSuiteBuilder.build(Which.jarFile(Hudson.class));
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册