use of co.cask.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ClientUpgradeContext method getPluginArtifact.
@Nullable
@Override
public ArtifactSelectorConfig getPluginArtifact(String pluginType, String pluginName) {
try {
List<PluginInfo> plugins = artifactClient.getPluginInfo(artifactId, pluginType, pluginName, ArtifactScope.SYSTEM);
if (plugins.isEmpty()) {
return null;
}
// doesn't really matter which one we choose, as all of them should be valid.
// choosing the last one because that tends to be the one with the highest version.
// order is not guaranteed though.
ArtifactSummary chosenArtifact = plugins.get(plugins.size() - 1).getArtifact();
return new ArtifactSelectorConfig(chosenArtifact.getScope().name(), chosenArtifact.getName(), chosenArtifact.getVersion());
} catch (Exception e) {
return null;
}
}
use of co.cask.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ArtifactHttpHandlerTest method testPluginNamespaceIsolation.
@Test
public void testPluginNamespaceIsolation() throws Exception {
// add a system artifact. currently can't do this through the rest api (by design)
// so bypass it and use the repository directly
Id.Artifact systemId = Id.Artifact.from(Id.Namespace.SYSTEM, "wordcount", "1.0.0");
File systemArtifact = buildAppArtifact(WordCountApp.class, "wordcount-1.0.0.jar");
artifactRepository.addArtifact(systemId, systemArtifact, Sets.<ArtifactRange>newHashSet());
Set<ArtifactRange> parents = Sets.newHashSet(new ArtifactRange(systemId.getNamespace().getId(), systemId.getName(), systemId.getVersion(), true, systemId.getVersion(), true));
Id.Namespace namespace1 = Id.Namespace.from("ns1");
Id.Namespace namespace2 = Id.Namespace.from("ns2");
createNamespace(namespace1.getId());
createNamespace(namespace2.getId());
try {
// add some plugins in namespace1. Will contain Plugin1 and Plugin2
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, Plugin1.class.getPackage().getName());
Id.Artifact pluginsId1 = Id.Artifact.from(namespace1, "plugins1", "1.0.0");
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addPluginArtifact(pluginsId1, Plugin1.class, manifest, parents).getStatusLine().getStatusCode());
// add some plugins in namespace2. Will contain Plugin1 and Plugin2
manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, Plugin1.class.getPackage().getName());
Id.Artifact pluginsId2 = Id.Artifact.from(namespace2, "plugins2", "1.0.0");
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addPluginArtifact(pluginsId2, Plugin1.class, manifest, parents).getStatusLine().getStatusCode());
ArtifactSummary artifact1 = new ArtifactSummary(pluginsId1.getName(), pluginsId1.getVersion().getVersion(), ArtifactScope.USER);
ArtifactSummary artifact2 = new ArtifactSummary(pluginsId2.getName(), pluginsId2.getVersion().getVersion(), ArtifactScope.USER);
PluginSummary summary1Namespace1 = new PluginSummary("Plugin1", "dummy", "This is plugin1", Plugin1.class.getName(), artifact1);
PluginSummary summary2Namespace1 = new PluginSummary("Plugin2", "callable", "Just returns the configured integer", Plugin2.class.getName(), artifact1);
PluginSummary summary1Namespace2 = new PluginSummary("Plugin1", "dummy", "This is plugin1", Plugin1.class.getName(), artifact2);
PluginSummary summary2Namespace2 = new PluginSummary("Plugin2", "callable", "Just returns the configured integer", Plugin2.class.getName(), artifact2);
PluginInfo info1Namespace1 = new PluginInfo("Plugin1", "dummy", "This is plugin1", Plugin1.class.getName(), artifact1, ImmutableMap.of("x", new PluginPropertyField("x", "", "int", true, false), "stuff", new PluginPropertyField("stuff", "", "string", true, true)), new HashSet<String>());
PluginInfo info2Namespace1 = new PluginInfo("Plugin2", "callable", "Just returns the configured integer", Plugin2.class.getName(), artifact1, ImmutableMap.of("v", new PluginPropertyField("v", "value to return when called", "int", true, false)), new HashSet<String>());
PluginInfo info1Namespace2 = new PluginInfo("Plugin1", "dummy", "This is plugin1", Plugin1.class.getName(), artifact2, ImmutableMap.of("x", new PluginPropertyField("x", "", "int", true, false), "stuff", new PluginPropertyField("stuff", "", "string", true, true)), new HashSet<String>());
PluginInfo info2Namespace2 = new PluginInfo("Plugin2", "callable", "Just returns the configured integer", Plugin2.class.getName(), artifact2, ImmutableMap.of("v", new PluginPropertyField("v", "value to return when called", "int", true, false)), new HashSet<String>());
Id.Artifact namespace1Artifact = Id.Artifact.from(namespace1, systemId.getName(), systemId.getVersion());
Id.Artifact namespace2Artifact = Id.Artifact.from(namespace2, systemId.getName(), systemId.getVersion());
// should see same types in both namespaces
Assert.assertEquals(ImmutableSet.of("dummy", "callable"), getPluginTypes(namespace1Artifact, ArtifactScope.SYSTEM));
Assert.assertEquals(ImmutableSet.of("dummy", "callable"), getPluginTypes(namespace2Artifact, ArtifactScope.SYSTEM));
// should see that plugins in namespace1 come only from the namespace1 artifact
Assert.assertEquals(ImmutableSet.of(summary1Namespace1), getPluginSummaries(namespace1Artifact, "dummy", ArtifactScope.SYSTEM));
Assert.assertEquals(ImmutableSet.of(summary2Namespace1), getPluginSummaries(namespace1Artifact, "callable", ArtifactScope.SYSTEM));
Assert.assertEquals(ImmutableSet.of(info1Namespace1), getPluginInfos(namespace1Artifact, "dummy", "Plugin1", ArtifactScope.SYSTEM));
Assert.assertEquals(ImmutableSet.of(info2Namespace1), getPluginInfos(namespace1Artifact, "callable", "Plugin2", ArtifactScope.SYSTEM));
// should see that plugins in namespace2 come only from the namespace2 artifact
Assert.assertEquals(ImmutableSet.of(summary1Namespace2), getPluginSummaries(namespace2Artifact, "dummy", ArtifactScope.SYSTEM));
Assert.assertEquals(ImmutableSet.of(summary2Namespace2), getPluginSummaries(namespace2Artifact, "callable", ArtifactScope.SYSTEM));
Assert.assertEquals(ImmutableSet.of(info1Namespace2), getPluginInfos(namespace2Artifact, "dummy", "Plugin1", ArtifactScope.SYSTEM));
Assert.assertEquals(ImmutableSet.of(info2Namespace2), getPluginInfos(namespace2Artifact, "callable", "Plugin2", ArtifactScope.SYSTEM));
} finally {
deleteNamespace("iso1");
deleteNamespace("iso2");
}
}
use of co.cask.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ArtifactHttpHandlerTest method testDeletePropertiesAndArtifacts.
@Test
public void testDeletePropertiesAndArtifacts() throws Exception {
// add 2 versions of the same app that doesn't use config
Id.Artifact wordcountId1 = Id.Artifact.from(Id.Namespace.DEFAULT, "wordcount", "1.0.0");
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addAppArtifact(wordcountId1, WordCountApp.class).getStatusLine().getStatusCode());
// test get /artifacts endpoint
Set<ArtifactSummary> expectedArtifacts = Sets.newHashSet(new ArtifactSummary("wordcount", "1.0.0"));
Set<ArtifactSummary> actualArtifacts = getArtifacts(Id.Namespace.DEFAULT);
Assert.assertEquals(expectedArtifacts, actualArtifacts);
addArtifactProperties(wordcountId1, ImmutableMap.of("key1", "value1", "key2", "value2", "key3", "value3"));
Assert.assertEquals(ImmutableMap.of("key1", "value1", "key2", "value2", "key3", "value3"), getArtifactProperties(wordcountId1));
// delete a single property
deleteArtifact(wordcountId1, false, "key1", 200);
Assert.assertEquals(ImmutableMap.of("key2", "value2", "key3", "value3"), getArtifactProperties(wordcountId1));
// delete all properties
deleteArtifact(wordcountId1, false, null, 200);
Assert.assertEquals(ImmutableMap.of(), getArtifactProperties(wordcountId1));
Set<MetadataRecord> metadataRecords = metadataClient.getMetadata(wordcountId1, MetadataScope.USER);
Assert.assertEquals(1, metadataRecords.size());
Assert.assertEquals(new MetadataRecord(wordcountId1.toEntityId(), MetadataScope.USER), metadataRecords.iterator().next());
// delete artifact
deleteArtifact(wordcountId1, true, null, 200);
try {
metadataClient.getMetadata(wordcountId1, MetadataScope.USER);
Assert.fail("Should not reach here");
} catch (NotFoundException e) {
// no-op
}
actualArtifacts = getArtifacts(Id.Namespace.DEFAULT);
Assert.assertTrue(actualArtifacts.isEmpty());
}
use of co.cask.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ArtifactHttpHandlerTest method testPluginWithEndpoints.
@Test
public void testPluginWithEndpoints() throws Exception {
// add an app for plugins to extend
Id.Artifact wordCount1Id = Id.Artifact.from(Id.Namespace.DEFAULT, "wordcount", "1.0.0");
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addAppArtifact(wordCount1Id, WordCountApp.class).getStatusLine().getStatusCode());
Id.Artifact wordCount2Id = Id.Artifact.from(Id.Namespace.DEFAULT, "testartifact", "1.0.0");
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addAppArtifact(wordCount2Id, WordCountApp.class).getStatusLine().getStatusCode());
// add some plugins.
// plugins-3.0.0 extends wordcount[1.0.0,2.0.0)
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, CallablePlugin.class.getPackage().getName());
Id.Artifact plugins3Id = Id.Artifact.from(Id.Namespace.DEFAULT, "plugins3", "1.0.0");
Set<ArtifactRange> plugins3Parents = Sets.newHashSet(new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "wordcount", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addPluginArtifact(plugins3Id, CallablePlugin.class, manifest, plugins3Parents).getStatusLine().getStatusCode());
Set<PluginInfo> expectedInfos = Sets.newHashSet(new PluginInfo("CallablePlugin", "interactive", "This is plugin with endpoint", CallablePlugin.class.getName(), new ArtifactSummary("plugins3", "1.0.0"), ImmutableMap.<String, PluginPropertyField>of(), ImmutableSet.<String>of("ping")));
Assert.assertEquals(expectedInfos, getPluginInfos(wordCount1Id, "interactive", "CallablePlugin"));
// test plugin with endpoint
Assert.assertEquals("hello", GSON.fromJson(callPluginMethod(plugins3Id, "interactive", "CallablePlugin", "ping", "user", ArtifactScope.USER, 200).getResponseBodyAsString(), String.class));
manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, CallingPlugin.class.getPackage().getName());
Id.Artifact plugins4Id = Id.Artifact.from(Id.Namespace.DEFAULT, "plugins4", "1.0.0");
// we also add test artifact as parent for calling plugin,
// when callable plugin is loaded by calling plugin's method,
// it will try with "testArtifact" parent - wouldn't be able to load
// then it will load using "wordcount" parent and succeed
Set<ArtifactRange> plugins4Parents = Sets.newHashSet(new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "wordcount", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")), new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "testartifact", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addPluginArtifact(plugins4Id, CallingPlugin.class, manifest, plugins4Parents).getStatusLine().getStatusCode());
// test plugin with endpoint having endpoint-context parameter
Assert.assertEquals("hi user", GSON.fromJson(callPluginMethod(plugins4Id, "interactive", "CallingPlugin", "ping", "user", ArtifactScope.USER, 200).getResponseBodyAsString(), String.class));
// test plugin that accepts list of data and aggregates and returns result map
manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, PluginWithPojo.class.getPackage().getName());
Id.Artifact plugins5Id = Id.Artifact.from(Id.Namespace.DEFAULT, "aggregator", "1.0.0");
Set<ArtifactRange> plugins5Parents = Sets.newHashSet(new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "wordcount", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addPluginArtifact(plugins5Id, PluginWithPojo.class, manifest, plugins5Parents).getStatusLine().getStatusCode());
// test plugin with endpoint having endpoint-context parameter
List<TestData> data = ImmutableList.of(new TestData(1, 10), new TestData(1, 20), new TestData(3, 15), new TestData(4, 5), new TestData(3, 15));
Map<Long, Long> expectedResult = new HashMap<>();
expectedResult.put(1L, 30L);
expectedResult.put(3L, 30L);
expectedResult.put(4L, 5L);
String response = callPluginMethod(plugins5Id, "interactive", "aggregator", "aggregate", GSON.toJson(data), ArtifactScope.USER, 200).getResponseBodyAsString();
Assert.assertEquals(expectedResult, GSON.fromJson(response, new TypeToken<Map<Long, Long>>() {
}.getType()));
// test calling a non-existent plugin method "bing"
callPluginMethod(plugins4Id, "interactive", "CallingPlugin", "bing", "user", ArtifactScope.USER, 404);
manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, InvalidPlugin.class.getPackage().getName());
Id.Artifact invalidPluginId = Id.Artifact.from(Id.Namespace.DEFAULT, "invalid", "1.0.0");
Set<ArtifactRange> invalidPluginParents = Sets.newHashSet(new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "wordcount", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
Assert.assertEquals(HttpResponseStatus.BAD_REQUEST.getCode(), addPluginArtifact(invalidPluginId, InvalidPlugin.class, manifest, invalidPluginParents).getStatusLine().getStatusCode());
// test adding plugin artifact which has endpoint method containing 3 params (invalid)
manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, InvalidPluginMethodParams.class.getPackage().getName());
invalidPluginId = Id.Artifact.from(Id.Namespace.DEFAULT, "invalidParams", "1.0.0");
invalidPluginParents = Sets.newHashSet(new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "wordcount", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
Assert.assertEquals(HttpResponseStatus.BAD_REQUEST.getCode(), addPluginArtifact(invalidPluginId, InvalidPluginMethodParams.class, manifest, invalidPluginParents).getStatusLine().getStatusCode());
// test adding plugin artifact which has endpoint method containing 2 params
// but 2nd param is not EndpointPluginContext (invalid)
manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, InvalidPluginMethodParamType.class.getPackage().getName());
invalidPluginId = Id.Artifact.from(Id.Namespace.DEFAULT, "invalidParamType", "1.0.0");
invalidPluginParents = Sets.newHashSet(new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "wordcount", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
Assert.assertEquals(HttpResponseStatus.BAD_REQUEST.getCode(), addPluginArtifact(invalidPluginId, InvalidPluginMethodParamType.class, manifest, invalidPluginParents).getStatusLine().getStatusCode());
// test adding plugin artifact which has endpoint methods containing 2 params
// but 2nd param is implementation and extensions of EndpointPluginContext, should succeed
manifest = new Manifest();
manifest.getMainAttributes().put(ManifestFields.EXPORT_PACKAGE, PluginEndpointContextTestPlugin.class.getPackage().getName());
Id.Artifact validPluginId = Id.Artifact.from(Id.Namespace.DEFAULT, "extender", "1.0.0");
Set<ArtifactRange> validPluginParents = Sets.newHashSet(new ArtifactRange(NamespaceId.DEFAULT.getNamespace(), "wordcount", new ArtifactVersion("1.0.0"), new ArtifactVersion("2.0.0")));
Assert.assertEquals(HttpResponseStatus.OK.getCode(), addPluginArtifact(validPluginId, PluginEndpointContextTestPlugin.class, manifest, validPluginParents).getStatusLine().getStatusCode());
}
use of co.cask.cdap.api.artifact.ArtifactSummary in project cdap by caskdata.
the class ProgramLifecycleHttpHandlerTest method testVersionedProgramStartStopStatus.
@Test
public void testVersionedProgramStartStopStatus() throws Exception {
Id.Artifact wordCountArtifactId = Id.Artifact.from(Id.Namespace.DEFAULT, "wordcountapp", VERSION1);
addAppArtifact(wordCountArtifactId, WordCountApp.class);
AppRequest<? extends Config> wordCountRequest = new AppRequest<>(new ArtifactSummary(wordCountArtifactId.getName(), wordCountArtifactId.getVersion().getVersion()));
ApplicationId wordCountApp1 = NamespaceId.DEFAULT.app("WordCountApp", VERSION1);
ProgramId wordcountFlow1 = wordCountApp1.program(ProgramType.FLOW, "WordCountFlow");
Id.Application wordCountAppDefault = wordCountApp1.toId();
Id.Program wordcountFlowDefault = wordcountFlow1.toId();
ApplicationId wordCountApp2 = NamespaceId.DEFAULT.app("WordCountApp", VERSION2);
ProgramId wordcountFlow2 = wordCountApp2.program(ProgramType.FLOW, "WordCountFlow");
// Start wordCountApp1
Assert.assertEquals(200, deploy(wordCountApp1, wordCountRequest).getStatusLine().getStatusCode());
// Start wordCountApp1 with default version
Assert.assertEquals(200, deploy(wordCountAppDefault, wordCountRequest).getStatusLine().getStatusCode());
// flow is stopped initially
Assert.assertEquals(STOPPED, getProgramStatus(wordcountFlow1));
// start flow
startProgram(wordcountFlow1, 200);
waitState(wordcountFlow1, RUNNING);
// same flow cannot be run concurrently in the same app version
startProgram(wordcountFlow1, 409);
// start flow in a wrong namespace
startProgram(new NamespaceId(TEST_NAMESPACE1).app(wordcountFlow1.getApplication(), wordcountFlow1.getVersion()).program(wordcountFlow1.getType(), wordcountFlow1.getProgram()), 404);
// Start the second version of the app
Assert.assertEquals(200, deploy(wordCountApp2, wordCountRequest).getStatusLine().getStatusCode());
// same flow cannot be run concurrently in multiple versions of the same app
startProgram(wordcountFlow2, 409);
startProgram(wordcountFlowDefault, 409);
stopProgram(wordcountFlow1, null, 200, null);
waitState(wordcountFlow1, "STOPPED");
// wordcountFlow2 can be run after wordcountFlow1 is stopped
startProgram(wordcountFlow2, 200);
stopProgram(wordcountFlow2, null, 200, null);
ProgramId wordFrequencyService1 = wordCountApp1.program(ProgramType.SERVICE, "WordFrequencyService");
ProgramId wordFrequencyService2 = wordCountApp2.program(ProgramType.SERVICE, "WordFrequencyService");
Id.Program wordFrequencyServiceDefault = wordFrequencyService1.toId();
// service is stopped initially
Assert.assertEquals(STOPPED, getProgramStatus(wordFrequencyService1));
// start service
startProgram(wordFrequencyService1, 200);
waitState(wordFrequencyService1, RUNNING);
// wordFrequencyService2 is stopped initially
Assert.assertEquals(STOPPED, getProgramStatus(wordFrequencyService2));
// start service in version2
startProgram(wordFrequencyService2, 200);
waitState(wordFrequencyService2, RUNNING);
// wordFrequencyServiceDefault is stopped initially
Assert.assertEquals(STOPPED, getProgramStatus(wordFrequencyServiceDefault));
// start service in default version
startProgram(wordFrequencyServiceDefault, 200);
waitState(wordFrequencyServiceDefault, RUNNING);
// same service cannot be run concurrently in the same app version
startProgram(wordFrequencyService1, 409);
stopProgram(wordFrequencyService1, null, 200, null);
Assert.assertEquals(STOPPED, getProgramStatus(wordFrequencyService1));
// wordFrequencyService1 can be run after wordFrequencyService1 is stopped
startProgram(wordFrequencyService1, 200);
stopProgram(wordFrequencyService1, null, 200, null);
stopProgram(wordFrequencyService2, null, 200, null);
stopProgram(wordFrequencyServiceDefault, null, 200, null);
Id.Artifact sleepWorkflowArtifactId = Id.Artifact.from(Id.Namespace.DEFAULT, "sleepworkflowapp", VERSION1);
addAppArtifact(sleepWorkflowArtifactId, SleepingWorkflowApp.class);
AppRequest<? extends Config> sleepWorkflowRequest = new AppRequest<>(new ArtifactSummary(sleepWorkflowArtifactId.getName(), sleepWorkflowArtifactId.getVersion().getVersion()));
ApplicationId sleepWorkflowApp1 = new ApplicationId(Id.Namespace.DEFAULT.getId(), "SleepingWorkflowApp", VERSION1);
ProgramId sleepWorkflow1 = sleepWorkflowApp1.program(ProgramType.WORKFLOW, "SleepWorkflow");
ApplicationId sleepWorkflowApp2 = new ApplicationId(Id.Namespace.DEFAULT.getId(), "SleepingWorkflowApp", VERSION2);
ProgramId sleepWorkflow2 = sleepWorkflowApp2.program(ProgramType.WORKFLOW, "SleepWorkflow");
// Start wordCountApp1
Assert.assertEquals(200, deploy(sleepWorkflowApp1, sleepWorkflowRequest).getStatusLine().getStatusCode());
// workflow is stopped initially
Assert.assertEquals(STOPPED, getProgramStatus(sleepWorkflow1));
// start workflow in a wrong version
startProgram(sleepWorkflow2, 404);
// Start wordCountApp2
Assert.assertEquals(200, deploy(sleepWorkflowApp2, sleepWorkflowRequest).getStatusLine().getStatusCode());
// start multiple workflow simultaneously
startProgram(sleepWorkflow1, 200);
startProgram(sleepWorkflow2, 200);
startProgram(sleepWorkflow1, 200);
startProgram(sleepWorkflow2, 200);
// stop multiple workflow simultaneously
// This will stop all concurrent runs of the Workflow version 1.0.0
stopProgram(sleepWorkflow1, null, 200, null);
// This will stop all concurrent runs of the Workflow version 2.0.0
stopProgram(sleepWorkflow2, null, 200, null);
Assert.assertEquals(STOPPED, getProgramStatus(sleepWorkflow1));
Assert.assertEquals(STOPPED, getProgramStatus(sleepWorkflow2));
//Test for runtime args
testVersionedProgramRuntimeArgs(sleepWorkflow1);
// cleanup
deleteApp(wordCountApp1, 200);
deleteApp(wordCountApp2, 200);
deleteApp(wordCountAppDefault, 200);
deleteApp(sleepWorkflowApp1, 200);
deleteApp(sleepWorkflowApp2, 200);
}
Aggregations