blob: e4b5f8d9b7e86e9a49b94c278a586cbdf4fdc423 [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 org.apache.ace.test.repositoryadmin;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import org.apache.ace.client.repository.ObjectRepository;
import org.apache.ace.client.repository.RepositoryAdmin;
import org.apache.ace.client.repository.RepositoryAdminLoginContext;
import org.apache.ace.client.repository.RepositoryObject;
import org.apache.ace.client.repository.RepositoryObject.WorkingState;
import org.apache.ace.client.repository.helper.ArtifactHelper;
import org.apache.ace.client.repository.helper.ArtifactPreprocessor;
import org.apache.ace.client.repository.helper.PropertyResolver;
import org.apache.ace.client.repository.helper.bundle.BundleHelper;
import org.apache.ace.client.repository.object.Artifact2GroupAssociation;
import org.apache.ace.client.repository.object.ArtifactObject;
import org.apache.ace.client.repository.object.DeploymentArtifact;
import org.apache.ace.client.repository.object.DeploymentVersionObject;
import org.apache.ace.client.repository.object.GatewayObject;
import org.apache.ace.client.repository.object.Group2LicenseAssociation;
import org.apache.ace.client.repository.object.GroupObject;
import org.apache.ace.client.repository.object.License2GatewayAssociation;
import org.apache.ace.client.repository.object.LicenseObject;
import org.apache.ace.client.repository.repository.Artifact2GroupAssociationRepository;
import org.apache.ace.client.repository.repository.ArtifactRepository;
import org.apache.ace.client.repository.repository.DeploymentVersionRepository;
import org.apache.ace.client.repository.repository.GatewayRepository;
import org.apache.ace.client.repository.repository.Group2LicenseAssociationRepository;
import org.apache.ace.client.repository.repository.GroupRepository;
import org.apache.ace.client.repository.repository.License2GatewayAssociationRepository;
import org.apache.ace.client.repository.repository.LicenseRepository;
import org.apache.ace.client.repository.stateful.StatefulGatewayObject;
import org.apache.ace.client.repository.stateful.StatefulGatewayRepository;
import org.apache.ace.client.repository.stateful.StatefulGatewayObject.ProvisioningState;
import org.apache.ace.client.repository.stateful.StatefulGatewayObject.RegistrationState;
import org.apache.ace.client.repository.stateful.StatefulGatewayObject.StoreState;
import org.apache.ace.http.listener.constants.HttpConstants;
import org.apache.ace.log.AuditEvent;
import org.apache.ace.log.LogEvent;
import org.apache.ace.obr.storage.file.constants.OBRFileStoreConstants;
import org.apache.ace.repository.Repository;
import org.apache.ace.repository.impl.constants.RepositoryConstants;
import org.apache.ace.scheduler.constants.SchedulerConstants;
import org.apache.ace.server.log.store.LogStore;
import org.apache.ace.test.constants.TestConstants;
import org.apache.ace.test.utils.TestUtils;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.service.Service;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.osgi.service.useradmin.User;
import org.osgi.util.tracker.ServiceTracker;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;
public class RepositoryAdminTest implements EventHandler {
private volatile BundleContext m_context; /* Injected by dependency manager */
private volatile ConfigurationAdmin m_configAdmin; /* Injected by dependency manager */
private volatile DependencyManager m_depManager; /* injected by dependency manager */
private volatile RepositoryAdmin m_repositoryAdmin; /* Injected by dependency manager */
private volatile ArtifactRepository m_artifactRepository; /* Injected by dependency manager */
private volatile Artifact2GroupAssociationRepository m_artifact2groupRepository; /* Injected by dependency manager */
private volatile GroupRepository m_groupRepository; /* Injected by dependency manager */
private volatile Group2LicenseAssociationRepository m_group2licenseRepository; /* Injected by dependency manager */
private volatile LicenseRepository m_licenseRepository; /* Injected by dependency manager */
private volatile License2GatewayAssociationRepository m_license2gatewayRepository; /* Injected by dependency manager */
private volatile GatewayRepository m_gatewayRepository; /* Injected by dependency manager */
private volatile DeploymentVersionRepository m_deploymentVersionRepository; /* Injected by dependency manager */
private volatile StatefulGatewayRepository m_statefulGatewayRepository; /* Injected by dependency manager */
private volatile LogStore m_auditLogStore; /* Injected by dependency manager */
/*
* TestNG magic
*/
private static Object instance;
public RepositoryAdminTest() {
if (instance == null) {
instance = this;
}
}
@Factory
public Object[] createInstances() {
return new Object[] { instance };
}
@AfterMethod( alwaysRun = true )
public void cleanUp() throws IOException, InvalidSyntaxException, InterruptedException {
// Simply remove all objects in the repository.
clearRepository(m_artifactRepository);
clearRepository(m_artifact2groupRepository);
clearRepository(m_group2licenseRepository);
clearRepository(m_license2gatewayRepository);
clearRepository(m_artifactRepository);
clearRepository(m_groupRepository);
clearRepository(m_licenseRepository);
clearRepository(m_gatewayRepository);
clearRepository(m_deploymentVersionRepository);
m_statefulGatewayRepository.refresh();
try {
m_repositoryAdmin.logout(true);
}
catch (Exception ioe) {
//ioe.printStackTrace(System.out);
}
}
public <T extends RepositoryObject> void clearRepository (ObjectRepository<T> rep) {
for (T entity : rep.get()) {
rep.remove(entity);
}
assert rep.get().size() == 0 : "Something went wrong clearing the repository.";
}
/**
* Add a bundle, group and license, associate all, remove the group, No associations should be left.
* @throws Exception
*/
@Test( groups = { TestUtils.INTEGRATION } )
public void testRemoveBundleGroup() throws Exception {
final ArtifactObject b1 = createBasicBundleObject("thebundle","1", null);
final GroupObject g1 = createBasicGroupObject("thegroup");
final Artifact2GroupAssociation bg = runAndWaitForEvent(new Callable<Artifact2GroupAssociation>() {
public Artifact2GroupAssociation call() throws Exception {
return m_artifact2groupRepository.create("(&(" + BundleHelper.KEY_SYMBOLICNAME + "=thebundle)(|("+BundleHelper.KEY_VERSION+">=1)("+BundleHelper.KEY_VERSION+"=<3))(!("+BundleHelper.KEY_VERSION+"=3)))", "(name=thegroup)");
}
}, false, Artifact2GroupAssociation.TOPIC_ADDED);
final LicenseObject l1 = createBasicLicenseObject("thelicense");
final Group2LicenseAssociation gtl = runAndWaitForEvent(new Callable<Group2LicenseAssociation>() {
public Group2LicenseAssociation call() throws Exception {
return m_group2licenseRepository.create("(name=thegroup)","(name=thelicense)");
}
}, false, Group2LicenseAssociation.TOPIC_ADDED);
assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b1) : "The left side of the BG-association should be b1.";
assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the BG-association should be g1.";
assert (gtl.getLeft().size() == 1) && gtl.getLeft().contains(g1) : "The left side of the GtL-association should be g1.";
assert (gtl.getRight().size() == 1) && gtl.getRight().contains(l1) : "The right side of the GtL-association should be l1.";
assert bg.isSatisfied() : "The bundlegroup association should be satisfied.";
assert gtl.isSatisfied() : "The group2license association should be satisfied.";
assert b1.getGroups().size() == 1 : "Bundle b1 should be associated to one group.";
assert l1.getGroups().size() == 1 : "License l1 should be associated to one group.";
//remove the group
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_groupRepository.remove(g1);
return null;
}
}, false,Artifact2GroupAssociation.TOPIC_CHANGED, Group2LicenseAssociation.TOPIC_CHANGED);
assert !gtl.isSatisfied() : "The bundlegroup association shouldn not be satisfied.";
assert !bg.isSatisfied() : "The group2license assocation should not be satisfied.";
assert b1.getGroups().size() == 0 : "Bundle b1 shouldn't be associated to any group, but is associated to " + b1.getGroups();
assert l1.getGroups().size() == 0 : "License l1 shouldn't be associated to any group.";
cleanUp();
}
@Test( groups = { TestUtils.INTEGRATION } )
public void testAssociationsWithMovingEndpoints () throws Exception {
final ArtifactObject b1 = createBasicBundleObject("thebundle", "1", null);
final GroupObject g1 = createBasicGroupObject("thegroup");
final Artifact2GroupAssociation bg = runAndWaitForEvent(new Callable<Artifact2GroupAssociation>() {
public Artifact2GroupAssociation call() throws Exception {
Map<String, String> properties = new HashMap<String, String>();
properties.put(BundleHelper.KEY_ASSOCIATION_VERSIONSTATEMENT, "[1,3)");
return m_artifact2groupRepository.create(b1, properties, g1, null);
}
}, false, Artifact2GroupAssociation.TOPIC_ADDED);
assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b1) : "The left side of the association should now be b1; we find " + bg.getLeft().size() + " bundles on the left side of the association.";
assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
assert b1.getGroups().get(0) == g1 : "b1 should be assocated with g1";
assert g1.getArtifacts().get(0) == b1 : "g1 should be assocated with b1";
final ArtifactObject b2 = runAndWaitForEvent(new Callable<ArtifactObject>() {
public ArtifactObject call() throws Exception {
return createBasicBundleObject("thebundle", "2", null);
}
}, false, Artifact2GroupAssociation.TOPIC_CHANGED);
assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1) : "The left side of the association should no longer be b1; we find " + bg.getLeft().size() + " bundles.";
assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b2) : "The left side of the association should now be b2.";
assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
assert b1.getGroups().size() == 0 : "b1 should not be associated with any group.";
assert b2.getGroups().get(0) == g1 : "b2 should now be assocation with g1";
assert g1.getArtifacts().get(0) == b2 : "g1 should be assocation with b2";
assert g1.getArtifacts().size() == 1 : "g1 should be associated with one bundle";
ArtifactObject b3 = createBasicBundleObject("thebundle", "3", null);
assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1) : "The left side of the association should no longer be b1.";
assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b2) : "The left side of the association should now be b2.";
assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3) : "The left side of the association should not be b3.";
assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
assert b1.getGroups().size() == 0 : "b1 should not be associated with any group.";
assert b2.getGroups().get(0) == g1 : "b2 should now be assocation with g1";
assert b3.getGroups().size() == 0 : "b3 should not be associated with any group.";
assert g1.getArtifacts().get(0) == b2 : "g1 should be assocation with b2";
assert g1.getArtifacts().size() == 1 : "g1 should be associated with one bundle";
ArtifactObject b15 = createBasicBundleObject("thebundle", "1.5", null);
assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1) : "The left side of the association should no longer be b1.";
assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b15) : "The left side of the association should not be b15.";
assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b2) : "The left side of the association should now be b2.";
assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3) : "The left side of the association should not be b3.";
assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
assert b1.getGroups().size() == 0 : "b1 should not be associated with any group.";
assert b15.getGroups().size() == 0 : "b15 should not be associated with any group.";
assert b2.getGroups().get(0) == g1 : "b2 should now be assocation with g1";
assert b3.getGroups().size() == 0 : "b3 should not be associated with any group.";
assert g1.getArtifacts().get(0) == b2 : "g1 should be assocation with b2";
assert g1.getArtifacts().size() == 1 : "g1 should be associated with one bundle";
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_artifactRepository.remove(b2);
return null;
}
}, false, Artifact2GroupAssociation.TOPIC_CHANGED);
//note that we cannot test anything for b2: this has been removed, and now has no
//defined state.
assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b1) : "The left side of the association should no longer be b1.";
assert (bg.getLeft().size() == 1) && bg.getLeft().contains(b15) : "The left side of the association should now be b15.";
assert (bg.getLeft().size() == 1) && !bg.getLeft().contains(b3) : "The left side of the association should not be b3.";
assert (bg.getRight().size() == 1) && bg.getRight().contains(g1) : "The right side of the association should now be g1.";
assert b1.getGroups().size() == 0 : "b1 should not be associated with any group.";
assert b15.getGroups().get(0) == g1 : "b15 should now be assocation with g1";
assert b3.getGroups().size() == 0 : "b3 should not be associated with any group.";
assert g1.getArtifacts().get(0) == b15 : "g1 should be assocation with b15";
assert g1.getArtifacts().size() == 1 : "g1 should be associated with one bundle";
cleanUp();
}
private static final String ENDPOINT = "/AdminRepTest";
private static final String HOST = "http://localhost:" + TestConstants.PORT;
/**
* Tests the behavior with logging in and out (with multiple users), and communication
* with the server.
* @throws Exception
*/
@Test( groups = { TestUtils.INTEGRATION } )
public void testRepositoryAdmin() throws Exception {
final User user1 = new MockUser("user1");
final User user2 = new MockUser("user2");
startRepositoryService();
addRepository("storeInstance", "apache", "store", true);
addRepository("gatewayInstance", "apache", "gateway", true);
try {
m_repositoryAdmin.checkout();
assert false : "Without being logged in, it should not be possible to do checkout.";
}
catch (IllegalStateException ise) {
//expected
}
final RepositoryAdminLoginContext loginContext1 = m_repositoryAdmin.createLoginContext(user1);
loginContext1.addShopRepository(new URL(HOST + ENDPOINT), "apache", "store", true);
loginContext1.addGatewayRepository(new URL(HOST + ENDPOINT), "apache", "gateway", true);
m_repositoryAdmin.login(loginContext1);
assert !m_repositoryAdmin.isCurrent() : "When first logging in without checking out, the repository cannot be current.";
assert !m_repositoryAdmin.isModified() : "Immediately after login, the repository not is modified.";
try {
m_repositoryAdmin.commit();
assert false : "We should not be able to commit before we check something out.";
}
catch (IllegalStateException e) {
// expected
}
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.checkout();
return null;
}
}, false, RepositoryAdmin.TOPIC_REFRESH);
assert m_repositoryAdmin.isCurrent() : "After initial checkout, the repository is current.";
assert !m_repositoryAdmin.isModified() : "Immediately after login, the repository cannot be modified.";
ArtifactObject b1 = runAndWaitForEvent(new Callable<ArtifactObject>() {
public ArtifactObject call() throws Exception {
return createBasicBundleObject("bundle1");
}
}, false, ArtifactObject.TOPIC_ADDED, RepositoryAdmin.TOPIC_STATUSCHANGED);
assert m_repositoryAdmin.isCurrent() : "After initial checkout, the repository is current.";
assert m_repositoryAdmin.isModified() : "We have added a bundle, so the repository is modified.";
assert m_artifactRepository.get().size() == 1;
assert m_repositoryAdmin.getWorkingState(b1).equals(WorkingState.New) : "We expect the working state of our bundle to be New, but it is " + m_repositoryAdmin.getWorkingState(b1);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New) == 1 : "We expect one bundle object in working state New, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed) == 0 : "We expect 0 bundle object in working state Changed, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged) == 0 : "We expect 0 bundle object in working state New, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.logout(false);
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGOUT);
cleanUp();
assert m_artifactRepository.get().size() == 0;
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.login(loginContext1);
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGIN);
assert m_repositoryAdmin.isCurrent() : "There has not been another commit in between, so we are still current.";
assert m_repositoryAdmin.isModified() : "We have made changes since the last commit, so the repository must be modified.";
assert m_artifactRepository.get().size() == 1;
assert m_repositoryAdmin.getWorkingState(b1).equals(WorkingState.New) : "We expect the working state of our bundle to be New, but it is " + m_repositoryAdmin.getWorkingState(b1);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New) == 1 : "We expect one bundle object in working state New, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed) == 0 : "We expect 0 bundle object in working state Changed, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged) == 0 : "We expect 0 bundle object in working state New, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
m_repositoryAdmin.commit();
assert m_repositoryAdmin.isCurrent() : "After a commit, the repository must be current.";
assert !m_repositoryAdmin.isModified() : "After a commit, the repository cannot be modified.";
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.logout(false);
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGOUT);
cleanUp();
final RepositoryAdminLoginContext loginContext2 = m_repositoryAdmin.createLoginContext(user2);
loginContext2.addShopRepository(new URL(HOST + ENDPOINT), "apache", "store", true);
loginContext2.addGatewayRepository(new URL(HOST + ENDPOINT), "apache", "gateway", true);
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.login(loginContext2);
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGIN);
assert m_artifactRepository.get().size() == 0;
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.checkout();
return null;
}
}, false, RepositoryAdmin.TOPIC_REFRESH);
assert m_artifactRepository.get().size() == 1 : "We expect to find 1 bundle after checkout, but we find " + m_artifactRepository.get().size();
assert m_repositoryAdmin.isCurrent() : "After a checkout, without changing anything, the repository must be current.";
assert !m_repositoryAdmin.isModified() : "After a checkout, without changing anything, the repository cannot be modified.";
ArtifactObject b2 = runAndWaitForEvent(new Callable<ArtifactObject>() {
public ArtifactObject call() throws Exception {
return createBasicBundleObject("bundle2");
}
}, false, ArtifactObject.TOPIC_ADDED, RepositoryAdmin.TOPIC_STATUSCHANGED);
assert m_artifactRepository.get().size() == 2;
assert m_repositoryAdmin.isCurrent() : "After changing something in memory without flushing it, the repository still is current.";
assert m_repositoryAdmin.isModified() : "We have added something, so the repository is modified.";
assert m_repositoryAdmin.getWorkingState(b1).equals(WorkingState.Unchanged) : "We expect the working state of our bundle1 to be Unchanged, but it is " + m_repositoryAdmin.getWorkingState(b1);
assert m_repositoryAdmin.getWorkingState(b2).equals(WorkingState.New) : "We expect the working state of our bundle2 to be New, but it is " + m_repositoryAdmin.getWorkingState(b1);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New) == 1 : "We expect one bundle object in working state New, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.New);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed) == 0 : "We expect 0 bundle object in working state Changed, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
assert m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Unchanged) == 1 : "We expect 1 bundle object in working state New, but we find "+ m_repositoryAdmin.getNumberWithWorkingState(ArtifactObject.class, WorkingState.Changed);
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.logout(false);
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGOUT);
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.login(loginContext1);
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGIN);
assert m_artifactRepository.get().size() == 1 : "We expect 1 item in the bundle repository, in stead of " + m_artifactRepository.get().size();
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.logout(false);
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGOUT);
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.login(loginContext2);
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGIN);
assert m_artifactRepository.get().size() == 2 : "We expect 2 items in the bundle repository, in stead of " + m_artifactRepository.get().size();
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_repositoryAdmin.revert();
return null;
}
}, false, RepositoryAdmin.TOPIC_REFRESH, RepositoryAdmin.TOPIC_STATUSCHANGED);
assert m_artifactRepository.get().size() == 1 : "We expect 1 item in the bundle repository, in stead of " + m_artifactRepository.get().size();
try {
removeAllRepositories();
}
catch (Exception e) {
// Not much we can do...
e.printStackTrace(System.err);
}
cleanUp();
}
@Test( groups = { TestUtils.INTEGRATION } )
public void testAutoApprove() throws Exception {
User user = new MockUser("user");
startRepositoryService();
addRepository("storeInstance", "apache", "store", true);
addRepository("gatewayInstance", "apache", "gateway", true);
addRepository("deploymentInstance", "apache", "deployment", true);
RepositoryAdminLoginContext loginContext = m_repositoryAdmin.createLoginContext(user);
loginContext.addShopRepository(new URL(HOST + ENDPOINT), "apache", "store", true);
loginContext.addGatewayRepository(new URL(HOST + ENDPOINT), "apache", "gateway", true);
loginContext.addDeploymentRepository(new URL(HOST + ENDPOINT), "apache", "deployment", true);
m_repositoryAdmin.login(loginContext);
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
createBasicGatewayObject("testAutoApproveGateway");
return null;
}
}, false, GatewayObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_ADDED);
final StatefulGatewayObject sgo = m_statefulGatewayRepository.get(m_context.createFilter("(" + GatewayObject.KEY_ID + "=" + "testAutoApproveGateway)")).get(0);
// Set up some deployment information for the gateway.
final GroupObject g = runAndWaitForEvent(new Callable<GroupObject>() {
public GroupObject call() throws Exception {
ArtifactObject b = createBasicBundleObject("myBundle", "1.0", null);
GroupObject g = createBasicGroupObject("myGroup");
LicenseObject l = createBasicLicenseObject("myLicense");
m_artifact2groupRepository.create(b, g);
m_group2licenseRepository.create(g, l);
m_license2gatewayRepository.create(l, sgo.getGatewayObject());
return g;
}
}, false, ArtifactObject.TOPIC_ADDED, GroupObject.TOPIC_ADDED, LicenseObject.TOPIC_ADDED,
Artifact2GroupAssociation.TOPIC_ADDED, Group2LicenseAssociation.TOPIC_ADDED,
License2GatewayAssociation.TOPIC_ADDED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
assert sgo.needsApprove() : "We added some deployment information, so the gateway should need approval.";
sgo.setAutoApprove(true);
assert sgo.needsApprove() : "Turning on the autoapprove should not automatically approve whatever was waiting.";
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
sgo.approve();
return null;
}
}, false, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
assert !sgo.needsApprove() : "We approved the new version by hand, so we should not need approval.";
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
ArtifactObject b = createBasicBundleObject("myBundle2", "1.0", null);
m_artifact2groupRepository.create(b, g);
return null;
}
}, false, ArtifactObject.TOPIC_ADDED, Artifact2GroupAssociation.TOPIC_ADDED, StatefulGatewayObject.TOPIC_STATUS_CHANGED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
assert !sgo.needsApprove() : "With autoapprove on, adding new deployment information should still not need approval (at least, after the two CHANGED events).";
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_statefulGatewayRepository.unregister(sgo.getID());
return null;
}
}, false, StatefulGatewayObject.TOPIC_STATUS_CHANGED, StatefulGatewayObject.TOPIC_REMOVED);
try {
removeAllRepositories();
}
catch (Exception e) {
// Not much we can do...
e.printStackTrace(System.err);
}
cleanUp();
}
@Test( groups = { TestUtils.INTEGRATION } )
public void testStateful() throws Exception {
User user = new MockUser("user");
startRepositoryService();
addRepository("storeInstance", "apache", "store", true);
addRepository("gatewayInstance", "apache", "gateway", true);
addRepository("deploymentInstance", "apache", "deployment", true);
RepositoryAdminLoginContext loginContext = m_repositoryAdmin.createLoginContext(user);
loginContext.addShopRepository(new URL(HOST + ENDPOINT), "apache", "store", true);
loginContext.addGatewayRepository(new URL(HOST + ENDPOINT), "apache", "gateway", true);
loginContext.addDeploymentRepository(new URL(HOST + ENDPOINT), "apache", "deployment", true);
m_repositoryAdmin.login(loginContext);
/*
* First, test some functionality without auditlog data.
* I would prefer to test without an auditlog present at all, but that
* is not so easily done.
*/
testStatefulCreateRemove();
testStatefulSetAutoApprove();
testStatefulApprove();
testStatefulAuditlog();
testStatefulAuditAndRegister();
testStrangeNamesInGateways();
try {
removeAllRepositories();
}
catch (Exception e) {
// Not much we can do...
e.printStackTrace(System.err);
}
cleanUp();
}
private void testStatefulSetAutoApprove() throws Exception {
// register gateway with
final Map<String, String> attr = new HashMap<String, String>();
attr.put(GatewayObject.KEY_ID, "a_gateway");
attr.put(GatewayObject.KEY_AUTO_APPROVE, String.valueOf(true));
final Map<String, String> tags = new HashMap<String, String>();
final StatefulGatewayObject sgo = runAndWaitForEvent(new Callable<StatefulGatewayObject>() {
public StatefulGatewayObject call() throws Exception {
return m_statefulGatewayRepository.preregister(attr, tags);
}
}, false, GatewayObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_ADDED);
assert m_gatewayRepository.get().size() == 1 : "We expect to find exactly one gateway in the repository, but we find " + m_gatewayRepository.get().size();
assert m_statefulGatewayRepository.get().size() == 1 : "We expect to find exactly one stateful gateway in the repository, but we find " + m_statefulGatewayRepository.get().size();
assert sgo.getAutoApprove() : "The gateway should have auto approved value: true but got: false.";
sgo.setAutoApprove(false);
assert !sgo.getAutoApprove() : "The gateway should have auto approved value: false but got: true.";
//clean up
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_statefulGatewayRepository.unregister(sgo.getID());
return null;
}
}, false, GatewayObject.TOPIC_REMOVED, StatefulGatewayObject.TOPIC_REMOVED);
}
private void testStatefulCreateRemove() throws Exception {
final Map<String, String> attr = new HashMap<String, String>();
attr.put(GatewayObject.KEY_ID, "myNewGateway1");
final Map<String, String> tags = new HashMap<String, String>();
try {
m_statefulGatewayRepository.create(attr, tags);
assert false : "Creating a stateful gateway repository should not be allowed.";
}
catch (UnsupportedOperationException uoe) {
// expected
}
final StatefulGatewayObject sgo = runAndWaitForEvent(new Callable<StatefulGatewayObject>() {
public StatefulGatewayObject call() throws Exception {
return m_statefulGatewayRepository.preregister(attr, tags);
}
}, false, GatewayObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_ADDED);
assert m_gatewayRepository.get().size() == 1 : "We expect to find exactly one gateway in the repository, but we find " + m_gatewayRepository.get().size();
assert m_statefulGatewayRepository.get().size() == 1 : "We expect to find exactly one stateful gateway in the repository, but we find " + m_statefulGatewayRepository.get().size();
try {
m_statefulGatewayRepository.remove(sgo);
assert false : "Deleting a stateful gateway repositoy should not be allowed.";
}
catch (UnsupportedOperationException uoe) {
// expected
}
assert m_gatewayRepository.get().size() == 1 : "We expect to find exactly one gateway in the repository, but we find " + m_gatewayRepository.get().size();
assert m_statefulGatewayRepository.get().size() == 1 : "We expect to find exactly one stateful gateway in the repository, but we find " + m_statefulGatewayRepository.get().size();
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_statefulGatewayRepository.unregister(sgo.getID());
return null;
}
}, false, GatewayObject.TOPIC_REMOVED, StatefulGatewayObject.TOPIC_REMOVED);
assert m_gatewayRepository.get().size() == 0 : "We expect to find no gateway in the repository, but we find " + m_gatewayRepository.get().size();
assert m_statefulGatewayRepository.get().size() == 0 : "We expect to find no stateful gateway in the repository, but we find " + m_statefulGatewayRepository.get().size();
}
private void testStatefulApprove() throws Exception {
final Map<String, String> attr = new HashMap<String, String>();
attr.put(GatewayObject.KEY_ID, "myNewGateway2");
final Map<String, String> tags = new HashMap<String, String>();
final StatefulGatewayObject sgo = runAndWaitForEvent(new Callable<StatefulGatewayObject>() {
public StatefulGatewayObject call() throws Exception {
return m_statefulGatewayRepository.preregister(attr, tags);
}
}, false, GatewayObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_ADDED);
assert !sgo.needsApprove() : "Without any deployment versions, and no information in the shop, we should not need to approve.";
assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is " + sgo.getRegistrationState();
assert sgo.getStoreState().equals(StoreState.New) : "We expect the registration state to be New, but it is " + sgo.getStoreState();
assert sgo.getCurrentVersion().equals(StatefulGatewayObject.UNKNOWN_VERSION);
final ArtifactObject b11 = createBasicBundleObject("bundle1", "1", null);
GroupObject g1 = createBasicGroupObject("group1");
GroupObject g2 = createBasicGroupObject("group2"); // note that this group is not associated to a bundle.
createDynamicBundle2GroupAssociation(b11, g1);
final LicenseObject l1 = createBasicLicenseObject("license1");
m_group2licenseRepository.create(g1, l1);
m_group2licenseRepository.create(g2, l1);
runAndWaitForEvent(new Callable<License2GatewayAssociation>() {
public License2GatewayAssociation call() throws Exception {
return m_license2gatewayRepository.create(l1, sgo.getGatewayObject());
}
}, false, License2GatewayAssociation.TOPIC_ADDED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
assert sgo.needsApprove() : "We added information that influences our gateway, so we should need to approve it.";
assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is " + sgo.getRegistrationState();
assert sgo.getStoreState().equals(StoreState.Unapproved) : "We expect the registration state to be Unapproved, but it is " + sgo.getStoreState();
assert sgo.getArtifactsFromShop().length == 1 : "According to the shop, this gateway needs 1 bundle, but it states we need " + sgo.getArtifactsFromShop().length;
assert sgo.getArtifactsFromDeployment().length == 0 : "According to the deployment, this gateway needs 0 bundles, but it states we need " + sgo.getArtifactsFromDeployment().length;
assert sgo.getCurrentVersion().equals(StatefulGatewayObject.UNKNOWN_VERSION);
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
createBasicDeploymentVersionObject("myNewGateway2", "1", b11);
return null;
}
}, false, DeploymentVersionObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
assert !sgo.needsApprove() : "We manually created a deployment version that reflects the shop, so no approval should be necessary.";
assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is " + sgo.getRegistrationState();
assert sgo.getStoreState().equals(StoreState.Approved) : "We expect the registration state to be Approved, but it is " + sgo.getStoreState();
assert sgo.getArtifactsFromShop().length == 1 : "According to the shop, this gateway needs 1 bundle, but it states we need " + sgo.getArtifactsFromShop().length;
assert sgo.getArtifactsFromDeployment().length == 1 : "According to the deployment, this gateway needs 1 bundles, but it states we need " + sgo.getArtifactsFromDeployment().length;
runAndWaitForEvent(new Callable<ArtifactObject>() {
public ArtifactObject call() throws Exception {
return createBasicBundleObject("bundle1", "2", null);
}
}, false, ArtifactObject.TOPIC_ADDED, Artifact2GroupAssociation.TOPIC_CHANGED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
assert sgo.needsApprove() : "We added a new version of a bundle that is used by the gateway, so approval should be necessary.";
assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is " + sgo.getRegistrationState();
assert sgo.getStoreState().equals(StoreState.Unapproved) : "We expect the registration state to be Unapproved, but it is " + sgo.getStoreState();
assert sgo.getArtifactsFromShop().length == 1 : "According to the shop, this gateway needs 1 bundle, but it states we need " + sgo.getArtifactsFromShop().length;
assert sgo.getArtifactsFromShop()[0].getURL().equals("http://bundle1-2") : "The shop should tell use we need bundle URL 'bundle1-2', but it tells us we need " + sgo.getArtifactsFromShop()[0].getURL();
assert sgo.getArtifactsFromDeployment().length == 1 : "According to the deployment, this gateway needs 1 bundles, but it states we need " + sgo.getArtifactsFromDeployment().length;
assert sgo.getArtifactsFromDeployment()[0].getUrl().equals("http://bundle1-1") : "The deployment should tell use we need bundle URL 'bundle1-1', but it tells us we need " + sgo.getArtifactsFromDeployment()[0].getUrl();
assert sgo.getCurrentVersion().equals("1");
final String newVersion = runAndWaitForEvent(new Callable<String>() {
public String call() throws Exception {
return sgo.approve();
}
}, false, DeploymentVersionObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
assert !sgo.needsApprove() : "Immediately after approval, no approval is necessary.";
assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "We expect the registration state to be Registered, but it is " + sgo.getRegistrationState();
assert sgo.getStoreState().equals(StoreState.Approved) : "We expect the registration state to be Approved, but it is " + sgo.getStoreState();
assert sgo.getArtifactsFromShop().length == 1 : "According to the shop, this gateway needs 1 bundle, but it states we need " + sgo.getArtifactsFromShop().length;
assert sgo.getArtifactsFromShop()[0].getURL().equals("http://bundle1-2") : "The shop should tell use we need bundle URL 'bundle1-2', but it tells us we need " + sgo.getArtifactsFromShop()[0].getURL();
assert sgo.getArtifactsFromDeployment().length == 1 : "According to the deployment, this gateway needs 1 bundles, but it states we need " + sgo.getArtifactsFromDeployment().length;
assert sgo.getArtifactsFromShop()[0].getURL().equals("http://bundle1-2") : "Deployment should tell use we need bundle URL 'bundle1-2', but it tells us we need " + sgo.getArtifactsFromShop()[0].getURL();
assert m_deploymentVersionRepository.get().size() == 2 : "We expect two deployment versions, but we find " + m_deploymentVersionRepository.get().size();
assert sgo.getCurrentVersion().equals(newVersion);
// clean up this object ourselves; we cannot rely on cleanUp() in this case.
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_statefulGatewayRepository.unregister(sgo.getID());
return null;
}
}, false, GatewayObject.TOPIC_REMOVED, StatefulGatewayObject.TOPIC_REMOVED);
assert m_statefulGatewayRepository.get().size() == 0;
}
private void testStrangeNamesInGateways() throws InvalidSyntaxException, IOException {
List<LogEvent> events = new ArrayList<LogEvent>();
Properties props = new Properties();
// add a gateway with a weird name.
events.add(new LogEvent(":)", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
//fill auditlog; no install data
m_auditLogStore.put(events);
//see presence of sgo
int sgrSizeBefore = m_statefulGatewayRepository.get().size();
m_statefulGatewayRepository.refresh();
assert m_statefulGatewayRepository.get().size() == sgrSizeBefore + 1 : "After refresh, we expect " + (sgrSizeBefore + 1) + " gateway based on auditlogdata, but we find " + m_statefulGatewayRepository.get().size();
StatefulGatewayObject sgo = findStatefulGateway(":)");
sgo.register();
assert sgo.getRegistrationState().equals(RegistrationState.Registered) : "After registring our gateway, we assume it to be registered.";
assert sgo.getProvisioningState().equals(ProvisioningState.Idle) : "We expect our object's provisioning state to be Idle, but it is " + m_statefulGatewayRepository.get().get(0).getProvisioningState();
}
private void testStatefulAuditlog() throws IOException, InvalidSyntaxException {
List<LogEvent> events = new ArrayList<LogEvent>();
Properties props = new Properties();
events.add(new LogEvent("myGateway", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
//fill auditlog; no install data
m_auditLogStore.put(events);
//see presence of sgo
assert m_statefulGatewayRepository.get().size() == 0 : "Before audit log refresh, we expect nothing in the stateful repository, but we find " + m_statefulGatewayRepository.get().size();
m_statefulGatewayRepository.refresh();
assert m_statefulGatewayRepository.get().size() == 1 : "After refresh, we expect 1 gateway based on auditlogdata, but we find " + m_statefulGatewayRepository.get().size();
StatefulGatewayObject sgo = m_statefulGatewayRepository.get().get(0);
assert sgo.getProvisioningState().equals(ProvisioningState.Idle) : "We expect our object's provisioning state to be Idle, but it is " + m_statefulGatewayRepository.get().get(0).getProvisioningState();
//fill auditlog with complete-data
events = new ArrayList<LogEvent>();
props = new Properties();
props.put(AuditEvent.KEY_NAME, "mypackage");
props.put(AuditEvent.KEY_VERSION, "123");
events.add(new LogEvent("myGateway", 1, 2, 2, AuditEvent.DEPLOYMENTCONTROL_INSTALL, props));
m_auditLogStore.put(events);
m_statefulGatewayRepository.refresh();
assert sgo.getLastInstallVersion().equals("123") : "Our last install version should be 123, but it is " + sgo.getLastInstallVersion();
assert sgo.getProvisioningState().equals(ProvisioningState.InProgress) : "We expect our object's provisioning state to be InProgress, but it is " + sgo.getProvisioningState();
//fill auditlog with install data
events = new ArrayList<LogEvent>();
props = new Properties();
props.put(AuditEvent.KEY_NAME, "mypackage");
props.put(AuditEvent.KEY_VERSION, "123");
props.put(AuditEvent.KEY_SUCCESS, "false");
events.add(new LogEvent("myGateway", 1, 3, 3, AuditEvent.DEPLOYMENTADMIN_COMPLETE, props));
m_auditLogStore.put(events);
m_statefulGatewayRepository.refresh();
assert sgo.getLastInstallVersion().equals("123") : "Our last install version should be 123, but it is " + sgo.getLastInstallVersion();
assert sgo.getProvisioningState().equals(ProvisioningState.Failed) : "We expect our object's provisioning state to be Failed, but it is " + sgo.getProvisioningState();
assert !sgo.getLastInstallSuccess() : "Our last install was not successful, but according to the sgo it was.";
sgo.acknowledgeInstallVersion("123");
assert sgo.getProvisioningState().equals(ProvisioningState.Idle) : "We expect our object's provisioning state to be Idle, but it is " + sgo.getProvisioningState();
//add another install event.
events = new ArrayList<LogEvent>();
props = new Properties();
props.put(AuditEvent.KEY_NAME, "mypackage");
props.put(AuditEvent.KEY_VERSION, "124");
events.add(new LogEvent("myGateway", 1, 4, 4, AuditEvent.DEPLOYMENTCONTROL_INSTALL, props));
m_auditLogStore.put(events);
m_statefulGatewayRepository.refresh();
assert sgo.getLastInstallVersion().equals("124") : "Our last install version should be 124, but it is " + sgo.getLastInstallVersion();
assert sgo.getProvisioningState().equals(ProvisioningState.InProgress) : "We expect our object's provisioning state to be InProgress, but it is " + sgo.getProvisioningState();
//fill auditlog with install data
events = new ArrayList<LogEvent>();
props = new Properties();
props.put(AuditEvent.KEY_NAME, "mypackage");
props.put(AuditEvent.KEY_VERSION, "124");
props.put(AuditEvent.KEY_SUCCESS, "true");
events.add(new LogEvent("myGateway", 1, 5, 5, AuditEvent.DEPLOYMENTADMIN_COMPLETE, props));
m_auditLogStore.put(events);
m_statefulGatewayRepository.refresh();
assert sgo.getLastInstallVersion().equals("124") : "Our last install version should be 124, but it is " + sgo.getLastInstallVersion();
assert sgo.getProvisioningState().equals(ProvisioningState.OK) : "We expect our object's provisioning state to be OK, but it is " + sgo.getProvisioningState();
assert sgo.getLastInstallSuccess() : "Our last install was successful, but according to the sgo it was not.";
sgo.acknowledgeInstallVersion("124");
assert sgo.getProvisioningState().equals(ProvisioningState.Idle) : "We expect our object's provisioning state to be Idle, but it is " + sgo.getProvisioningState();
}
private void testStatefulAuditAndRegister() throws Exception {
//preregister gateway
final Map<String, String> attr = new HashMap<String, String>();
attr.put(GatewayObject.KEY_ID, "myNewGateway3");
final Map<String, String> tags = new HashMap<String, String>();
final StatefulGatewayObject sgo1 = runAndWaitForEvent(new Callable<StatefulGatewayObject>() {
public StatefulGatewayObject call() throws Exception {
return m_statefulGatewayRepository.preregister(attr, tags);
}
}, false, GatewayObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_ADDED);
//do checks
assert sgo1.isRegistered() : "We just preregistered a gateway, so it should be registered.";
//add auditlog data
List<LogEvent> events = new ArrayList<LogEvent>();
Properties props = new Properties();
events.add(new LogEvent("myNewGateway3", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
m_auditLogStore.put(events);
m_statefulGatewayRepository.refresh();
//do checks
assert sgo1.isRegistered() : "Adding auditlog data for a gateway does not influence its isRegistered().";
try {
sgo1.getGatewayObject();
}
catch (IllegalStateException ise) {
assert false : "We should be able to get sgo1's gatewayObject.";
}
//add auditlog data for other gateway
events = new ArrayList<LogEvent>();
props = new Properties();
events.add(new LogEvent("myNewGateway4", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
m_auditLogStore.put(events);
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_statefulGatewayRepository.refresh();
return false;
}
}, false, StatefulGatewayObject.TOPIC_ADDED);
final StatefulGatewayObject sgo2 = findStatefulGateway("myNewGateway4");
//do checks
assert sgo1.isRegistered() : "Adding auditlog data for a gateway does not influence its isRegistered().";
try {
sgo1.getGatewayObject();
}
catch (IllegalStateException ise) {
assert false : "We should be able to get sgo1's gatewayObject.";
}
assert !sgo2.isRegistered() : "sgo2 is only found in the auditlog, so it cannot be in registered.";
try {
sgo2.getGatewayObject();
assert false : "We should not be able to get sgo2's gatewayObject.";
}
catch (IllegalStateException ise) {
// expected
}
//remove original gateway
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
m_statefulGatewayRepository.unregister(sgo1.getID());
return null;
}
}, false, GatewayObject.TOPIC_REMOVED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
//do checks
assert !sgo1.isRegistered() : "sgo1 is now only found in the auditlog, so it cannot be registered.";
try {
sgo1.getGatewayObject();
assert false : "We should not be able to get sgo1's gatewayObject.";
}
catch (IllegalStateException ise) {
//expected
}
assert !sgo2.isRegistered() : "sgo2 is only found in the auditlog, so it cannot be in registered.";
try {
sgo2.getGatewayObject();
assert false : "We should not be able to get sgo2's gatewayObject.";
}
catch (IllegalStateException ise) {
// expected
}
//register second gateway
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
sgo2.register();
return null;
}
}, false, GatewayObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
//do checks
assert !sgo1.isRegistered() : "sgo1 is now only found in the auditlog, so it cannot be in registered.";
try {
sgo1.getGatewayObject();
assert false : "We should not be able to get sgo1's gatewayObject.";
}
catch (IllegalStateException ise) {
//expected
}
assert sgo2.isRegistered() : "sgo2 has been registered.";
try {
sgo2.getGatewayObject();
}
catch (IllegalStateException ise) {
assert false : "We should be able to get sgo2's gatewayObject.";
}
int nrRegistered = m_statefulGatewayRepository.get(m_context.createFilter("(" + StatefulGatewayObject.KEY_REGISTRATION_STATE + "=" + RegistrationState.Registered + ")")).size();
assert nrRegistered == 1 : "We expect to filter out one registered gateway, but we find " + nrRegistered;
// Finally, create a license object
final LicenseObject l1 = createBasicLicenseObject("thelicense");
assert !sgo1.isRegistered() : "We just created a Staful GW object, is should not be registered";
// register sgo1 again and create an association in 1 go
License2GatewayAssociation lgw1 = runAndWaitForEvent(new Callable<License2GatewayAssociation>() {
public License2GatewayAssociation call() throws Exception {
sgo1.register();
return m_license2gatewayRepository.create(l1, sgo1.getGatewayObject());
}
}, false, License2GatewayAssociation.TOPIC_ADDED, GatewayObject.TOPIC_ADDED, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
// checks
nrRegistered = m_statefulGatewayRepository.get(m_context.createFilter("(" + StatefulGatewayObject.KEY_REGISTRATION_STATE + "=" + RegistrationState.Registered + ")")).size();
assert nrRegistered == 2 : "We expect to filter out two registered gateways, but we find " + nrRegistered;
assert sgo1.isRegistered() : "A stateful gw object should be registered";
assert sgo1.isAssociated(l1, LicenseObject.class) : "The stateful gw object should be associated to thelicense.";
assert lgw1.isSatisfied() : "Both ends of license - stateful gw should be satisfied.";
}
private StatefulGatewayObject findStatefulGateway(String gatewayID) throws InvalidSyntaxException {
for (StatefulGatewayObject sgo : m_statefulGatewayRepository.get()) {
if (sgo.getID().equals(gatewayID)) {
return sgo;
}
}
return null;
}
@Test( groups = { TestUtils.INTEGRATION } )
public void testStatefulApprovalWithArtifacts() throws Exception {
// some setup: we need a helper.
ArtifactHelper myHelper = new MockArtifactHelper("mymime");
Properties serviceProps = new Properties();
serviceProps.put(ArtifactHelper.KEY_MIMETYPE, "mymime");
Service myHelperService = m_depManager.createService()
.setInterface(ArtifactHelper.class.getName(), serviceProps)
.setImplementation(myHelper);
m_depManager.add(myHelperService);
// Empty tag map to be reused througout test
final Map<String, String> tags = new HashMap<String, String>();
// First, create a bundle and an artifact, but do not provide a processor for the artifact.
ArtifactObject b1 = createBasicBundleObject("bundle1");
Map<String, String> attr = new HashMap<String, String>();
attr.put(ArtifactObject.KEY_URL, "http://myobject");
attr.put(ArtifactObject.KEY_PROCESSOR_PID, "my.processor.pid");
attr.put(ArtifactHelper.KEY_MIMETYPE, "mymime");
ArtifactObject a1 = m_artifactRepository.create(attr, tags);
GroupObject g = createBasicGroupObject("group");
LicenseObject l = createBasicLicenseObject("license");
attr = new HashMap<String, String>();
attr.put(GatewayObject.KEY_ID, "myGateway");
StatefulGatewayObject sgo = m_statefulGatewayRepository.preregister(attr, tags);
m_artifact2groupRepository.create(b1, g);
m_artifact2groupRepository.create(a1, g);
m_group2licenseRepository.create(g, l);
m_license2gatewayRepository.create(l, sgo.getGatewayObject());
try {
sgo.approve();
assert false : "Without a resource processor for our artifact, approve should go wrong.";
}
catch (IllegalStateException ise) {
// expected
}
// Now, add a processor for the artifact.
attr = new HashMap<String, String>();
attr.put(ArtifactObject.KEY_URL, "http://myprocessor");
attr.put(BundleHelper.KEY_RESOURCE_PROCESSOR_PID, "my.processor.pid");
attr.put(BundleHelper.KEY_SYMBOLICNAME, "my.processor.bundle");
attr.put(ArtifactHelper.KEY_MIMETYPE, BundleHelper.MIMETYPE);
ArtifactObject b2 = m_artifactRepository.create(attr, tags);
sgo.approve();
DeploymentVersionObject dep = m_deploymentVersionRepository.getMostRecentDeploymentVersion(sgo.getID());
DeploymentArtifact[] toDeploy = dep.getDeploymentArtifacts();
assert toDeploy.length == 3 : "We expect to find three artifacts to deploy, but we find: " + toDeploy.length;
DeploymentArtifact bundle1 = toDeploy[0];
assert bundle1.getUrl().equals(b1.getURL()) && (bundle1.getKeys().length == 2) : "The first artifact in the list should be bundle1, but it is '" + toDeploy[0].toString() + "'";
DeploymentArtifact bundle2 = toDeploy[1];
assert bundle2.getUrl().equals(b2.getURL()) && (bundle2.getKeys().length == 3) && bundle2.getDirective(DeploymentArtifact.DIRECTIVE_ISCUSTOMIZER).equals("true"): "The first artifact in the list should be bundle1, but it is '" + toDeploy[0].toString() + "'";
DeploymentArtifact artifact1 = toDeploy[2];
assert artifact1.getUrl().equals(a1.getURL()) && (artifact1.getKeys().length == 2) && artifact1.getDirective(DeploymentArtifact.DIRECTIVE_KEY_PROCESSORID).equals("my.processor.pid"): "The first artifact in the list should be bundle1, but it is '" + toDeploy[0].toString() + "'";
cleanUp();
m_depManager.remove(myHelperService);
}
@Test( groups = { TestUtils.INTEGRATION } )
public void testAutoGatewayOperator() throws Exception {
startRepositoryService();
addRepository("storeInstance", "apache", "store", true);
addRepository("gatewayInstance", "apache", "gateway", true);
addRepository("deploymentInstance", "apache", "deployment", true);
// configure automation bundle; new configuration properties; bundle will start
final Properties props = new Properties();
props.put("registerGatewayFilter", "(id=anotherGate*)");
props.put("approveGatewayFilter", "(id=DO_NOTHING)");
props.put("autoApproveGatewayFilter", "(id=anotherGate*)");
props.put("commitRepositories","true");
props.put("gatewayRepository","gateway");
props.put("deploymentRepository","deployment");
props.put("storeRepository","store");
props.put("customerName","apache");
props.put("hostName",HOST);
props.put("endpoint",ENDPOINT);
final Configuration config = m_configAdmin.getConfiguration("org.apache.ace.client.automation", null);
/*
* First test the basic scenario where we create some auditlog data, this gateway should be auto-registered after max 1 sec.
*/
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
config.update(props);
return null;
}
}, true, RepositoryAdmin.TOPIC_LOGIN);
testAutoGatewayReg();
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
config.delete();
return null;
}
}, false, RepositoryAdmin.TOPIC_LOGOUT);
// Remove all repositories
try {
removeAllRepositories();
}
catch (Exception e) {
// Not much we can do...
}
cleanUp();
}
private void testAutoGatewayReg() throws Exception {
List<LogEvent> events = new ArrayList<LogEvent>();
Properties props = new Properties();
events.add(new LogEvent("anotherGateway", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
//fill auditlog; no install data
m_auditLogStore.put(events);
int initRepoSize = m_statefulGatewayRepository.get().size();
// Get the processauditlog task and run it
ServiceTracker tracker = new ServiceTracker(m_context, m_context.createFilter("(&(" + Constants.OBJECTCLASS + "=" + Runnable.class.getName() + ")(" + SchedulerConstants.SCHEDULER_NAME_KEY + "=" + "org.apache.ace.client.processauditlog" + "))"), null);
tracker.open();
final Runnable processAuditlog = (Runnable) tracker.waitForService(2000);
if (processAuditlog != null) {
// commit should be called
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
processAuditlog.run();
return null;
}
}, false, RepositoryAdmin.TOPIC_REFRESH);
assert m_statefulGatewayRepository.get().size() == initRepoSize + 1 : "After refresh, we expect 1 gateway based on auditlogdata, but we find " + m_statefulGatewayRepository.get().size();
List<StatefulGatewayObject> sgoList = m_statefulGatewayRepository.get(m_context.createFilter("(id=anotherG*)"));
StatefulGatewayObject sgo = sgoList.get(0);
assert sgo != null : "Expected one (anotherGateway) in the list.";
// should be registered and auto approved
assert sgo.isRegistered(): "The automation gw operator should have registered anotherGateway.";
assert sgo.getAutoApprove(): "The automation gw operator should have auto-approved anotherGateway.";
// add a gateway which will not be autoregistered
events.clear();
events.add(new LogEvent("secondGateway", 1, 1, 1, AuditEvent.FRAMEWORK_STARTED, props));
m_auditLogStore.put(events);
// do auto gateway action
processAuditlog.run();
assert m_statefulGatewayRepository.get().size() == initRepoSize + 2 : "After refresh, we expect an additional gateway based on auditlogdata, but we find " + m_statefulGatewayRepository.get().size();
sgoList = m_statefulGatewayRepository.get(m_context.createFilter("(id=second*)"));
sgo = sgoList.get(0);
// second gateway should not be registered
assert !sgo.isRegistered(): "The automation gw operator should not have registered secongGateway.";
assert !sgo.getAutoApprove(): "The automation gw operator should not have auto-approved myGateway.";
}
else
{
assert false : "Could not get a reference to the processAuditLog task.";
}
}
@Test( groups = { TestUtils.INTEGRATION } )
public void testImportArtifactInvalidURL() throws Exception {
try {
m_artifactRepository.importArtifact(null, true);
assert false : "A null URL cannot be imported into an artifact repository.";
}
catch (IllegalArgumentException iae) {
// expected
}
URL invalidfile = new URL("file:/thisfilecannotexist");
try {
m_artifactRepository.importArtifact(invalidfile, true);
assert false : "An illegal URL should result in an error.";
}
catch (IllegalArgumentException iae) {
// expected
}
cleanUp();
}
@Test( groups = { TestUtils.INTEGRATION } )
public void testImportArtifactGeneralBundle() throws Exception {
// Use a valid JAR file, without a Bundle-SymbolicName header.
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1");
attributes.putValue(Constants.BUNDLE_MANIFESTVERSION, "2");
File temp = File.createTempFile("org.apache.ace.test", ".jar");
temp.deleteOnExit();
JarOutputStream jos = new JarOutputStream(new FileOutputStream(temp), manifest);
jos.close();
try {
m_artifactRepository.importArtifact(temp.toURI().toURL(), true);
assert false : "Without a Bundle-SymbolicName header, the BundleHelper cannot recognize this bundle.";
}
catch (IllegalArgumentException re) {
//expected
}
try {
m_artifactRepository.importArtifact(temp.toURI().toURL(), "notTheBundleMime", true);
assert false : "We have given an illegal mimetype, so no recognizer or helper can be found.";
}
catch (IllegalArgumentException re) {
//expected
}
// Use a valid JAR file, with a Bundle-SymbolicName header, but do not supply an OBR.
attributes.putValue(BundleHelper.KEY_SYMBOLICNAME, "org.apache.ace.test");
temp = File.createTempFile("org.apache.ace.test", ".jar");
temp.deleteOnExit();
jos = new JarOutputStream(new FileOutputStream(temp), manifest);
jos.close();
try {
m_artifactRepository.importArtifact(temp.toURI().toURL(), true);
assert false : "No OBR has been started, so the artifact repository should complain that there is no storage available.";
}
catch (IOException ise) {
//expected
}
// Supply the OBR.
addObr("/obr", "store");
m_artifactRepository.setObrBase(new URL("http://localhost:" + TestConstants.PORT + "/obr/"));
m_artifactRepository.importArtifact(temp.toURI().toURL(), true);
assert m_artifactRepository.get().size() == 1;
assert m_artifactRepository.getResourceProcessors().size() == 0;
// Create a JAR file which looks like a resource processor supplying bundle.
attributes.putValue(BundleHelper.KEY_RESOURCE_PROCESSOR_PID, "someProcessor");
temp = File.createTempFile("org.apache.ace.test", ".jar");
temp.deleteOnExit();
jos = new JarOutputStream(new FileOutputStream(temp), manifest);
jos.close();
m_artifactRepository.importArtifact(temp.toURI().toURL(), true);
assert m_artifactRepository.get().size() == 1;
assert m_artifactRepository.getResourceProcessors().size() == 1;
deleteObr("/obr");
}
private class MockUser implements User {
private final String m_name;
public MockUser(String name) {
m_name = name;
}
@SuppressWarnings("unchecked")
public Dictionary getCredentials() {
return null;
}
public boolean hasCredential(String arg0, Object arg1) {
return false;
}
public String getName() {
return m_name;
}
@SuppressWarnings("unchecked")
public Dictionary getProperties() {
return null;
}
public int getType() {
return 0;
}
}
@Test( groups = { TestUtils.INTEGRATION } )
public void testLoginLogoutAndLoginOnceAgainWhileCreatingAnAssociation() throws IOException, InterruptedException, InvalidSyntaxException {
User user1 = new MockUser("user1");
startRepositoryService();
addRepository("storeInstance", "apache", "store", true);
addRepository("gatewayInstance", "apache", "gateway", true);
final RepositoryAdminLoginContext loginContext1 = m_repositoryAdmin.createLoginContext(user1);
loginContext1.addShopRepository(new URL(HOST + ENDPOINT), "apache", "store", true);
loginContext1.addGatewayRepository(new URL(HOST + ENDPOINT), "apache", "gateway", true);
m_repositoryAdmin.login(loginContext1);
GroupObject g1 = createBasicGroupObject("group1");
LicenseObject l1 = createBasicLicenseObject("license1");
m_group2licenseRepository.create(g1, l1);
m_repositoryAdmin.logout(false);
m_repositoryAdmin.login(loginContext1);
try {
removeAllRepositories();
}
catch (IOException ioe) {
// too bad.
}
}
/**
* Tests read only repository access: marking a repository as readonly for a login should
* mean that it does not get committed, but local changes will stay around between logins.
*/
@Test( groups = { TestUtils.INTEGRATION } )
public void testReadOnlyRepositoryAccess() throws Exception {
User user1 = new MockUser("user1");
startRepositoryService();
addRepository("storeInstance", "apache", "store", true);
addRepository("gatewayInstance", "apache", "gateway", true);
final RepositoryAdminLoginContext loginContext1 = m_repositoryAdmin.createLoginContext(user1);
loginContext1.addShopRepository(new URL(HOST + ENDPOINT), "apache", "store", true);
loginContext1.addGatewayRepository(new URL(HOST + ENDPOINT), "apache", "gateway", false);
m_repositoryAdmin.login(loginContext1);
m_repositoryAdmin.checkout();
createBasicGroupObject("group1");
createBasicGatewayObject("gateway1");
m_repositoryAdmin.logout(false);
m_repositoryAdmin.login(loginContext1);
assert m_groupRepository.get().size() == 1 : "We expect our own group object in the repository; we find " + m_groupRepository.get().size();
assert m_gatewayRepository.get().size() == 1 : "We expect our own gateway object in the repository; we find " + m_gatewayRepository.get().size();
m_repositoryAdmin.commit();
m_repositoryAdmin.logout(false);
m_repositoryAdmin.login(loginContext1);
m_repositoryAdmin.checkout();
assert m_groupRepository.get().size() == 1 : "We expect our own group object in the repository; we find " + m_groupRepository.get().size();
assert m_gatewayRepository.get().size() == 0 : "Since the gateway repository will not be committed, we expect no gateway objects in the repository; we find " + m_gatewayRepository.get().size();
cleanUp();
try {
removeAllRepositories();
}
catch (IOException ioe) {
// too bad.
}
}
@SuppressWarnings("unchecked")
@Test( groups = { TestUtils.INTEGRATION } )
public void testRepostoryLoginDoubleRepository() throws Exception {
RepositoryAdminLoginContext context = m_repositoryAdmin.createLoginContext(new MockUser("user"));
context.addRepositories(new URL("http://localhost:" + TestConstants.PORT), "apache", "shop", true, ArtifactRepository.class, Artifact2GroupAssociationRepository.class, GroupRepository.class);
context.addRepositories(new URL("http://localhost:" + TestConstants.PORT), "apache", "deployment", true, GroupRepository.class, Group2LicenseAssociationRepository.class, LicenseRepository.class);
try {
m_repositoryAdmin.login(context);
assert false : "We tried to log in with two repositories that try to access the same repository service; this should not be allowed.";
}
catch (IllegalArgumentException iae) {
// expected
}
}
private static interface newRepository extends ObjectRepository<LicenseObject> {}
@SuppressWarnings("unchecked")
@Test( groups = { TestUtils.INTEGRATION } )
public void testRepostoryLoginRepositoryWithoutImplementation() throws Exception {
RepositoryAdminLoginContext context = m_repositoryAdmin.createLoginContext(new MockUser("user"));
context.addRepositories(new URL("http://localhost:" + TestConstants.PORT), "apache", "shop", true, ArtifactRepository.class, Artifact2GroupAssociationRepository.class, GroupRepository.class);
context.addRepositories(new URL("http://localhost:" + TestConstants.PORT), "apache", "deployment", true, GroupRepository.class, Group2LicenseAssociationRepository.class, newRepository.class);
try {
m_repositoryAdmin.login(context);
assert false : "We tried to log in with a repository for which no implementation is available; this should not be allowed.";
}
catch (IllegalArgumentException iae) {
// expected
}
}
/**
* Tests the template processing mechanism: given a custom processor, do the correct calls go out?
*/
@SuppressWarnings("unchecked")
@Test( groups = { TestUtils.INTEGRATION } )
public void testTemplateProcessingInfrastructure() throws Exception {
// create a preprocessor
MockArtifactPreprocessor preprocessor = new MockArtifactPreprocessor();
// create a helper
MockArtifactHelper helper = new MockArtifactHelper("mymime", preprocessor);
// register preprocessor and helper
Properties serviceProps = new Properties();
serviceProps.put(ArtifactHelper.KEY_MIMETYPE, "mymime");
Service helperService = m_depManager.createService()
.setInterface(ArtifactHelper.class.getName(), serviceProps)
.setImplementation(helper);
m_depManager.add(helperService);
// create some tree from artifacts to a gateway
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
ArtifactObject b1 = createBasicBundleObject("myBundle");
ArtifactObject b2 = createBasicBundleObject("myProcessor", "1.0.0", "myProcessor.pid");
ArtifactObject a1 = createBasicArtifactObject("myArtifact", "mymime", "myProcessor.pid");
GroupObject go = createBasicGroupObject("mygroup");
LicenseObject lo = createBasicLicenseObject("mylicense");
GatewayObject gwo = createBasicGatewayObject("templategateway");
m_artifact2groupRepository.create(b1, go);
// note that we do not associate b2: this is a resource processor, so it will be packed
// implicitly. It should not be available to a preprocessor either.
m_artifact2groupRepository.create(a1, go);
m_group2licenseRepository.create(go, lo);
m_license2gatewayRepository.create(lo, gwo);
return null;
}
}, false, StatefulGatewayObject.TOPIC_ADDED);
StatefulGatewayObject sgo = m_statefulGatewayRepository.get(m_context.createFilter("(" + GatewayObject.KEY_ID + "=templategateway)")).get(0);
// wait until needsApprove is true; depending on timing, this could have happened before or after the TOPIC_ADDED.
int attempts = 0;
while (!sgo.needsApprove() && (attempts < 10)) {
Thread.sleep(10);
}
assert sgo.needsApprove() : "With the new assignments, the SGO should need approval.";
// create a deploymentversion
sgo.approve();
// // the preprocessor now has gotten its properties; inspect these
PropertyResolver gateway = preprocessor.getProps();
assert gateway.get("id").equals("templategateway") : "The property resolver should be able to resolve 'id'.";
assert gateway.get("name").equals("mylicense") : "The property resolver should be able to resolve 'name'.";
assert gateway.get("someunknownproperty") == null : "The property resolver should not be able to resolve 'someunknownproperty'.";
cleanUp(); // we need to do this before the helper goes away
m_depManager.remove(helperService);
}
/**
* Tests the full template mechanism, from importing templatable artifacts, to creating deployment
* versions with it. It uses the configuration (autoconf) helper, which uses a VelocityBased preprocessor.
*/
@SuppressWarnings("unchecked")
@Test( groups = { TestUtils.INTEGRATION } )
public void testTemplateProcessing() throws Exception {
addObr("/obr", "store");
m_artifactRepository.setObrBase(new URL("http://localhost:" + TestConstants.PORT + "/obr/"));
// create some template things
String xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metatype:MetaData xmlns:metatype= \"http://www.osgi.org/xmlns/metatype/v1.0.0\">\n";
String xmlFooter = "\n</metatype:MetaData>";
String noTemplate = "<Attribute content=\"http://someURL\"/>";
String noTemplateProcessed = "<Attribute content=\"http://someURL\"/>";
final File noTemplateFile = createFileWithContents("template", "xml", xmlHeader+noTemplate+xmlFooter);
String simpleTemplate = "<Attribute content=\"http://$context.name\"/>";
String simpleTemplateProcessed = "<Attribute content=\"http://mylicense\"/>";
File simpleTemplateFile = createFileWithContents("template", "xml", xmlHeader+simpleTemplate+xmlFooter);
// create some tree from artifacts to a gateway
GroupObject go = runAndWaitForEvent(new Callable<GroupObject>() {
public GroupObject call() throws Exception {
ArtifactObject b1 = createBasicBundleObject("myBundle");
ArtifactObject b2 = createBasicBundleObject("myProcessor", "1.0.0", "org.osgi.deployment.rp.autoconf");
GroupObject go = createBasicGroupObject("mygroup");
LicenseObject lo = createBasicLicenseObject("mylicense");
GatewayObject gwo = createBasicGatewayObject("templategateway2");
m_artifact2groupRepository.create(b1, go);
// note that we do not associate b2: this is a resource processor, so it will be packed
// implicitly. It should not be available to a preprocessor either.
m_group2licenseRepository.create(go, lo);
m_license2gatewayRepository.create(lo, gwo);
return go;
}
}, false, StatefulGatewayObject.TOPIC_ADDED);
ArtifactObject a1 = m_artifactRepository.importArtifact(noTemplateFile.toURI().toURL(), true);
Artifact2GroupAssociation a2g = m_artifact2groupRepository.create(a1, go);
final StatefulGatewayObject sgo = m_statefulGatewayRepository.get(m_context.createFilter("(" + GatewayObject.KEY_ID + "=templategateway2)")).get(0);
// create a deploymentversion
assert sgo.needsApprove() : "With the new assignments, the SGO should need approval.";
runAndWaitForEvent(new Callable<Object>() {
public Object call() throws Exception {
sgo.approve();
return null;
}
}, false, StatefulGatewayObject.TOPIC_STATUS_CHANGED);
// find the deployment version
DeploymentVersionObject dvo = m_deploymentVersionRepository.getMostRecentDeploymentVersion("templategateway2");
String inFile = tryGetStringFromURL(findXmlUrlInDeploymentObject(dvo), 10, 100);
assert inFile.equals(xmlHeader + noTemplateProcessed + xmlFooter) : "We expected to find\n" + xmlHeader + noTemplateProcessed + xmlFooter + "\n in the processed artifact, but found\n" + inFile;
// try the simple template
m_artifact2groupRepository.remove(a2g);
a1 = m_artifactRepository.importArtifact(simpleTemplateFile.toURI().toURL(), true);
a2g = m_artifact2groupRepository.create(a1, go);
sgo.approve();
// find the deployment version
dvo = m_deploymentVersionRepository.getMostRecentDeploymentVersion("templategateway2");
// sleep for a while, to allow the OBR to process the file.
Thread.sleep(1000);
inFile = tryGetStringFromURL(findXmlUrlInDeploymentObject(dvo), 10, 100);
assert inFile.equals(xmlHeader + simpleTemplateProcessed + xmlFooter) : "We expected to find\n" + xmlHeader + simpleTemplateProcessed + xmlFooter + "\n in the processed artifact, but found\n" + inFile;
deleteObr("/obr");
}
private String tryGetStringFromURL(URL url, int tries, int interval) throws Exception {
while (true) {
try {
String result = getStringFromURL(url);
return result;
}
catch (IOException ioe) {
Thread.sleep(interval);
tries--;
if (tries == 0) {
throw ioe;
}
}
}
}
/**
* Helper method for testTemplateProcessing; finds the URL of the first deploymentartifact
* with 'xml' in its url.
*/
private URL findXmlUrlInDeploymentObject(DeploymentVersionObject dvo) throws MalformedURLException {
DeploymentArtifact[] artifacts = dvo.getDeploymentArtifacts();
for (DeploymentArtifact da : artifacts) {
if (da.getUrl().contains("xml")) {
return new URL(da.getUrl());
}
}
return null;
}
/**
* Creates a temporary file with the given name and extension, and stores the given
* contents in it.
*/
private File createFileWithContents(String name, String extension, String contents) throws IOException {
File file = File.createTempFile(name, extension);
file.deleteOnExit();
Writer w = new OutputStreamWriter(new FileOutputStream(file));
w.write(contents);
w.close();
return file;
}
/**
* Opens a URL, and gets all data from it as a string.
*/
private String getStringFromURL(URL url) throws IOException {
StringBuilder found = new StringBuilder();
Reader reader = new InputStreamReader(url.openStream());
char[] buf = new char[1024];
for (int count = reader.read(buf); count != -1; count = reader.read(buf)) {
found.append(buf, 0, count);
}
reader.close();
return found.toString();
}
private volatile List<String> m_waitingForTopic = Collections.synchronizedList(new ArrayList<String>());
private volatile Semaphore m_semaphore;
private volatile boolean m_runAndWaitDebug = false;
private <T> T runAndWaitForEvent(Callable<T> callable, boolean debug, String... topic) throws Exception {
m_runAndWaitDebug = debug;
T result = null;
m_waitingForTopic.clear();
m_waitingForTopic.addAll(Arrays.asList(topic));
m_semaphore = new Semaphore(0);
result = callable.call();
assert m_semaphore.tryAcquire(15000, TimeUnit.MILLISECONDS) : "We expect the event within a reasonable timeout.";
m_semaphore = null;
return result;
}
public void handleEvent(Event event) {
if (m_runAndWaitDebug) {System.err.println("Received event: " + event.getTopic());}
if (m_waitingForTopic.remove(event.getTopic())) {
if (m_runAndWaitDebug) {System.err.println("Event was expected.");}
if ((m_semaphore != null) && m_waitingForTopic.isEmpty()) {
m_semaphore.release();
m_runAndWaitDebug = false;
}
}
}
private ArtifactObject createBasicBundleObject(String symbolicName) {
return createBasicBundleObject(symbolicName, null, null);
}
private ArtifactObject createBasicBundleObject(String symbolicName, String version, String processorPID) {
Map<String, String> attr = new HashMap<String, String>();
attr.put(BundleHelper.KEY_SYMBOLICNAME, symbolicName);
attr.put(ArtifactObject.KEY_MIMETYPE, BundleHelper.MIMETYPE);
attr.put(ArtifactObject.KEY_URL, "http://" + symbolicName + "-" + ((version == null) ? "null" : version));
Map<String, String> tags = new HashMap<String, String>();
if (version != null) {
attr.put(BundleHelper.KEY_VERSION, version);
}
if (processorPID != null) {
attr.put(BundleHelper.KEY_RESOURCE_PROCESSOR_PID, processorPID);
}
return m_artifactRepository.create(attr, tags);
}
private ArtifactObject createBasicArtifactObject(String name, String mimetype, String processorPID) throws InterruptedException {
Map<String, String> attr = new HashMap<String, String>();
attr.put(ArtifactObject.KEY_ARTIFACT_NAME, name);
attr.put(ArtifactObject.KEY_MIMETYPE, mimetype);
attr.put(ArtifactObject.KEY_URL, "http://" + name);
attr.put(ArtifactObject.KEY_PROCESSOR_PID, processorPID);
Map<String, String> tags = new HashMap<String, String>();
return m_artifactRepository.create(attr, tags);
}
private GroupObject createBasicGroupObject(String name) {
Map<String, String> attr = new HashMap<String, String>();
attr.put(GroupObject.KEY_NAME, name);
Map<String, String> tags = new HashMap<String, String>();
return m_groupRepository.create(attr, tags);
}
private LicenseObject createBasicLicenseObject(String name) {
Map<String, String> attr = new HashMap<String, String>();
attr.put(LicenseObject.KEY_NAME, name);
Map<String, String> tags = new HashMap<String, String>();
return m_licenseRepository.create(attr, tags);
}
private GatewayObject createBasicGatewayObject(String id) {
Map<String, String> attr = new HashMap<String, String>();
attr.put(GatewayObject.KEY_ID, id);
Map<String, String> tags = new HashMap<String, String>();
return m_gatewayRepository.create(attr, tags);
}
private DeploymentVersionObject createBasicDeploymentVersionObject(String gatewayID, String version, ArtifactObject... bundles) {
Map<String, String> attr = new HashMap<String, String>();
attr.put(DeploymentVersionObject.KEY_GATEWAYID, gatewayID);
attr.put(DeploymentVersionObject.KEY_VERSION, version);
Map<String, String> tags = new HashMap<String, String>();
List<DeploymentArtifact> artifacts = new ArrayList<DeploymentArtifact>();
for (ArtifactObject artifact : bundles) {
Map<String, String> directives = new HashMap<String, String>();
directives.put(BundleHelper.KEY_SYMBOLICNAME, artifact.getAttribute(BundleHelper.KEY_SYMBOLICNAME));
directives.put(DeploymentArtifact.DIRECTIVE_KEY_BASEURL, artifact.getURL());
if (artifact.getAttribute(BundleHelper.KEY_VERSION) != null) {
directives.put(BundleHelper.KEY_VERSION, artifact.getAttribute(BundleHelper.KEY_VERSION));
}
artifacts.add(m_deploymentVersionRepository.createDeploymentArtifact(artifact.getURL(), directives));
}
return m_deploymentVersionRepository.create(attr, tags, artifacts.toArray(new DeploymentArtifact[0]));
}
private Artifact2GroupAssociation createDynamicBundle2GroupAssociation(ArtifactObject artifact, GroupObject group) {
Map<String, String> properties = new HashMap<String, String>();
properties.put(BundleHelper.KEY_ASSOCIATION_VERSIONSTATEMENT, "0.0.0");
return m_artifact2groupRepository.create(artifact, properties, group, null);
}
/*
* The following code is borrowed from RepositoryTest.java, and is used to instantiate and
* use repository servlets.
*/
protected void startRepositoryService() throws IOException {
// configure the (replication)repository servlets
setProperty("org.apache.ace.repository.servlet.RepositoryServlet", new Object[][] { { HttpConstants.ENDPOINT, ENDPOINT } });
}
@AfterMethod(alwaysRun = true)
public void tearDown() throws Exception {
// remove all repositories, in case a test case does not reach it's cleanup section due to an exception
removeAllRepositories();
}
/* Configure a new repository instance */
private void addRepository(String instanceName, String customer, String name, boolean isMaster) throws IOException, InterruptedException, InvalidSyntaxException {
// Publish configuration for a repository instance
Properties props = new Properties();
props.put(RepositoryConstants.REPOSITORY_CUSTOMER, customer);
props.put(RepositoryConstants.REPOSITORY_NAME, name);
props.put(RepositoryConstants.REPOSITORY_MASTER, String.valueOf(isMaster));
props.put("factory.instance.pid", instanceName);
Configuration config = m_configAdmin.createFactoryConfiguration("org.apache.ace.server.repository.factory", null);
ServiceTracker tracker = new ServiceTracker(m_context, m_context.createFilter("(factory.instance.pid=" + instanceName + ")"), null);
tracker.open();
config.update(props);
if (tracker.waitForService(5000) == null) {
throw new IOException("Did not get notified about new repository becoming available in time.");
}
tracker.close();
}
private void addObr(String endpoint, String fileLocation) throws IOException, InterruptedException, InvalidSyntaxException {
Properties propsServlet = new Properties();
propsServlet.put(HttpConstants.ENDPOINT, endpoint);
propsServlet.put("OBRInstance", "singleOBRServlet");
Properties propsStore = new Properties();
propsStore.put(OBRFileStoreConstants.FILE_LOCATION_KEY, fileLocation);
propsStore.put("OBRInstance", "singleOBRStore");
Configuration configServlet = m_configAdmin.getConfiguration("org.apache.ace.obr.servlet", null);
Configuration configStore = m_configAdmin.getConfiguration("org.apache.ace.obr.storage.file", null);
configServlet.update(propsServlet);
configStore.update(propsStore);
// Wait for the endpoint to respond.
// TODO below there is a similar url that does put a slash between port and endpoint, why?
URL url = new URL("http://localhost:" + TestConstants.PORT + endpoint + "/repository.xml");
int response = ((HttpURLConnection) url.openConnection()).getResponseCode();
int tries = 0;
while ((response != 200) && (tries < 50)) {
Thread.sleep(100); //If we get interrupted, there will be a good reason for it.
response = ((HttpURLConnection) url.openConnection()).getResponseCode();
tries++;
}
if (tries == 50) {
throw new IOException("The OBR servlet does not seem to be responding well. Last response code: " + response);
}
}
private void deleteObr(String endpoint) throws IOException, InvalidSyntaxException, InterruptedException {
// This is a little ugly: we cannot just delete the configuration, since that will result in a
// sharing violation between this bundle and the servlet bundle. In stead, we make the servlet
// use an invalid endpoint.
Properties propsServlet = new Properties();
propsServlet.put(HttpConstants.ENDPOINT, endpoint + "invalid");
propsServlet.put("OBRInstance", "singleOBRServlet");
Configuration configServlet = m_configAdmin.getConfiguration("org.apache.ace.obr.servlet");
configServlet.update(propsServlet);
URL url = new URL("http://localhost:" + TestConstants.PORT + "/" + endpoint + "/repository.xml");
int response = ((HttpURLConnection) url.openConnection()).getResponseCode();
int tries = 0;
while ((response != 404) && (tries < 50)) {
Thread.sleep(100); //If we get interrupted, there will be a good reason for it.
response = ((HttpURLConnection) url.openConnection()).getResponseCode();
tries++;
}
if (tries == 50) {
throw new IOException("The OBR servlet does not want to go away. Last response code: " + response);
}
}
private void removeAllRepositories() throws IOException, InvalidSyntaxException, InterruptedException {
final Configuration[] configs = m_configAdmin.listConfigurations("(factory.instance.pid=*)");
if ((configs != null) && (configs.length > 0)) {
final Semaphore sem = new Semaphore(0);
ServiceTracker tracker = new ServiceTracker(m_context, m_context.createFilter("(" + Constants.OBJECTCLASS + "=" + Repository.class.getName() + ")"), null) {
@Override
public void removedService(ServiceReference reference, Object service) {
super.removedService(reference, service);
// config.length times two because the service tracker also sees added events for each instance
if (size() == 0) {
sem.release();
}
}
};
tracker.open();
for (int i = 0; i < configs.length; i++) {
configs[i].delete();
}
if (!sem.tryAcquire(1, TimeUnit.SECONDS)) {
throw new IOException("Not all instances were removed in time.");
}
tracker.close();
}
}
/* Configure properties for the specified service PID */
@SuppressWarnings("unchecked")
private void setProperty(String pid, Object[][] props) throws IOException {
Configuration configuration = m_configAdmin.getConfiguration(pid, null);
Dictionary dictionary = configuration.getProperties();
if (dictionary == null) {
dictionary = new Hashtable();
}
for (Object[] pair : props) {
dictionary.put(pair[0], pair[1]);
}
configuration.update(dictionary);
}
}
class MockArtifactHelper implements ArtifactHelper {
private final String m_mimetype;
private final ArtifactPreprocessor m_preprocessor;
MockArtifactHelper(String mimetype) {
this(mimetype, null);
}
MockArtifactHelper(String mimetype, ArtifactPreprocessor preprocessor) {
m_mimetype = mimetype;
m_preprocessor = preprocessor;
}
public boolean canUse(ArtifactObject object) {
return object.getMimetype().equals(m_mimetype);
}
public Map<String, String> checkAttributes(Map<String, String> attributes) {
return attributes;
}
public Comparator<ArtifactObject> getComparator() {
return null;
}
public String[] getDefiningKeys() {
return new String[0];
}
public String[] getMandatoryAttributes() {
return new String[0];
}
public <TYPE extends ArtifactObject> String getAssociationFilter(TYPE obj, Map<String, String> properties) {
return ("(" + ArtifactObject.KEY_URL + "=" + obj.getURL() + ")");
}
public <TYPE extends ArtifactObject> int getCardinality(TYPE obj, Map<String, String> properties) {
return 1;
}
public ArtifactPreprocessor getPreprocessor() {
return m_preprocessor;
}
};
class MockArtifactPreprocessor implements ArtifactPreprocessor {
private PropertyResolver m_props;
public String preprocess(String url, PropertyResolver props, String gatewayID, String version, URL obrBase) throws IOException {
m_props = props;
return url;
}
PropertyResolver getProps() {
return m_props;
}
public boolean needsNewVersion(String url, PropertyResolver props, String gatewayID, String fromVersion) {
return false;
}
}