blob: a70fee1710bd245a4bd066bbe855735bae3a076c [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.usergrid.rest.applications;
import com.fasterxml.jackson.databind.JsonNode;
import com.sun.jersey.api.client.UniformInterfaceException;
import org.apache.usergrid.rest.test.resource2point0.AbstractRestIT;
import org.apache.usergrid.rest.test.resource2point0.endpoints.mgmt.ManagementResponse;
import org.apache.usergrid.rest.test.resource2point0.model.*;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.jcip.annotations.NotThreadSafe;
import javax.ws.rs.core.MediaType;
import java.util.*;
import static org.junit.Assert.fail;
@NotThreadSafe
public class ApplicationDeleteIT extends AbstractRestIT {
private static final Logger logger = LoggerFactory.getLogger(ApplicationDeleteIT.class);
public static final int INDEXING_WAIT = 3000;
Token orgAdminToken;
String orgName;
@Before
public void setup(){
orgAdminToken = getAdminToken( clientSetup.getUsername(), clientSetup.getUsername());
orgName = clientSetup.getOrganization().getName();
}
/**
* Test most common use cases.
* <pre>
* - create app with collection of things
* - delete the app
* - test that attempts to get the app, its collections and entities throw 400 with message
* - test that we cannot delete the app a second time
* - test that we can create a new app with the same name as the deleted app
* </pre>
*/
@Test
public void testBasicOperation() throws Exception {
// create app with a collection of "things"
List<Entity> entities = new ArrayList<>();
String appToDeleteName = clientSetup.getAppName() + UUID.randomUUID();
UUID appToDeleteId = createAppWithCollection(orgName, appToDeleteName, orgAdminToken, entities);
// delete the app
try {
clientSetup.getRestClient()
.org(orgName).app(appToDeleteId.toString()).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken())
.delete();
fail("Delete must fail without app_delete_confirm parameter");
} catch ( Exception e ) {
logger.error("Error", e);
}
clientSetup.getRestClient()
.org(orgName).app(appToDeleteId.toString() ).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken() )
.queryParam("app_delete_confirm", "confirm_delete_of_application_and_data")
.delete();
// test that we can no longer get the app
try {
clientSetup.getRestClient()
.org(orgName).app(appToDeleteName).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken())
.type(MediaType.APPLICATION_JSON)
.get(ApiResponse.class);
fail("Must not be able to get deleted app");
} catch ( UniformInterfaceException expected ) {
Assert.assertEquals("Error must be 400", 400, expected.getResponse().getStatus() );
JsonNode node = mapper.readTree( expected.getResponse().getEntity( String.class ));
Assert.assertEquals("organization_application_not_found", node.get("error").textValue());
}
// test that we can no longer get deleted app's collection
try {
clientSetup.getRestClient()
.org(orgName).app(appToDeleteName).collection("things").getResource()
.queryParam("access_token", orgAdminToken.getAccessToken() )
.type(MediaType.APPLICATION_JSON )
.get(ApiResponse.class);
fail("Must not be able to get deleted app's collection");
} catch ( UniformInterfaceException expected ) {
Assert.assertEquals("Error must be 400", 400, expected.getResponse().getStatus() );
JsonNode node = mapper.readTree( expected.getResponse().getEntity( String.class ));
Assert.assertEquals("organization_application_not_found", node.get("error").textValue());
}
// test that we can no longer get an app entity
try {
UUID entityId = entities.get(0).getUuid();
clientSetup.getRestClient()
.org(orgName).app(appToDeleteName).collection("things").entity( entityId ).getResource()
.queryParam( "access_token", orgAdminToken.getAccessToken())
.type( MediaType.APPLICATION_JSON)
.get(ApiResponse.class);
fail("Must not be able to get deleted app entity");
} catch ( UniformInterfaceException expected ) {
// TODO: why not a 404?
Assert.assertEquals("Error must be 400", 400, expected.getResponse().getStatus() );
JsonNode node = mapper.readTree( expected.getResponse().getEntity( String.class ));
Assert.assertEquals("organization_application_not_found", node.get("error").textValue());
}
// test that we cannot see the application in the list of applications returned
// by the management resource's get organization's applications end-point
refreshIndex();
ManagementResponse orgAppResponse = clientSetup.getRestClient()
.management().orgs().organization( orgName ).apps().getOrganizationApplications();
for ( String appName : orgAppResponse.getData().keySet() ) {
if ( orgAppResponse.getData().get( appName ).equals( appToDeleteId.toString() )) {
fail("Deleted app must not be included in list of org apps");
}
}
// test that we cannot delete the application a second time
try {
clientSetup.getRestClient()
.org(orgName).app(appToDeleteId.toString()).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken())
.delete();
} catch ( UniformInterfaceException expected ) {
Assert.assertEquals("Error must be 404", 404, expected.getResponse().getStatus() );
JsonNode node = mapper.readTree( expected.getResponse().getEntity( String.class ));
Assert.assertEquals("not_found", node.get("error").textValue());
}
// test that we can create a new application with the same name
ApiResponse appCreateAgainResponse = clientSetup.getRestClient()
.management().orgs().organization( orgName ).app().getResource()
.queryParam( "access_token", orgAdminToken.getAccessToken() )
.type( MediaType.APPLICATION_JSON )
.post( ApiResponse.class, new Application( appToDeleteName ) );
Assert.assertEquals("Must be able to create app with same name as deleted app",
(orgName + "/" + appToDeleteName).toLowerCase(),
appCreateAgainResponse.getEntities().get(0).get("name"));
}
/**
* Test restore of deleted app.
* <pre>
* - create app with collection of things
* - delete the app
* - restore the app
* - test that we can get the app, its collections and an entity
* </pre>
*/
@Test
public void testAppRestore() throws Exception {
String appToDeleteName = clientSetup.getAppName() + UUID.randomUUID();
// create app with a collection of "things"
List<Entity> entities = new ArrayList<>();
UUID appToDeleteId = createAppWithCollection(orgName, appToDeleteName, orgAdminToken, entities);
// delete the app
logger.debug("\n\nDeleting app\n");
clientSetup.getRestClient()
.org(orgName).app( appToDeleteName ).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken() )
.queryParam("app_delete_confirm", "confirm_delete_of_application_and_data")
.delete();
refreshIndex();
// restore the app
logger.debug("\n\nRestoring app\n");
clientSetup.getRestClient()
.org(orgName).app( appToDeleteId.toString() ).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken() )
.put();
refreshIndex();
// test that we can see the application in the list of applications
logger.debug("\n\nGetting app list from management end-point\n");
ManagementResponse orgAppResponse = clientSetup.getRestClient()
.management().orgs().organization( orgName ).apps().getOrganizationApplications();
boolean found = false;
for ( String appName : orgAppResponse.getData().keySet() ) {
if ( orgAppResponse.getData().get( appName ).equals( appToDeleteId.toString() )) {
found = true;
break;
}
}
Assert.assertTrue( found );
// test that we can get an app entity
logger.debug("\n\nGetting entities from app\n");
UUID entityId = entities.get(0).getUuid();
ApiResponse entityResponse = clientSetup.getRestClient()
.org(orgName).app(appToDeleteName).collection("things").entity( entityId ).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken())
.type(MediaType.APPLICATION_JSON)
.get(ApiResponse.class);
Assert.assertEquals( entityId, entityResponse.getEntities().get(0).getUuid() );
// test that we can get deleted app's collection
ApiResponse collectionReponse = clientSetup.getRestClient()
.org(orgName).app(appToDeleteName).collection("things").getResource()
.queryParam("access_token", orgAdminToken.getAccessToken())
.type(MediaType.APPLICATION_JSON)
.get(ApiResponse.class);
Assert.assertEquals( entities.size(), collectionReponse.getEntityCount() );
}
/**
* Test that we cannot restore deleted app with same name as
*/
@Test
public void testAppRestoreConflict() throws Exception {
String appToDeleteName = clientSetup.getAppName() + UUID.randomUUID();
// create app with a collection of "things"
List<Entity> entities = new ArrayList<>();
UUID appToDeleteId = createAppWithCollection(orgName, appToDeleteName, orgAdminToken, entities);
// delete the app
clientSetup.getRestClient()
.org( orgName ).app(appToDeleteId.toString() ).getResource()
.queryParam( "access_token", orgAdminToken.getAccessToken() )
.queryParam("app_delete_confirm", "confirm_delete_of_application_and_data")
.delete();
refreshIndex();
// create new app with same name
createAppWithCollection(orgName, appToDeleteName, orgAdminToken, entities);
// attempt to restore original app, should get 409
try {
clientSetup.getRestClient()
.org(orgName).app(appToDeleteId.toString()).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken())
.put();
fail("Must fail to restore app with same name as existing app");
} catch ( UniformInterfaceException e ) {
Assert.assertEquals(409, e.getResponse().getStatus());
}
}
/**
* Test that we cannot delete an app with same name as an app that is already deleted.
* TODO: investigate way to support this, there should be no such restriction.
*/
@Test
public void testAppDeleteConflict() throws Exception {
String appToDeleteName = clientSetup.getAppName() + UUID.randomUUID();
// create app with a collection of "things"
String orgName = clientSetup.getOrganization().getName();
Token orgAdminToken = getAdminToken( clientSetup.getUsername(), clientSetup.getUsername());
List<Entity> entities = new ArrayList<>();
UUID appToDeleteId = createAppWithCollection(orgName, appToDeleteName, orgAdminToken, entities);
// delete the app
clientSetup.getRestClient()
.org( orgName ).app(appToDeleteId.toString() ).getResource()
.queryParam( "access_token", orgAdminToken.getAccessToken() )
.queryParam("app_delete_confirm", "confirm_delete_of_application_and_data")
.delete();
refreshIndex();
// create new app with same name
UUID newAppId = createAppWithCollection(orgName, appToDeleteName, orgAdminToken, entities);
// attempt to delete new app, it should fail
try {
clientSetup.getRestClient()
.org(orgName).app( newAppId.toString() ).getResource()
.queryParam("access_token", orgAdminToken.getAccessToken())
.queryParam("app_delete_confirm", "confirm_delete_of_application_and_data")
.delete();
fail("Must fail to delete app with same name as deleted app");
} catch ( UniformInterfaceException e ) {
Assert.assertEquals( 409, e.getResponse().getStatus() );
}
}
private UUID createAppWithCollection(
String orgName, String appName, Token orgAdminToken, List<Entity> entities) {
ApiResponse appCreateResponse = clientSetup.getRestClient()
.management().orgs().organization( orgName ).app().getResource()
.queryParam( "access_token", orgAdminToken.getAccessToken() )
.type( MediaType.APPLICATION_JSON )
.post( ApiResponse.class, new Application( appName ) );
UUID appId = appCreateResponse.getEntities().get(0).getUuid();
try { Thread.sleep(INDEXING_WAIT); } catch (InterruptedException ignored ) { }
for ( int i=0; i<10; i++ ) {
final String entityName = "entity" + i;
Entity entity = new Entity();
entity.setProperties(new HashMap<String, Object>() {{
put("name", entityName );
}});
ApiResponse createResponse = clientSetup.getRestClient()
.org(orgName).app( appName ).collection("things").getResource()
.queryParam("access_token", orgAdminToken.getAccessToken())
.type(MediaType.APPLICATION_JSON)
.post( ApiResponse.class, entity );
entities.add( createResponse.getEntities().get(0) );
}
refreshIndex();
return appId;
}
}