diff options
author | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-07-06 12:50:02 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@yahoo-inc.com> | 2016-07-06 12:50:02 +0200 |
commit | e71f72757dd77f7bd6b0412e557274155bdc9e62 (patch) | |
tree | 016e4fc2a204ca5853fd291f172a612ef8ef185c /configserver | |
parent | 67a773d0bb03f03f9184fc5bb338886e77cf38b8 (diff) |
Towards transactional application delete
Diffstat (limited to 'configserver')
14 files changed, 131 insertions, 54 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/RotationsCache.java b/configserver/src/main/java/com/yahoo/vespa/config/server/Rotations.java index b1a2988109d..54d522e0d63 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/RotationsCache.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/Rotations.java @@ -8,6 +8,8 @@ import com.yahoo.config.provision.Rotation; import com.yahoo.path.Path; import com.yahoo.vespa.curator.Curator; +import com.yahoo.vespa.curator.transaction.CuratorOperations; +import com.yahoo.vespa.curator.transaction.CuratorTransaction; import java.util.LinkedHashSet; import java.util.Set; @@ -18,12 +20,13 @@ import java.util.stream.Collectors; * * @author hmusum */ -public class RotationsCache { +// TODO: This should be owned by the correct Tenant object +public class Rotations { private final Path path; private final Curator curator; - public RotationsCache(Curator curator, Path tenantPath) { + public Rotations(Curator curator, Path tenantPath) { this.curator = curator; this.path = tenantPath.append("rotationsCache/"); } @@ -63,7 +66,10 @@ public class RotationsCache { } } - public void deleteRotationFromZooKeeper(ApplicationId applicationId) { - curator.delete(path.append(applicationId.serializedForm())); + /** Returns a transaction which deletes these rotations */ + public CuratorTransaction delete(ApplicationId applicationId) { + return CuratorTransaction.from(CuratorOperations.delete(path.append(applicationId.serializedForm()).getAbsolute()), + curator); } + } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationRepo.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationRepo.java index a9296f26eeb..f2fca3bc3a9 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationRepo.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ApplicationRepo.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.config.server.application; import com.yahoo.config.provision.ApplicationId; import com.yahoo.transaction.Transaction; +import com.yahoo.vespa.curator.transaction.CuratorTransaction; import java.util.List; @@ -19,7 +20,7 @@ public interface ApplicationRepo { * * @return a list of {@link com.yahoo.config.provision.ApplicationId}s that are active. */ - public List<ApplicationId> listApplications(); + List<ApplicationId> listApplications(); /** * Register active application and adds it to the repo. If it already exists it is overwritten. @@ -39,11 +40,11 @@ public interface ApplicationRepo { long getSessionIdForApplication(ApplicationId applicationId); /** - * Deletes an application from the repo if it exists. + * Returns a transaction which deletes this application * * @param applicationId an {@link ApplicationId} to delete. */ - void deleteApplication(ApplicationId applicationId); + Transaction deleteApplication(ApplicationId applicationId); /** * Closes the application repo. Once a repo has been closed, it should not be used again. diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKApplicationRepo.java b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKApplicationRepo.java index 42957984461..753956ef7bf 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKApplicationRepo.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/application/ZKApplicationRepo.java @@ -137,9 +137,9 @@ public class ZKApplicationRepo implements ApplicationRepo, PathChildrenCacheList } @Override - public void deleteApplication(ApplicationId applicationId) { + public CuratorTransaction deleteApplication(ApplicationId applicationId) { Path path = root.append(applicationId.serializedForm()); - curator.delete(path); + return CuratorTransaction.from(CuratorOperations.delete(path.getAbsolute()), curator); } @Override diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployer.java index e96a3de71e3..3cc652cb617 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployer.java @@ -8,7 +8,7 @@ import com.yahoo.config.provision.Provisioner; import com.yahoo.log.LogLevel; import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.config.server.ActivateLock; -import com.yahoo.vespa.config.server.RotationsCache; +import com.yahoo.vespa.config.server.Rotations; import com.yahoo.vespa.config.server.Tenant; import com.yahoo.vespa.config.server.Tenants; import com.yahoo.vespa.config.server.TimeoutBudget; @@ -18,7 +18,6 @@ import com.yahoo.vespa.config.server.session.LocalSession; import com.yahoo.vespa.config.server.session.LocalSessionRepo; import com.yahoo.vespa.config.server.session.SilentDeployLogger; import com.yahoo.vespa.curator.Curator; -import com.yahoo.vespa.curator.transaction.CuratorTransaction; import java.time.Clock; import java.time.Duration; @@ -104,12 +103,15 @@ public class Deployer implements com.yahoo.config.provision.Deployer { if (session == null) return false; NestedTransaction transaction = new NestedTransaction(); - localSessionRepo.removeSession(session.getSessionId()); - session.delete(transaction); + transaction.add(localSessionRepo.removeSessionTransaction(session.getSessionId())); + session.delete(transaction); // TODO: Not tested + + transaction.add(new Rotations(owner.get().getCurator(), owner.get().getPath()).delete(applicationId)); // TODO: Not tested + + transaction.add(applicationRepo.deleteApplication(applicationId)); + transaction.commit(); - RotationsCache rotationsCache = new RotationsCache(owner.get().getCurator(), owner.get().getPath()); - rotationsCache.deleteRotationFromZooKeeper(applicationId); - applicationRepo.deleteApplication(applicationId); + if (hostProvisioner.isPresent()) hostProvisioner.get().removed(applicationId); log.log(LogLevel.INFO, "Deleted " + applicationId); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java index c3046887b0e..e27c6cad545 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java @@ -17,7 +17,7 @@ import com.yahoo.config.provision.Version; import com.yahoo.config.provision.Zone; import com.yahoo.log.LogLevel; import com.yahoo.vespa.config.server.GlobalComponentRegistry; -import com.yahoo.vespa.config.server.RotationsCache; +import com.yahoo.vespa.config.server.Rotations; import com.yahoo.vespa.config.server.ServerCache; import com.yahoo.vespa.config.server.Tenants; import com.yahoo.vespa.config.server.application.Application; @@ -120,7 +120,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> { applicationId, configserverConfig, zone, - new RotationsCache(curator, Tenants.getTenantPath(tenant)).readRotationsFromZooKeeper(applicationId)); + new Rotations(curator, Tenants.getTenantPath(tenant)).readRotationsFromZooKeeper(applicationId)); } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java index 0d6170909a7..970740872b1 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java @@ -22,7 +22,7 @@ import com.yahoo.vespa.config.server.ApplicationSet; import com.yahoo.vespa.config.server.ConfigServerSpec; import com.yahoo.vespa.config.server.GlobalComponentRegistry; import com.yahoo.vespa.config.server.HostValidator; -import com.yahoo.vespa.config.server.RotationsCache; +import com.yahoo.vespa.config.server.Rotations; import com.yahoo.vespa.config.server.application.PermanentApplicationPackage; import com.yahoo.vespa.config.server.deploy.ModelContextImpl; import com.yahoo.vespa.config.server.filedistribution.FileDistributionProvider; @@ -60,8 +60,8 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P private final HostProvisionerProvider hostProvisionerProvider; private final Optional<ApplicationSet> currentActiveApplicationSet; private final ApplicationId applicationId; - private final RotationsCache rotationsCache; - private final Set<Rotation> rotations; + private final Rotations rotations; + private final Set<Rotation> rotationsSet; private final ModelContext.Properties properties; /** Construct from global component registry */ @@ -89,13 +89,13 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P this.currentActiveApplicationSet = currentActiveApplicationSet; this.applicationId = params.getApplicationId(); - this.rotationsCache = new RotationsCache(curator, tenantPath); - this.rotations = getRotations(params.rotations()); + this.rotations = new Rotations(curator, tenantPath); + this.rotationsSet = getRotations(params.rotations()); this.properties = createModelContextProperties( params.getApplicationId(), configserverConfig, zone, - rotations); + rotationsSet); } /** Construct with all dependencies passed separately */ @@ -128,15 +128,15 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P this.currentActiveApplicationSet = currentActiveApplicationSet; this.applicationId = params.getApplicationId(); - this.rotationsCache = new RotationsCache(curator, tenantPath); - this.rotations = getRotations(params.rotations()); + this.rotations = new Rotations(curator, tenantPath); + this.rotationsSet = getRotations(params.rotations()); this.properties = new ModelContextImpl.Properties( params.getApplicationId(), configserverConfig.multitenant(), ConfigServerSpec.fromConfig(configserverConfig), configserverConfig.hostedVespa(), zone, - rotations); + rotationsSet); } @Override @@ -187,7 +187,7 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P private Set<Rotation> getRotations(Set<Rotation> rotations) { if (rotations == null || rotations.isEmpty()) { - rotations = rotationsCache.readRotationsFromZooKeeper(applicationId); + rotations = this.rotations.readRotationsFromZooKeeper(applicationId); } return rotations; } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java index 4b6d5d57798..667fe249925 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/LocalSession.java @@ -128,9 +128,9 @@ public class LocalSession extends Session implements Comparable<LocalSession> { /** Add transactions to delete this session to the given nested transaction */ public void delete(NestedTransaction transaction) { - transaction.add(superModelGenerationCounter.incrementTransaction(), CuratorTransaction.class); transaction.add(zooKeeperClient.deleteTransaction(), FileTransaction.class); - transaction.add(FileTransaction.from(FileOperations.delete(serverDB.getAbsolutePath()))); + transaction.add(FileTransaction.from(FileOperations.delete(serverDB.getAbsolutePath())), SuperModelGenerationCounter.IncrementTransaction.class); + transaction.add(superModelGenerationCounter.incrementTransaction()); } @Override diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java index 3ef6f23b84e..981948c0f27 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java @@ -134,11 +134,9 @@ public class SessionFactoryImpl implements SessionFactory, LocalSessionLoader { IOUtils.copyDirectory(applicationFile, userApplicationDir); ApplicationPackage applicationPackage = createApplication(applicationFile, userApplicationDir, applicationName, sessionId, currentlyActiveSession); applicationPackage.writeMetaData(); - logger.log(LogLevel.SPAM, "Application package is written to disk"); return createSessionFromApplication(applicationPackage, sessionId, sessionZooKeeperClient, timeoutBudget); } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Error creating session: " + e.getMessage(), e); + throw new RuntimeException("Error creating session " + sessionIdPath, e); } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java index 4057d010b15..efaa95a7de3 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java @@ -15,7 +15,7 @@ import com.yahoo.vespa.config.server.ApplicationSet; import com.yahoo.vespa.config.server.ConfigServerSpec; import com.yahoo.vespa.config.server.application.PermanentApplicationPackage; import com.yahoo.vespa.config.server.modelfactory.ModelFactoryRegistry; -import com.yahoo.vespa.config.server.RotationsCache; +import com.yahoo.vespa.config.server.Rotations; import com.yahoo.vespa.config.server.configchange.ConfigChangeActions; import com.yahoo.vespa.config.server.deploy.ModelContextImpl; import com.yahoo.vespa.config.server.deploy.ZooKeeperDeployer; @@ -113,8 +113,8 @@ public class SessionPreparer { final Optional<ApplicationSet> currentActiveApplicationSet; final Path tenantPath; final ApplicationId applicationId; - final RotationsCache rotationsCache; - final Set<Rotation> rotations; + final Rotations rotations; + final Set<Rotation> rotationsSet; final ModelContext.Properties properties; private ApplicationPackage applicationPackage; @@ -132,14 +132,14 @@ public class SessionPreparer { this.tenantPath = tenantPath; this.applicationId = params.getApplicationId(); - this.rotationsCache = new RotationsCache(curator, tenantPath); - this.rotations = getRotations(params.rotations()); + this.rotations = new Rotations(curator, tenantPath); + this.rotationsSet = getRotations(params.rotations()); this.properties = new ModelContextImpl.Properties(params.getApplicationId(), configserverConfig.multitenant(), ConfigServerSpec.fromConfig(configserverConfig), configserverConfig.hostedVespa(), zone, - rotations); + rotationsSet); this.preparedModelsBuilder = new PreparedModelsBuilder(modelFactoryRegistry, permanentApplicationPackage, configserverConfig, @@ -192,7 +192,7 @@ public class SessionPreparer { } void writeRotZK() { - rotationsCache.writeRotationsToZooKeeper(applicationId, rotations); + rotations.writeRotationsToZooKeeper(applicationId, rotationsSet); checkTimeout("write rotations to zookeeper"); } @@ -215,7 +215,7 @@ public class SessionPreparer { private Set<Rotation> getRotations(Set<Rotation> rotations) { if (rotations == null || rotations.isEmpty()) { - rotations = rotationsCache.readRotationsFromZooKeeper(applicationId); + rotations = this.rotations.readRotationsFromZooKeeper(applicationId); } return rotations; } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepo.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepo.java index 2b2c18204f6..0ed6ebce65a 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepo.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepo.java @@ -1,6 +1,8 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config.server.session; +import com.yahoo.transaction.AbstractTransaction; +import com.yahoo.transaction.Transaction; import com.yahoo.vespa.config.server.TimeoutBudget; import com.yahoo.vespa.config.server.http.NotFoundException; @@ -43,6 +45,12 @@ public class SessionRepo<SESSIONTYPE extends Session> { * @return the removed session, or null if none was found */ public synchronized SESSIONTYPE removeSession(long id) { return sessions.remove(id); } + + public SessionRepoTransaction removeSessionTransaction(long id) { + SessionRepoTransaction transaction = new SessionRepoTransaction(); + transaction.addRemoveOperation(id); + return transaction; + } /** * Gets a Session @@ -84,4 +92,58 @@ public class SessionRepo<SESSIONTYPE extends Session> { public synchronized Collection<SESSIONTYPE> listSessions() { return new ArrayList<>(sessions.values()); } + + public class SessionRepoTransaction extends AbstractTransaction<SessionRepoTransaction.Operation> { + + public void addRemoveOperation(long sessionIdToRemove) { + add(new RemoveOperation(sessionIdToRemove)); + } + + @Override + public void prepare() { } + + @Override + public void commit() { + for (Operation operation : operations()) + operation.commit(); + } + + @Override + public void rollbackOrLog() { + for (Operation operation : operations()) + operation.rollback(); + } + + public abstract class Operation implements Transaction.Operation { + + abstract void commit(); + + abstract void rollback(); + + } + + public class RemoveOperation extends Operation { + + private final long sessionIdToRemove; + private SESSIONTYPE removed = null; + + public RemoveOperation(long sessionIdToRemove) { + this.sessionIdToRemove = sessionIdToRemove; + } + + @Override + public void commit() { + removed = removeSession(sessionIdToRemove); + } + + @Override + public void rollback() { + if (removed != null) + addSession(removed); + } + + } + + } + } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationRepoTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationRepoTest.java index eea951e5c9c..148f9ca2d6e 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationRepoTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/ApplicationRepoTest.java @@ -116,11 +116,14 @@ public class ApplicationRepoTest extends TestWithCurator { repo.createPutApplicationTransaction(id1, 1).commit(); repo.createPutApplicationTransaction(id2, 1).commit(); assertThat(repo.listApplications().size(), is(2)); - repo.deleteApplication(id1); + System.out.println("------ Test deleting " + id1); + repo.deleteApplication(id1).commit(); assertThat(repo.listApplications().size(), is(1)); - repo.deleteApplication(id2); + System.out.println("------ Test deleting " + id2); + repo.deleteApplication(id2).commit(); assertThat(repo.listApplications().size(), is(0)); - repo.deleteApplication(id2); + System.out.println("------ Test deleting " + id2); + repo.deleteApplication(id2).commit(); assertThat(repo.listApplications().size(), is(0)); } @@ -148,11 +151,11 @@ public class ApplicationRepoTest extends TestWithCurator { assertThat(lst.get(1).application(), is(id2.application())); assertThat(repo.getSessionIdForApplication(id1), is(6l)); assertThat(repo.getSessionIdForApplication(id2), is(5l)); - repo.deleteApplication(id1); + repo.deleteApplication(id1).commit(); assertThat(repo.listApplications().size(), is(1)); - repo.deleteApplication(id2); + repo.deleteApplication(id2).commit(); assertThat(repo.listApplications().size(), is(0)); - repo.deleteApplication(id2); + repo.deleteApplication(id2).commit(); } } @@ -166,7 +169,8 @@ public class ApplicationRepoTest extends TestWithCurator { assertNull(reloadHandler.lastRemoved); repo.deleteApplication(new ApplicationId.Builder() .tenant("mytenant") - .applicationName("bar").instanceName("quux").build()); + .applicationName("bar").instanceName("quux").build()) + .commit(); long endTime = System.currentTimeMillis() + 60_000; while (System.currentTimeMillis() < endTime && reloadHandler.lastRemoved == null) { Thread.sleep(100); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/application/MemoryApplicationRepo.java b/configserver/src/test/java/com/yahoo/vespa/config/server/application/MemoryApplicationRepo.java index c725775e467..89252657760 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/application/MemoryApplicationRepo.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/application/MemoryApplicationRepo.java @@ -17,6 +17,7 @@ import java.util.Map; * @since 5.1 */ public class MemoryApplicationRepo implements ApplicationRepo { + private final Map<ApplicationId, Long> applications = new LinkedHashMap<>(); private boolean isOpen = true; @@ -43,8 +44,10 @@ public class MemoryApplicationRepo implements ApplicationRepo { } @Override - public void deleteApplication(ApplicationId id) { - applications.remove(id); + public Transaction deleteApplication(ApplicationId id) { + return new DummyTransaction().add((DummyTransaction.RunnableOperation) () -> { + applications.remove(id); + }); } @Override diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java index 6d8f93f4f8f..27df54b2174 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/RemoteSessionRepoTest.java @@ -133,6 +133,7 @@ public class RemoteSessionRepoTest extends TestWithCurator { } private class FailingApplicationRepo implements ApplicationRepo { + @Override public List<ApplicationId> listApplications() { return Collections.singletonList(ApplicationId.defaultId()); @@ -149,8 +150,8 @@ public class RemoteSessionRepoTest extends TestWithCurator { } @Override - public void deleteApplication(ApplicationId applicationId) { - + public Transaction deleteApplication(ApplicationId applicationId) { + return null; } @Override diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java index 308e6aa29d2..ba69281c342 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java @@ -197,7 +197,7 @@ public class SessionPreparerTest extends TestWithCurator { } private Set<Rotation> readRotationsFromZK(ApplicationId applicationId) { - return new RotationsCache(curator, tenantPath).readRotationsFromZooKeeper(applicationId); + return new Rotations(curator, tenantPath).readRotationsFromZooKeeper(applicationId); } @Test @@ -219,7 +219,7 @@ public class SessionPreparerTest extends TestWithCurator { final String rotations = "foo.msbe.global.vespa.yahooapis.com"; final ApplicationId applicationId = applicationId("test"); - new RotationsCache(curator, tenantPath).writeRotationsToZooKeeper(applicationId, Collections.singleton(new Rotation(rotations))); + new Rotations(curator, tenantPath).writeRotationsToZooKeeper(applicationId, Collections.singleton(new Rotation(rotations))); final PrepareParams params = new PrepareParams().applicationId(applicationId); final File app = new File("src/test/resources/deploy/app"); preparer.prepare(getContext(getApplicationPackage(app)), getLogger(), params, Optional.empty(), tenantPath); |