/*
* Copyright © 2015 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package co.cask.cdap.client;
import co.cask.cdap.client.app.AppReturnsArgs;
import co.cask.cdap.client.app.FakeApp;
import co.cask.cdap.client.common.ClientTestBase;
import co.cask.cdap.common.ApplicationNotFoundException;
import co.cask.cdap.common.NotFoundException;
import co.cask.cdap.common.ProgramNotFoundException;
import co.cask.cdap.proto.Id;
import co.cask.cdap.proto.NamespaceMeta;
import co.cask.cdap.proto.ProgramType;
import co.cask.cdap.test.XSlowTests;
import co.cask.common.http.HttpMethod;
import co.cask.common.http.HttpRequest;
import co.cask.common.http.HttpRequests;
import co.cask.common.http.HttpResponse;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
/**
* Test for {@link PreferencesClient}
*/
@Category(XSlowTests.class)
public class PreferencesClientTestRun extends ClientTestBase {
private static final Gson GSON = new Gson();
private static final Id.Application FAKE_APP_ID = Id.Application.from(Id.Namespace.DEFAULT, FakeApp.NAME);
private static final Type STRING_MAP_TYPE = new TypeToken<Map<String, String>>() { }.getType();
private PreferencesClient client;
private ApplicationClient appClient;
private ServiceClient serviceClient;
private ProgramClient programClient;
private NamespaceClient namespaceClient;
@Before
public void setUp() throws Throwable {
super.setUp();
client = new PreferencesClient(clientConfig);
appClient = new ApplicationClient(clientConfig);
serviceClient = new ServiceClient(clientConfig);
programClient = new ProgramClient(clientConfig);
namespaceClient = new NamespaceClient(clientConfig);
}
@Test
public void testProgramAPI() throws Exception {
Map<String, String> propMap = Maps.newHashMap();
propMap.put("key", "instance");
File jarFile = createAppJarFile(AppReturnsArgs.class);
appClient.deploy(Id.Namespace.DEFAULT, jarFile);
Id.Application app = Id.Application.from(Id.Namespace.DEFAULT, AppReturnsArgs.NAME);
Id.Service service = Id.Service.from(app, AppReturnsArgs.SERVICE);
try {
client.setInstancePreferences(propMap);
Map<String, String> setMap = Maps.newHashMap();
setMap.put("saved", "args");
programClient.setRuntimeArgs(service, setMap);
assertEquals(setMap, programClient.getRuntimeArgs(service));
propMap.put("run", "value");
propMap.put("logical.start.time", "1234567890000");
propMap.putAll(setMap);
programClient.start(service, false, propMap);
assertProgramRunning(programClient, service);
URL serviceURL = new URL(serviceClient.getServiceURL(service), AppReturnsArgs.ENDPOINT);
HttpResponse response = getServiceResponse(serviceURL);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
Map<String, String> responseMap = GSON.fromJson(response.getResponseBodyAsString(), STRING_MAP_TYPE);
assertEquals(propMap, responseMap);
programClient.stop(service);
assertProgramStopped(programClient, service);
long minStartTime = System.currentTimeMillis();
client.deleteInstancePreferences();
programClient.start(service);
assertProgramRunning(programClient, service);
propMap.remove("key");
propMap.remove("run");
propMap.remove("logical.start.time");
serviceURL = new URL(serviceClient.getServiceURL(service), AppReturnsArgs.ENDPOINT);
response = getServiceResponse(serviceURL);
responseMap = GSON.fromJson(response.getResponseBodyAsString(), STRING_MAP_TYPE);
long actualStartTime = Long.parseLong(responseMap.remove("logical.start.time"));
Assert.assertTrue(actualStartTime >= minStartTime);
assertEquals(propMap, responseMap);
programClient.stop(service);
assertProgramStopped(programClient, service);
propMap.clear();
minStartTime = System.currentTimeMillis();
programClient.setRuntimeArgs(service, propMap);
programClient.start(service);
assertProgramRunning(programClient, service);
serviceURL = new URL(serviceClient.getServiceURL(service), AppReturnsArgs.ENDPOINT);
response = getServiceResponse(serviceURL);
assertEquals(HttpURLConnection.HTTP_OK, response.getResponseCode());
responseMap = GSON.fromJson(response.getResponseBodyAsString(), STRING_MAP_TYPE);
actualStartTime = Long.parseLong(responseMap.remove("logical.start.time"));
Assert.assertTrue(actualStartTime >= minStartTime);
assertEquals(propMap, responseMap);
} finally {
programClient.stop(service);
assertProgramStopped(programClient, service);
appClient.delete(app);
}
}
private HttpResponse getServiceResponse(URL serviceURL) throws IOException, InterruptedException {
int iterations = 0;
HttpResponse response;
do {
response = HttpRequests.execute(HttpRequest.builder(HttpMethod.GET, serviceURL).build());
if (response.getResponseCode() == HttpURLConnection.HTTP_OK) {
return response;
}
TimeUnit.MILLISECONDS.sleep(50);
iterations++;
} while (iterations <= 100);
return response;
}
@Test
public void testPreferences() throws Exception {
Id.Namespace invalidNamespace = Id.Namespace.from("invalid");
namespaceClient.create(new NamespaceMeta.Builder().setName(invalidNamespace.getId()).build());
Map<String, String> propMap = client.getInstancePreferences();
Assert.assertEquals(ImmutableMap.<String, String>of(), propMap);
propMap.put("k1", "instance");
client.setInstancePreferences(propMap);
Assert.assertEquals(propMap, client.getInstancePreferences());
File jarFile = createAppJarFile(FakeApp.class);
appClient.deploy(Id.Namespace.DEFAULT, jarFile);
try {
propMap.put("k1", "namespace");
client.setNamespacePreferences(Id.Namespace.DEFAULT, propMap);
Assert.assertEquals(propMap, client.getNamespacePreferences(Id.Namespace.DEFAULT, true));
Assert.assertEquals(propMap, client.getNamespacePreferences(Id.Namespace.DEFAULT, false));
Assert.assertTrue(client.getNamespacePreferences(invalidNamespace, false).isEmpty());
Assert.assertEquals("instance", client.getNamespacePreferences(invalidNamespace, true).get("k1"));
client.deleteNamespacePreferences(Id.Namespace.DEFAULT);
propMap.put("k1", "instance");
Assert.assertEquals(propMap, client.getNamespacePreferences(Id.Namespace.DEFAULT, true));
Assert.assertEquals(ImmutableMap.<String, String>of(),
client.getNamespacePreferences(Id.Namespace.DEFAULT, false));
propMap.put("k1", "namespace");
client.setNamespacePreferences(Id.Namespace.DEFAULT, propMap);
Assert.assertEquals(propMap, client.getNamespacePreferences(Id.Namespace.DEFAULT, true));
Assert.assertEquals(propMap, client.getNamespacePreferences(Id.Namespace.DEFAULT, false));
propMap.put("k1", "application");
client.setApplicationPreferences(FAKE_APP_ID, propMap);
Assert.assertEquals(propMap, client.getApplicationPreferences(FAKE_APP_ID, true));
Assert.assertEquals(propMap, client.getApplicationPreferences(FAKE_APP_ID, false));
propMap.put("k1", "program");
Id.Program flow = Id.Program.from(FAKE_APP_ID, ProgramType.FLOW, FakeApp.FLOWS.get(0));
client.setProgramPreferences(flow, propMap);
Assert.assertEquals(propMap, client.getProgramPreferences(flow, true));
Assert.assertEquals(propMap, client.getProgramPreferences(flow, false));
client.deleteProgramPreferences(flow);
propMap.put("k1", "application");
Assert.assertTrue(client.getProgramPreferences(flow, false).isEmpty());
Assert.assertEquals(propMap, client.getProgramPreferences(flow, true));
client.deleteApplicationPreferences(FAKE_APP_ID);
propMap.put("k1", "namespace");
Assert.assertTrue(client.getApplicationPreferences(FAKE_APP_ID, false).isEmpty());
Assert.assertEquals(propMap, client.getApplicationPreferences(FAKE_APP_ID, true));
Assert.assertEquals(propMap, client.getProgramPreferences(flow, true));
client.deleteNamespacePreferences(Id.Namespace.DEFAULT);
propMap.put("k1", "instance");
Assert.assertTrue(client.getNamespacePreferences(Id.Namespace.DEFAULT, false).isEmpty());
Assert.assertEquals(propMap, client.getNamespacePreferences(Id.Namespace.DEFAULT, true));
Assert.assertEquals(propMap, client.getApplicationPreferences(FAKE_APP_ID, true));
Assert.assertEquals(propMap, client.getProgramPreferences(flow, true));
client.deleteInstancePreferences();
propMap.clear();
Assert.assertEquals(propMap, client.getInstancePreferences());
Assert.assertEquals(propMap, client.getNamespacePreferences(Id.Namespace.DEFAULT, true));
Assert.assertEquals(propMap, client.getNamespacePreferences(Id.Namespace.DEFAULT, true));
Assert.assertEquals(propMap, client.getApplicationPreferences(FAKE_APP_ID, true));
Assert.assertEquals(propMap, client.getProgramPreferences(flow, true));
//Test Deleting Application
propMap.put("k1", "application");
client.setApplicationPreferences(FAKE_APP_ID, propMap);
Assert.assertEquals(propMap, client.getApplicationPreferences(FAKE_APP_ID, false));
propMap.put("k1", "program");
client.setProgramPreferences(flow, propMap);
Assert.assertEquals(propMap, client.getProgramPreferences(flow, false));
appClient.delete(FAKE_APP_ID);
// deleting the app should have deleted the preferences that were stored. so deploy the app and check
// if the preferences are empty. we need to deploy the app again since getting preferences of non-existent apps
// is not allowed by the API.
appClient.deploy(Id.Namespace.DEFAULT, jarFile);
propMap.clear();
Assert.assertEquals(propMap, client.getApplicationPreferences(FAKE_APP_ID, false));
Assert.assertEquals(propMap, client.getProgramPreferences(flow, false));
} finally {
try {
appClient.delete(FAKE_APP_ID);
} catch (ApplicationNotFoundException e) {
// ok if this happens, means its already deleted.
}
namespaceClient.delete(invalidNamespace);
}
}
@Test
public void testDeletingNamespace() throws Exception {
Map<String, String> propMap = Maps.newHashMap();
propMap.put("k1", "namespace");
Id.Namespace myspace = Id.Namespace.from("myspace");
namespaceClient.create(new NamespaceMeta.Builder().setName(myspace.getId()).build());
client.setNamespacePreferences(myspace, propMap);
Assert.assertEquals(propMap, client.getNamespacePreferences(myspace, false));
Assert.assertEquals(propMap, client.getNamespacePreferences(myspace, true));
namespaceClient.delete(myspace);
namespaceClient.create(new NamespaceMeta.Builder().setName(myspace.getId()).build());
Assert.assertTrue(client.getNamespacePreferences(myspace, false).isEmpty());
Assert.assertTrue(client.getNamespacePreferences(myspace, true).isEmpty());
namespaceClient.delete(myspace);
}
@Test(expected = NotFoundException.class)
public void testInvalidNamespace() throws Exception {
Id.Namespace somespace = Id.Namespace.from("somespace");
client.setNamespacePreferences(somespace, ImmutableMap.of("k1", "v1"));
}
@Test(expected = NotFoundException.class)
public void testInvalidApplication() throws Exception {
Id.Application someapp = Id.Application.from("somespace", "someapp");
client.getApplicationPreferences(someapp, true);
}
@Test(expected = ProgramNotFoundException.class)
public void testInvalidProgram() throws Exception {
Id.Application someapp = Id.Application.from("somespace", "someapp");
client.deleteProgramPreferences(Id.Program.from(someapp, ProgramType.FLOW, "myflow"));
}
}