blob: 6238857f9fc9c0bf81de8fd0d0a039ff5536bacc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 groovy.grape
import org.codehaus.groovy.control.CompilationFailedException
import org.junit.BeforeClass
import org.junit.Test
import static groovy.test.GroovyAssert.assertScript
import static groovy.test.GroovyAssert.shouldFail
final class GrapeIvyTest {
private static Set<String> jarNames(GroovyClassLoader loader) {
loader.URLs.collect { url -> url.path.split('/')[-1] } as Set
}
@BeforeClass
static void setUpClass() {
// make sure files are installed locally
[
[groupId:'log4j', artifactId:'log4j', version:'1.1.3'],
[groupId:'org.apache.poi', artifactId:'poi', version:'3.7'],
[groupId:'com.jidesoft', artifactId:'jide-oss', version:'2.2.12'],
[groupId:'commons-lang', artifactId:'commons-lang', version:'2.6'],
[groupId:'org.neo4j', artifactId:'neo4j-kernel', version:'2.0.0-RC1'],
[groupId:'commons-digester', artifactId:'commons-digester', version:'2.1'],
[groupId:'net.sf.json-lib', artifactId:'json-lib', version:'2.2.3', classifier:'jdk15'],
[groupId:'org.apache.ivy', artifactId:'ivy', version:'2.0.0', conf:['default', 'optional']]
].each { spec ->
Grape.resolve([autoDownload:true, classLoader:new GroovyClassLoader()], spec)
}
}
@Test
void testSingleArtifact() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
Grape.grab(groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)', classLoader:shell.classLoader)
assert shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class').name == 'com.jidesoft.swing.JideSplitButton';
}
@Test
void testModuleWithDependencies() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class')
}
Grape.grab(groupId:'org.apache.poi', artifactId:'poi', version:'3.7', classLoader:shell.classLoader)
assert shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class').name == 'org.apache.poi.POIDocument'
}
@Test
void testMultipleDependencies() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class')
}
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
Grape.grab(classLoader:shell.classLoader,
[groupId:'org.apache.poi', artifactId:'poi', version:'3.7'],
[groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)'])
assert shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class').name == 'org.apache.poi.POIDocument'
assert shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class').name == 'com.jidesoft.swing.JideSplitButton';
}
@Test
void testListDependencies() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
shouldFail(CompilationFailedException) {
shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class')
}
Grape.grab(classLoader:shell.classLoader,
[groupId:'org.apache.poi', artifactId:'poi', version:'3.7'],
[groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)'])
def loadedDependencies = Grape.listDependencies(shell.classLoader)
assert loadedDependencies == [
[group:'org.apache.poi', module:'poi', version:'3.7'],
[group:'com.jidesoft', module:'jide-oss', version:'[2.2.1,2.3)']
]
}
@Test
void testGrabRefless() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
shell.evaluate("new groovy.grape.Grape().grab(groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)')")
assert shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class').name == 'com.jidesoft.swing.JideSplitButton';
}
@Test
void testGrabScriptClass() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
shell.evaluate("new groovy.grape.Grape().grab(groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)', refObject:this)")
assert shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class').name == 'com.jidesoft.swing.JideSplitButton';
}
@Test
void testGrabScriptLoader() {
def shell = new GroovyShell(new GroovyClassLoader())
shell.setVariable('loader', shell.classLoader)
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
shell.evaluate("new groovy.grape.Grape().grab(groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)', classLoader:loader)")
assert shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class').name == 'com.jidesoft.swing.JideSplitButton';
}
@Test
void testGrabReflessMultiple() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class')
}
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
shell.evaluate('''new groovy.grape.Grape().grab([:],
[groupId:'org.apache.poi', artifactId:'poi', version:'3.7'],
[groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)'])''')
assert shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class').name == 'org.apache.poi.POIDocument'
assert shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class').name == 'com.jidesoft.swing.JideSplitButton';
}
@Test
void testGrabScriptClassMultiple() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class')
}
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
shell.evaluate('''new groovy.grape.Grape().grab(refObject: this,
[groupId:'org.apache.poi', artifactId:'poi', version:'3.7'],
[groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)'])''')
assert shell.evaluate("import org.apache.poi.POIDocument; POIDocument.class").name == 'org.apache.poi.POIDocument'
assert shell.evaluate("import com.jidesoft.swing.JideSplitButton; JideSplitButton.class").name == 'com.jidesoft.swing.JideSplitButton';
}
@Test
void testGrabScriptLoaderMultiple() {
def shell = new GroovyShell(new GroovyClassLoader())
shell.setVariable('loader', shell.classLoader)
shouldFail(CompilationFailedException) {
shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class')
}
shouldFail(CompilationFailedException) {
shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class')
}
shell.evaluate('''new groovy.grape.Grape().grab(classLoader:loader,
[groupId:'org.apache.poi', artifactId:'poi', version:'3.7'],
[groupId:'com.jidesoft', artifactId:'jide-oss', version:'[2.2.1,2.3)'])''')
assert shell.evaluate('import org.apache.poi.POIDocument; POIDocument.class').name == 'org.apache.poi.POIDocument'
assert shell.evaluate('import com.jidesoft.swing.JideSplitButton; JideSplitButton.class').name == 'com.jidesoft.swing.JideSplitButton';
}
@Test
void testSerialGrabs() {
GroovyClassLoader loader = new GroovyClassLoader()
Grape.grab(groupId:'log4j', artifactId:'log4j', version:'1.1.3', classLoader:loader)
Grape.grab(groupId:'org.apache.poi', artifactId:'poi', version:'3.7', classLoader:loader)
def jars = jarNames(loader)
// because poi asks for log4j 1.2.13, but we already have 1.1.3 so it won't be loaded
assert jars.contains('log4j-1.1.3.jar')
assert !jars.contains('log4j-1.2.13.jar')
Grape.grab(groupId:'log4j', artifactId:'log4j', version:'1.2.13', classLoader:loader)
jars = jarNames(loader)
// because log4j 1.1.3 was loaded first, 1.2.13 should not get loaded
// even though it was explicitly asked for
assert jars.contains('log4j-1.1.3.jar')
assert !jars.contains('log4j-1.2.13.jar')
}
@Test
void testConf1() {
Set noJars = [
]
Set coreJars = [
'ivy-2.0.0.jar'
]
Set testJars = [
'commons-lang-2.3.jar',
'junit-3.8.2.jar'
]
Set optionalJars = [
'ant-1.6.2.jar',
'ant-nodeps-1.6.2.jar',
'ant-trax-1.6.2.jar',
'commons-codec-1.2.jar',
'commons-httpclient-3.0.jar',
'commons-logging-1.0.4.jar',
'commons-vfs-1.0.jar',
'jsch-0.1.31.jar',
'junit-3.8.1.jar',
'oro-2.0.8.jar'
]
def loader = new GroovyClassLoader()
Grape.grab(groupId:'org.apache.ivy', artifactId:'ivy', version:'2.0.0', classLoader:loader)
def jars = jarNames(loader)
assert jars == coreJars, 'assert that no extraneous jars are present'
assert coreJars - jars == noJars, 'assert that all core jars are present'
assert testJars - jars == testJars, 'assert that no test jars are present'
assert optionalJars - jars == optionalJars, 'assert that no optional jars are present'
loader = new GroovyClassLoader()
Grape.grab(groupId:'org.apache.ivy', artifactId:'ivy', version:'2.0.0', conf:'optional', classLoader:loader)
jars = jarNames(loader)
assert jars == optionalJars, 'assert that no extraneous jars are present'
assert coreJars - jars == coreJars, 'assert that no core jars are present'
assert testJars - jars == testJars, 'assert that no test jars are present'
assert optionalJars - jars == noJars, 'assert that all optional jars are present'
loader = new GroovyClassLoader()
Grape.grab(groupId:'org.apache.ivy', artifactId:'ivy', version:'2.0.0', conf:['default', 'optional'], classLoader:loader)
jars = jarNames(loader)
assert coreJars - jars == noJars, 'assert that all core jars are present'
assert testJars - jars == testJars, 'assert that no test jars are present'
assert optionalJars - jars == noJars, 'assert that all optional jars are present'
assert jars == coreJars + optionalJars, 'assert that no extraneous jars are present'
}
@Test // GROOVY-8372
void testConf2() {
def tempDir = File.createTempDir()
def jarsDir = new File(tempDir, 'foo/bar/jars'); jarsDir.mkdirs()
new File(jarsDir, 'bar-1.2.3.jar').createNewFile()
new File(jarsDir, 'baz-1.2.3.jar').createNewFile()
new File(tempDir, 'ivysettings.xml').write '''\
<?xml version="1.0" encoding="UTF-8"?>
<ivysettings>
<caches useOrigin="true" />
<resolvers>
<filesystem name="downloadGrapes">
<ivy pattern="${ivy.settings.dir}/[organization]/[module]/ivy-[revision].xml" />
<artifact pattern="${ivy.settings.dir}/[organization]/[module]/[type]s/[artifact]-[revision].[ext]" />
</filesystem>
</resolvers>
</ivysettings>
'''.stripIndent()
new File(tempDir, 'foo/bar/ivy-1.2.3.xml').write '''\
<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0" xmlns:m="http://ant.apache.org/ivy/maven">
<info organisation="foo" module="bar" revision="1.2.3" status="release" />
<configurations>
<conf name="default" visibility="public" extends="master" />
<conf name="master" visibility="public" />
<conf name="other" visibility="public" />
</configurations>
<publications>
<artifact name="bar" type="jar" ext="jar" conf="master" />
<artifact name="baz" type="jar" ext="jar" conf="other" />
</publications>
</ivy-module>
'''.stripIndent()
System.setProperty('grape.config', tempDir.absolutePath + File.separator + 'ivysettings.xml')
try {
Grape.@instance = null
def loader = new GroovyClassLoader()
// request conf="other" which should resolve to artifact "baz-1.2.3.jar"
def uris = Grape.resolve(classLoader:loader, validate:false, [group:'foo', module:'bar', version:'1.2.3', conf:'other'])
def jars = uris.collect { uri -> uri.path.split('/')[-1] } as Set
assert 'baz-1.2.3.jar' in jars
assert 'bar-1.2.3.jar' !in jars
} finally {
System.clearProperty('grape.config')
Grape.@instance = null
tempDir.deleteDir()
}
}
@Test
void testClassifier() {
def shell = new GroovyShell(new GroovyClassLoader())
shouldFail(CompilationFailedException) {
shell.evaluate('import net.sf.json.JSON; JSON')
}
Grape.grab(groupId:'net.sf.json-lib', artifactId:'json-lib', version:'2.2.3', classifier:'jdk15', classLoader:shell.classLoader)
assert shell.evaluate('import net.sf.json.JSON; JSON').name == 'net.sf.json.JSON'
}
@Test
void testClassifierWithConf() {
Set coreJars = [
'json-lib-2.2.3-jdk15.jar',
'commons-beanutils-1.7.0.jar',
'commons-collections-3.2.jar',
'commons-lang-2.4.jar',
'commons-logging-1.1.1.jar',
'ezmorph-1.0.6.jar'
]
Set optionalJars = [
'ant-1.7.0.jar',
'ant-launcher-1.7.0.jar',
'dom4j-1.6.1.jar',
'groovy-all-1.5.7.jar',
'jaxen-1.1-beta-8.jar',
'jdom-1.0.jar',
'jline-0.9.94.jar',
'jruby-1.1.jar',
'junit-3.8.2.jar',
'log4j-1.2.14.jar',
'oro-2.0.8.jar',
'xalan-2.7.0.jar',
'xercesImpl-2.6.2.jar',
'xmlParserAPIs-2.6.2.jar',
'xom-1.1.jar'
]
def loader = new GroovyClassLoader()
Grape.grab(groupId:'net.sf.json-lib', artifactId:'json-lib', version:'2.2.3', classifier:'jdk15', classLoader:loader)
assert jarNames(loader) == coreJars
loader = new GroovyClassLoader()
Grape.grab(groupId:'net.sf.json-lib', artifactId:'json-lib', version:'2.2.3', classifier:'jdk15', conf:'optional', classLoader:loader)
assert jarNames(loader) == optionalJars
loader = new GroovyClassLoader()
Grape.grab(groupId:'net.sf.json-lib', artifactId:'json-lib', version:'2.2.3', classifier:'jdk15', conf:['default', 'optional'], classLoader:loader)
assert jarNames(loader) == coreJars + optionalJars
}
@Test // BeanUtils is a transitive dependency for Digester
void testTransitiveShorthandControl() {
assertScript '''
@Grab('commons-digester:commons-digester:2.1')
import org.apache.commons.digester.Digester
assert Digester.name.size() == 36
assert org.apache.commons.beanutils.BeanUtils.name.size() == 38
'''
}
@Test
void testTransitiveShorthandExpectFailure() {
shouldFail MissingPropertyException, '''
@Grab('commons-digester:commons-digester:2.1;transitive=false')
import org.apache.commons.digester.Digester
assert Digester.name.size() == 36
assert org.apache.commons.beanutils.BeanUtils.name.size() == 38
'''
}
@Test
void testAutoDownloadGrapeConfig() {
assertScript '''
@Grab('commons-digester:commons-digester:2.1;transitive=false')
import org.apache.commons.digester.Digester
assert Digester.name.size() == 36
'''
assert Grape.instance.ivyInstance.settings.defaultResolver.name == 'downloadGrapes'
assertScript '''
@Grab('commons-digester:commons-digester:2.1;transitive=false')
@GrabConfig(autoDownload=false)
import org.apache.commons.digester.Digester
assert Digester.name.size() == 36
'''
assert Grape.instance.ivyInstance.settings.defaultResolver.name == 'cachedGrapes'
assertScript '''
@Grab('commons-digester:commons-digester:2.1;transitive=false')
@GrabConfig(autoDownload=true)
import org.apache.commons.digester.Digester
assert Digester.name.size() == 36
'''
assert Grape.instance.ivyInstance.settings.defaultResolver.name == 'downloadGrapes'
}
@Test // GROOVY-470: multiple jars should be loaded for an artifacts with and without a classifier
void testClassifierAndNonClassifierOnSameArtifact() {
GroovyClassLoader loader = new GroovyClassLoader()
Grape.grab(groupId:'org.neo4j', artifactId:'neo4j-kernel', version:'2.0.0-RC1', classLoader:loader)
Grape.grab(groupId:'org.neo4j', artifactId:'neo4j-kernel', version:'2.0.0-RC1', classifier:'tests', classLoader:loader)
def jars = jarNames(loader)
assert jars.contains('neo4j-kernel-2.0.0-RC1.jar')
assert jars.contains('neo4j-kernel-2.0.0-RC1-tests.jar')
// also check reverse ordering of deps
loader = new GroovyClassLoader()
Grape.grab(groupId:'org.neo4j', artifactId:'neo4j-kernel', version:'2.0.0-RC1', classifier:'tests', classLoader:loader)
Grape.grab(groupId:'org.neo4j', artifactId:'neo4j-kernel', version:'2.0.0-RC1', classLoader:loader)
jars = jarNames(loader)
assert jars.contains('neo4j-kernel-2.0.0-RC1.jar')
assert jars.contains('neo4j-kernel-2.0.0-RC1-tests.jar')
}
@Test // GROOVY-7548
void testSystemProperties() {
System.setProperty('groovy7548prop', 'x')
assert System.getProperty('groovy7548prop') == 'x'
try {
assertScript '''
@GrabConfig(systemProperties='groovy7548prop=y')
@Grab('commons-lang:commons-lang:2.6')
import org.apache.commons.lang.StringUtils
assert StringUtils.name == 'org.apache.commons.lang.StringUtils'
'''
assert System.getProperty('groovy7548prop') == 'y'
} finally {
System.clearProperty('groovy7548prop')
}
}
@Test // GROOVY-7649
void testResolveSucceedsAfterFailure() {
GroovyClassLoader loader = new GroovyClassLoader()
shouldFail {
Grape.resolve([classLoader:loader], [], [groupId:'bogus', artifactId:'bogus', version:'0.1'])
}
Grape.resolve([classLoader:loader], [], [groupId:'org.apache.poi', artifactId:'poi', version:'3.7'])
}
@Test // GROOVY-9312
void testResolveSucceedsFromLocalMavenRepository() {
def tempDir = File.createTempDir()
new File(tempDir, 'pom.xml').write '''\
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.codehaus.groovy.tests</groupId>
<artifactId>maven-bootstrap</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>net.jqwik</groupId>
<artifactId>jqwik</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>net.jqwik</groupId>
<artifactId>jqwik-engine</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
</project>
'''.stripIndent()
try {
// prime "${user.home}/.m2/repository" with jqwik
assertScript """
@Grab('org.apache.maven.shared:maven-invoker:3.0.1')
import org.apache.maven.shared.invoker.*
def request = new DefaultInvocationRequest(goals: ['compile'],
baseDirectory: new File('${tempDir.absolutePath.replace('\\', '\\\\')}'))
def result = new DefaultInvoker().execute(request)
assert result.exitCode == 0
"""
assertScript '''
@Grab('net.jqwik:jqwik:1.2.1')
import net.jqwik.api.ForAll
import net.jqwik.api.Property
@groovy.transform.CompileStatic
class Jsr308 {
@Property
boolean 'size zero or positive'(@ForAll List<Integer> items) {
items.size() >= 0
}
}
println 'success'
'''
} finally {
tempDir.deleteDir()
}
}
}