/*
* Copyright © 2015 Cask Data, 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 co.cask.cdap.internal.app.runtime.artifact;
import co.cask.cdap.api.app.Application;
import co.cask.cdap.api.artifact.ArtifactId;
import co.cask.cdap.api.artifact.ArtifactVersion;
import co.cask.cdap.api.plugin.Plugin;
import co.cask.cdap.api.plugin.PluginClass;
import co.cask.cdap.api.plugin.PluginProperties;
import co.cask.cdap.api.plugin.PluginPropertyField;
import co.cask.cdap.api.plugin.PluginSelector;
import co.cask.cdap.app.program.ManifestFields;
import co.cask.cdap.common.InvalidArtifactException;
import co.cask.cdap.common.conf.ArtifactConfig;
import co.cask.cdap.common.conf.CConfiguration;
import co.cask.cdap.common.conf.Constants;
import co.cask.cdap.common.io.Locations;
import co.cask.cdap.common.lang.ProgramClassLoader;
import co.cask.cdap.common.lang.jar.BundleJarUtil;
import co.cask.cdap.common.utils.DirUtils;
import co.cask.cdap.data2.metadata.store.MetadataStore;
import co.cask.cdap.internal.AppFabricTestHelper;
import co.cask.cdap.internal.app.plugins.test.TestPlugin;
import co.cask.cdap.internal.app.plugins.test.TestPlugin2;
import co.cask.cdap.internal.app.runtime.artifact.app.plugin.PluginTestApp;
import co.cask.cdap.internal.app.runtime.artifact.app.plugin.PluginTestRunnable;
import co.cask.cdap.internal.app.runtime.artifact.plugin.EmptyClass;
import co.cask.cdap.internal.app.runtime.artifact.plugin.Plugin1;
import co.cask.cdap.internal.app.runtime.artifact.plugin.Plugin2;
import co.cask.cdap.internal.app.runtime.plugin.PluginInstantiator;
import co.cask.cdap.internal.app.runtime.plugin.PluginNotExistsException;
import co.cask.cdap.internal.test.AppJarHelper;
import co.cask.cdap.internal.test.PluginJarHelper;
import co.cask.cdap.proto.Id;
import co.cask.cdap.proto.artifact.ArtifactRange;
import co.cask.cdap.proto.id.Ids;
import co.cask.cdap.proto.id.NamespaceId;
import co.cask.cdap.proto.metadata.MetadataRecord;
import co.cask.cdap.proto.metadata.MetadataScope;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import com.google.inject.Injector;
import org.apache.twill.filesystem.LocalLocationFactory;
import org.apache.twill.filesystem.Location;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.concurrent.Callable;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
* Unit-tests for app template plugin support.
*/
public class ArtifactRepositoryTest {
@ClassRule
public static final TemporaryFolder TMP_FOLDER = new TemporaryFolder();
private static final String TEST_EMPTY_CLASS = EmptyClass.class.getName();
private static final Id.Artifact APP_ARTIFACT_ID =
Id.Artifact.from(Id.Namespace.DEFAULT, "PluginTest", "1.0.0");
private static CConfiguration cConf;
private static File tmpDir;
private static File systemArtifactsDir1;
private static File systemArtifactsDir2;
private static ArtifactRepository artifactRepository;
private static ClassLoader appClassLoader;
private static MetadataStore metadataStore;
@BeforeClass
public static void setup() throws Exception {
systemArtifactsDir1 = TMP_FOLDER.newFolder();
systemArtifactsDir2 = TMP_FOLDER.newFolder();
tmpDir = TMP_FOLDER.newFolder();
cConf = CConfiguration.create();
cConf.set(Constants.CFG_LOCAL_DATA_DIR, TMP_FOLDER.newFolder().getAbsolutePath());
cConf.set(Constants.AppFabric.SYSTEM_ARTIFACTS_DIR,
systemArtifactsDir1.getAbsolutePath() + ";" + systemArtifactsDir2.getAbsolutePath());
Injector injector = AppFabricTestHelper.getInjector(cConf);
artifactRepository = injector.getInstance(ArtifactRepository.class);
metadataStore = injector.getInstance(MetadataStore.class);
}
@Before
public void setupData() throws Exception {
artifactRepository.clear(NamespaceId.DEFAULT);
File appArtifactFile = createAppJar(PluginTestApp.class, new File(tmpDir, "PluginTest-1.0.0.jar"),
createManifest(ManifestFields.EXPORT_PACKAGE, PluginTestRunnable.class.getPackage().getName()));
artifactRepository.addArtifact(APP_ARTIFACT_ID, appArtifactFile, null);
appClassLoader = createAppClassLoader(appArtifactFile);
}
@Test
public void testDeletingArtifact() throws Exception {
MetadataRecord record = metadataStore.getMetadata(MetadataScope.SYSTEM, APP_ARTIFACT_ID);
Assert.assertEquals(1, record.getTags().size());
artifactRepository.deleteArtifact(APP_ARTIFACT_ID);
record = metadataStore.getMetadata(MetadataScope.SYSTEM, APP_ARTIFACT_ID);
Assert.assertEquals(0, record.getTags().size());
}
@Test(expected = InvalidArtifactException.class)
public void testMultipleParentVersions() throws InvalidArtifactException {
Id.Artifact child = Id.Artifact.from(Id.Namespace.SYSTEM, "abc", "1.0.0");
ArtifactRepository.validateParentSet(child, ImmutableSet.of(
new ArtifactRange(Id.Namespace.SYSTEM, "r1", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")),
new ArtifactRange(Id.Namespace.SYSTEM, "r1", new ArtifactVersion("3.0.0"), new ArtifactVersion("4.0.0"))));
}
@Test(expected = InvalidArtifactException.class)
public void testSelfExtendingArtifact() throws InvalidArtifactException {
Id.Artifact child = Id.Artifact.from(Id.Namespace.SYSTEM, "abc", "1.0.0");
ArtifactRepository.validateParentSet(child, ImmutableSet.of(
new ArtifactRange(Id.Namespace.SYSTEM, "abc", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0"))));
}
@Test(expected = InvalidArtifactException.class)
public void testMultiplePluginClasses() throws InvalidArtifactException {
ArtifactRepository.validatePluginSet(ImmutableSet.of(
new PluginClass("t1", "n1", "", "co.cask.test1", "cfg", ImmutableMap.<String, PluginPropertyField>of()),
new PluginClass("t1", "n1", "", "co.cask.test2", "cfg", ImmutableMap.<String, PluginPropertyField>of())));
}
@Test
public void testAddSystemArtifacts() throws Exception {
Id.Artifact systemAppArtifactId = Id.Artifact.from(Id.Namespace.SYSTEM, "PluginTest", "1.0.0");
File systemAppJar = createAppJar(PluginTestApp.class, new File(systemArtifactsDir1, "PluginTest-1.0.0.jar"),
createManifest(ManifestFields.EXPORT_PACKAGE, PluginTestRunnable.class.getPackage().getName()));
// write plugins jar
Id.Artifact pluginArtifactId1 = Id.Artifact.from(Id.Namespace.SYSTEM, "APlugin", "1.0.0");
Manifest manifest = createManifest(ManifestFields.EXPORT_PACKAGE, TestPlugin.class.getPackage().getName());
File pluginJar1 = createPluginJar(TestPlugin.class, new File(systemArtifactsDir1, "APlugin-1.0.0.jar"), manifest);
// write plugins config file
Map<String, PluginPropertyField> emptyMap = Collections.emptyMap();
Set<PluginClass> manuallyAddedPlugins1 = ImmutableSet.of(
new PluginClass("typeA", "manual1", "desc", "co.cask.classname", null, emptyMap),
new PluginClass("typeB", "manual2", "desc", "co.cask.otherclassname", null, emptyMap)
);
File pluginConfigFile = new File(systemArtifactsDir1, "APlugin-1.0.0.json");
ArtifactConfig pluginConfig1 = new ArtifactConfig(
ImmutableSet.of(new ArtifactRange(
Id.Namespace.SYSTEM, "PluginTest", new ArtifactVersion("0.9.0"), new ArtifactVersion("2.0.0"))),
// add a dummy plugin to test explicit addition of plugins through the config file
manuallyAddedPlugins1,
ImmutableMap.of("k1", "v1", "k2", "v2")
);
try (BufferedWriter writer = Files.newWriter(pluginConfigFile, Charsets.UTF_8)) {
writer.write(pluginConfig1.toString());
}
// write another plugins jar to a different directory, to test that plugins will get picked up from both directories
Id.Artifact pluginArtifactId2 = Id.Artifact.from(Id.Namespace.SYSTEM, "BPlugin", "1.0.0");
manifest = createManifest(ManifestFields.EXPORT_PACKAGE, TestPlugin.class.getPackage().getName());
File pluginJar2 = createPluginJar(TestPlugin.class, new File(systemArtifactsDir2, "BPlugin-1.0.0.jar"), manifest);
// write plugins config file
Set<PluginClass> manuallyAddedPlugins2 = ImmutableSet.of(
new PluginClass("typeA", "manual1", "desc", "co.notcask.classname", null, emptyMap),
new PluginClass("typeB", "manual2", "desc", "co.notcask.otherclassname", null, emptyMap)
);
pluginConfigFile = new File(systemArtifactsDir2, "BPlugin-1.0.0.json");
ArtifactConfig pluginConfig2 = new ArtifactConfig(
ImmutableSet.of(new ArtifactRange(
Id.Namespace.SYSTEM, "PluginTest", new ArtifactVersion("0.9.0"), new ArtifactVersion("2.0.0"))),
manuallyAddedPlugins2,
ImmutableMap.of("k3", "v3")
);
try (BufferedWriter writer = Files.newWriter(pluginConfigFile, Charsets.UTF_8)) {
writer.write(pluginConfig2.toString());
}
artifactRepository.addSystemArtifacts();
Assert.assertTrue(systemAppJar.delete());
Assert.assertTrue(pluginJar1.delete());
Assert.assertTrue(pluginJar2.delete());
try {
// check app artifact added correctly
ArtifactDetail appArtifactDetail = artifactRepository.getArtifact(systemAppArtifactId);
Map<ArtifactDescriptor, Set<PluginClass>> plugins =
artifactRepository.getPlugins(NamespaceId.DEFAULT, systemAppArtifactId);
Assert.assertEquals(2, plugins.size());
Set<PluginClass> pluginClasses = plugins.values().iterator().next();
Set<String> pluginNames = Sets.newHashSet();
for (PluginClass pluginClass : pluginClasses) {
pluginNames.add(pluginClass.getName());
}
Assert.assertEquals(Sets.newHashSet("manual1", "manual2", "TestPlugin", "TestPlugin2"), pluginNames);
Assert.assertEquals(systemAppArtifactId.getName(), appArtifactDetail.getDescriptor().getArtifactId().getName());
Assert.assertEquals(systemAppArtifactId.getVersion(),
appArtifactDetail.getDescriptor().getArtifactId().getVersion());
// check plugin artifact added correctly
ArtifactDetail pluginArtifactDetail = artifactRepository.getArtifact(pluginArtifactId1);
Assert.assertEquals(pluginArtifactId1.getName(), pluginArtifactDetail.getDescriptor().getArtifactId().getName());
Assert.assertEquals(pluginArtifactId1.getVersion(),
pluginArtifactDetail.getDescriptor().getArtifactId().getVersion());
// check manually added plugins are there
Assert.assertTrue(pluginArtifactDetail.getMeta().getClasses().getPlugins().containsAll(manuallyAddedPlugins1));
// check properties are there
Assert.assertEquals(pluginConfig1.getProperties(), pluginArtifactDetail.getMeta().getProperties());
// check other plugin artifact added correctly
pluginArtifactDetail = artifactRepository.getArtifact(pluginArtifactId2);
Assert.assertEquals(pluginArtifactId2.getName(), pluginArtifactDetail.getDescriptor().getArtifactId().getName());
Assert.assertEquals(pluginArtifactId2.getVersion(),
pluginArtifactDetail.getDescriptor().getArtifactId().getVersion());
// check manually added plugins are there
Assert.assertTrue(pluginArtifactDetail.getMeta().getClasses().getPlugins().containsAll(manuallyAddedPlugins2));
// check properties are there
Assert.assertEquals(pluginConfig2.getProperties(), pluginArtifactDetail.getMeta().getProperties());
} finally {
artifactRepository.clear(NamespaceId.SYSTEM);
}
}
@Test
public void testExportPackage() {
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE,
"co.cask.plugin;use:=\"\\\"test,test2\\\"\";version=\"1.0\",co.cask.plugin2");
Set<String> packages = ManifestFields.getExportPackages(manifest);
Assert.assertEquals(ImmutableSet.of("co.cask.plugin", "co.cask.plugin2"), packages);
}
@Test
public void testPlugin() throws Exception {
File pluginDir = DirUtils.createTempDir(tmpDir);
// Create the plugin jar. There should be two plugins there (TestPlugin and TestPlugin2).
Manifest manifest = createManifest(ManifestFields.EXPORT_PACKAGE, TestPlugin.class.getPackage().getName());
File jarFile = createPluginJar(TestPlugin.class, new File(tmpDir, "myPlugin-1.0.jar"), manifest);
// add the artifact
Set<ArtifactRange> parents = ImmutableSet.of(
new ArtifactRange(APP_ARTIFACT_ID.getNamespace(), APP_ARTIFACT_ID.getName(),
new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
Id.Artifact artifactId = Id.Artifact.from(Id.Namespace.DEFAULT, "myPlugin", "1.0");
artifactRepository.addArtifact(artifactId, jarFile, parents);
// check the parent can see the plugins
SortedMap<ArtifactDescriptor, Set<PluginClass>> plugins =
artifactRepository.getPlugins(NamespaceId.DEFAULT, APP_ARTIFACT_ID);
Assert.assertEquals(1, plugins.size());
Assert.assertEquals(2, plugins.get(plugins.firstKey()).size());
ArtifactDescriptor descriptor = plugins.firstKey();
Files.copy(Locations.newInputSupplier(descriptor.getLocation()),
new File(pluginDir, Artifacts.getFileName(descriptor.getArtifactId())));
// Instantiate the plugins and execute them
try (PluginInstantiator instantiator = new PluginInstantiator(cConf, appClassLoader, pluginDir)) {
for (Map.Entry<ArtifactDescriptor, Set<PluginClass>> entry : plugins.entrySet()) {
for (PluginClass pluginClass : entry.getValue()) {
Plugin pluginInfo = new Plugin(entry.getKey().getArtifactId(), pluginClass,
PluginProperties.builder().add("class.name", TEST_EMPTY_CLASS)
.add("timeout", "10").build());
Callable<String> plugin = instantiator.newInstance(pluginInfo);
Assert.assertEquals(TEST_EMPTY_CLASS, plugin.call());
}
}
}
}
@Test
public void testPluginSelector() throws Exception {
// No plugin yet
try {
artifactRepository.findPlugin(NamespaceId.DEFAULT, APP_ARTIFACT_ID,
"plugin", "TestPlugin2", new PluginSelector());
Assert.fail();
} catch (PluginNotExistsException e) {
// expected
}
File pluginDir = DirUtils.createTempDir(tmpDir);
// Create a plugin jar. It contains two plugins, TestPlugin and TestPlugin2 inside.
Id.Artifact artifact1Id = Id.Artifact.from(Id.Namespace.DEFAULT, "myPlugin", "1.0");
Manifest manifest = createManifest(ManifestFields.EXPORT_PACKAGE, TestPlugin.class.getPackage().getName());
File jarFile = createPluginJar(TestPlugin.class, new File(tmpDir, "myPlugin-1.0.jar"), manifest);
// Build up the plugin repository.
Set<ArtifactRange> parents = ImmutableSet.of(
new ArtifactRange(APP_ARTIFACT_ID.getNamespace(), APP_ARTIFACT_ID.getName(),
new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
artifactRepository.addArtifact(artifact1Id, jarFile, parents);
// Should get the only version.
Map.Entry<ArtifactDescriptor, PluginClass> plugin =
artifactRepository.findPlugin(NamespaceId.DEFAULT, APP_ARTIFACT_ID,
"plugin", "TestPlugin2", new PluginSelector());
Assert.assertNotNull(plugin);
Assert.assertEquals(new ArtifactVersion("1.0"), plugin.getKey().getArtifactId().getVersion());
Assert.assertEquals("TestPlugin2", plugin.getValue().getName());
Files.copy(Locations.newInputSupplier(plugin.getKey().getLocation()),
new File(pluginDir, Artifacts.getFileName(plugin.getKey().getArtifactId())));
// Create another plugin jar with later version and update the repository
Id.Artifact artifact2Id = Id.Artifact.from(Id.Namespace.DEFAULT, "myPlugin", "2.0");
jarFile = createPluginJar(TestPlugin.class, new File(tmpDir, "myPlugin-2.0.jar"), manifest);
artifactRepository.addArtifact(artifact2Id, jarFile, parents);
// Should select the latest version
plugin = artifactRepository.findPlugin(NamespaceId.DEFAULT, APP_ARTIFACT_ID,
"plugin", "TestPlugin2", new PluginSelector());
Assert.assertNotNull(plugin);
Assert.assertEquals(new ArtifactVersion("2.0"), plugin.getKey().getArtifactId().getVersion());
Assert.assertEquals("TestPlugin2", plugin.getValue().getName());
Files.copy(Locations.newInputSupplier(plugin.getKey().getLocation()),
new File(pluginDir, Artifacts.getFileName(plugin.getKey().getArtifactId())));
// Load the Plugin class from the classLoader.
try (PluginInstantiator instantiator = new PluginInstantiator(cConf, appClassLoader, pluginDir)) {
ClassLoader pluginClassLoader = instantiator.getArtifactClassLoader(plugin.getKey().getArtifactId());
Class<?> pluginClass = pluginClassLoader.loadClass(TestPlugin2.class.getName());
// Use a custom plugin selector to select with smallest version
plugin = artifactRepository.findPlugin(NamespaceId.DEFAULT, APP_ARTIFACT_ID,
"plugin", "TestPlugin2", new PluginSelector() {
@Override
public Map.Entry<ArtifactId, PluginClass> select(SortedMap<ArtifactId, PluginClass> plugins) {
return plugins.entrySet().iterator().next();
}
});
Assert.assertNotNull(plugin);
Assert.assertEquals(new ArtifactVersion("1.0"), plugin.getKey().getArtifactId().getVersion());
Assert.assertEquals("TestPlugin2", plugin.getValue().getName());
// Load the Plugin class again from the current plugin selected
// The plugin class should be different (from different ClassLoader)
// The empty class should be the same (from the plugin lib ClassLoader)
pluginClassLoader = instantiator.getArtifactClassLoader(plugin.getKey().getArtifactId());
Assert.assertNotSame(pluginClass, pluginClassLoader.loadClass(TestPlugin2.class.getName()));
// From the pluginClassLoader, loading export classes from the template jar should be allowed
Class<?> cls = pluginClassLoader.loadClass(PluginTestRunnable.class.getName());
// The class should be loaded from the parent artifact's classloader
Assert.assertSame(appClassLoader.loadClass(PluginTestRunnable.class.getName()), cls);
// From the plugin classloader, all cdap api classes is loadable as well.
cls = pluginClassLoader.loadClass(Application.class.getName());
// The Application class should be the same as the one in the system classloader
Assert.assertSame(Application.class, cls);
}
}
@Test(expected = InvalidArtifactException.class)
public void testGrandparentsAreInvalid() throws Exception {
// create child artifact
Id.Artifact childId = Id.Artifact.from(Id.Namespace.DEFAULT, "child", "1.0.0");
Manifest manifest = createManifest(ManifestFields.EXPORT_PACKAGE, Plugin1.class.getPackage().getName());
File jarFile = createPluginJar(Plugin1.class, new File(tmpDir, "child-1.0.0.jar"), manifest);
// add the artifact
Set<ArtifactRange> parents = ImmutableSet.of(new ArtifactRange(
APP_ARTIFACT_ID.getNamespace(), APP_ARTIFACT_ID.getName(),
new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
artifactRepository.addArtifact(childId, jarFile, parents);
// try and create grandchild, should throw exception
Id.Artifact grandchildId = Id.Artifact.from(Id.Namespace.DEFAULT, "grandchild", "1.0.0");
manifest = createManifest(ManifestFields.EXPORT_PACKAGE, Plugin2.class.getPackage().getName());
jarFile = createPluginJar(Plugin2.class, new File(tmpDir, "grandchild-1.0.0.jar"), manifest);
parents = ImmutableSet.of(new ArtifactRange(
childId.getNamespace(), childId.getName(),
new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
artifactRepository.addArtifact(grandchildId, jarFile, parents);
}
@Test
public void testArtifactProperties() throws Exception {
// test adding properties
Map<String, String> properties = ImmutableMap.of("k1", "v1", "k2", "v2");
artifactRepository.writeArtifactProperties(APP_ARTIFACT_ID, properties);
ArtifactDetail detail = artifactRepository.getArtifact(APP_ARTIFACT_ID);
Assert.assertEquals(properties, detail.getMeta().getProperties());
// test properties are overwritten
properties = ImmutableMap.of("k2", "v2-2", "k3", "v3");
artifactRepository.writeArtifactProperties(APP_ARTIFACT_ID, properties);
detail = artifactRepository.getArtifact(APP_ARTIFACT_ID);
Assert.assertEquals(properties, detail.getMeta().getProperties());
// test deleting a property
artifactRepository.deleteArtifactProperty(APP_ARTIFACT_ID, "k2");
detail = artifactRepository.getArtifact(APP_ARTIFACT_ID);
Assert.assertEquals(ImmutableMap.of("k3", "v3"), detail.getMeta().getProperties());
// test deleting a non-existant property is a no-op
artifactRepository.deleteArtifactProperty(APP_ARTIFACT_ID, "k2");
detail = artifactRepository.getArtifact(APP_ARTIFACT_ID);
Assert.assertEquals(ImmutableMap.of("k3", "v3"), detail.getMeta().getProperties());
// test updating one property
artifactRepository.writeArtifactProperty(APP_ARTIFACT_ID, "k3", "v3-2");
detail = artifactRepository.getArtifact(APP_ARTIFACT_ID);
Assert.assertEquals(ImmutableMap.of("k3", "v3-2"), detail.getMeta().getProperties());
// test writing one new property
artifactRepository.writeArtifactProperty(APP_ARTIFACT_ID, "k2", "v2-3");
detail = artifactRepository.getArtifact(APP_ARTIFACT_ID);
Assert.assertEquals(ImmutableMap.of("k2", "v2-3", "k3", "v3-2"), detail.getMeta().getProperties());
// test deleting all properties
artifactRepository.deleteArtifactProperties(APP_ARTIFACT_ID);
detail = artifactRepository.getArtifact(APP_ARTIFACT_ID);
Assert.assertEquals(0, detail.getMeta().getProperties().size());
}
@Test
public void testNamespaceIsolation() throws Exception {
// create system app artifact
Id.Artifact systemAppArtifactId = Id.Artifact.from(Id.Namespace.SYSTEM, "PluginTest", "1.0.0");
File jar = createAppJar(PluginTestApp.class, new File(systemArtifactsDir1, "PluginTest-1.0.0.jar"),
createManifest(ManifestFields.EXPORT_PACKAGE, PluginTestRunnable.class.getPackage().getName()));
artifactRepository.addSystemArtifacts();
Assert.assertTrue(jar.delete());
Set<ArtifactRange> parents = ImmutableSet.of(
new ArtifactRange(systemAppArtifactId.getNamespace(), systemAppArtifactId.getName(),
new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
NamespaceId namespace1 = Ids.namespace("ns1");
NamespaceId namespace2 = Ids.namespace("ns2");
Id.Artifact pluginArtifactId1 = Id.Artifact.from(namespace1.toId(), "myPlugin", "1.0");
Id.Artifact pluginArtifactId2 = Id.Artifact.from(namespace2.toId(), "myPlugin", "1.0");
try {
// create plugin artifact in namespace1 that extends the system artifact
// There should be two plugins there (TestPlugin and TestPlugin2).
Manifest manifest = createManifest(ManifestFields.EXPORT_PACKAGE, TestPlugin.class.getPackage().getName());
File jarFile = createPluginJar(TestPlugin.class, new File(tmpDir, "myPlugin-1.0.jar"), manifest);
artifactRepository.addArtifact(pluginArtifactId1, jarFile, parents);
// create plugin artifact in namespace2 that extends the system artifact
artifactRepository.addArtifact(pluginArtifactId2, jarFile, parents);
// check that only plugins from the artifact in the namespace are returned, and not plugins from both
SortedMap<ArtifactDescriptor, Set<PluginClass>> extensions =
artifactRepository.getPlugins(namespace1, systemAppArtifactId);
Assert.assertEquals(1, extensions.keySet().size());
Assert.assertEquals(2, extensions.values().iterator().next().size());
extensions = artifactRepository.getPlugins(namespace2, systemAppArtifactId);
Assert.assertEquals(1, extensions.keySet().size());
Assert.assertEquals(2, extensions.values().iterator().next().size());
} finally {
artifactRepository.clear(NamespaceId.SYSTEM);
artifactRepository.clear(namespace1);
artifactRepository.clear(namespace2);
}
}
private static ClassLoader createAppClassLoader(File jarFile) throws IOException {
final File unpackDir = DirUtils.createTempDir(TMP_FOLDER.newFolder());
BundleJarUtil.unJar(Files.newInputStreamSupplier(jarFile), unpackDir);
return ProgramClassLoader.create(cConf, unpackDir, ArtifactRepositoryTest.class.getClassLoader());
}
private static File createAppJar(Class<?> cls, File destFile, Manifest manifest) throws IOException {
Location deploymentJar = AppJarHelper.createDeploymentJar(new LocalLocationFactory(TMP_FOLDER.newFolder()),
cls, manifest);
DirUtils.mkdirs(destFile.getParentFile());
Files.copy(Locations.newInputSupplier(deploymentJar), destFile);
return destFile;
}
private static File createPluginJar(Class<?> cls, File destFile, Manifest manifest) throws IOException {
Location deploymentJar = PluginJarHelper.createPluginJar(new LocalLocationFactory(TMP_FOLDER.newFolder()),
manifest, cls);
DirUtils.mkdirs(destFile.getParentFile());
Files.copy(Locations.newInputSupplier(deploymentJar), destFile);
return destFile;
}
private static Manifest createManifest(Object...entries) {
Preconditions.checkArgument(entries.length % 2 == 0);
Attributes attributes = new Attributes();
for (int i = 0; i < entries.length; i += 2) {
attributes.put(entries[i], entries[i + 1]);
}
Manifest manifest = new Manifest();
manifest.getMainAttributes().putAll(attributes);
return manifest;
}
}