com.orange.clara.cloud.servicedbdumper.integrations.AbstractIntegrationWithRealCfClientTest.java Source code

Java tutorial

Introduction

Here is the source code for com.orange.clara.cloud.servicedbdumper.integrations.AbstractIntegrationWithRealCfClientTest.java

Source

package com.orange.clara.cloud.servicedbdumper.integrations;

import com.orange.clara.cloud.servicedbdumper.cloudfoundry.CloudFoundryClientFactory;
import com.orange.clara.cloud.servicedbdumper.exception.CannotFindDatabaseDumperException;
import com.orange.clara.cloud.servicedbdumper.exception.DatabaseExtractionException;
import com.orange.clara.cloud.servicedbdumper.exception.ServiceKeyException;
import com.orange.clara.cloud.servicedbdumper.integrations.model.DatabaseAccess;
import com.orange.clara.cloud.servicedbdumper.model.DatabaseRef;
import com.orange.clara.cloud.servicedbdumper.model.DatabaseType;
import org.cloudfoundry.client.lib.CloudFoundryClient;
import org.cloudfoundry.client.lib.domain.CloudService;
import org.cloudfoundry.client.lib.domain.CloudServiceKey;
import org.cloudfoundry.client.lib.domain.CloudServiceOffering;
import org.cloudfoundry.client.lib.domain.CloudServicePlan;
import org.cloudfoundry.community.servicebroker.exception.ServiceBrokerAsyncRequiredException;
import org.cloudfoundry.community.servicebroker.exception.ServiceBrokerException;
import org.junit.After;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.web.client.HttpServerErrorException;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.*;

import static org.fest.assertions.Fail.fail;
import static org.junit.Assume.assumeTrue;

/**
 * Copyright (C) 2016 Orange
 * <p>
 * This software is distributed under the terms and conditions of the 'Apache-2.0'
 * license which can be found in the file 'LICENSE' in this package distribution
 * or at 'https://opensource.org/licenses/Apache-2.0'.
 * <p>
 * Author: Arthur Halet
 * Date: 08/04/2016
 */
abstract public class AbstractIntegrationWithRealCfClientTest extends AbstractIntegrationTest {

    @Value("${int.cf.service.name.mysql:cleardb}")
    protected String serviceNameMysql;
    @Value("${int.cf.service.plan.mysql:spark}")
    protected String servicePlanMysql;
    @Value("${int.cf.service.instance.source.mysql:mysql-db-dumper-src-int}")
    protected String serviceSourceInstanceMysql;
    @Value("${int.cf.service.instance.target.mysql:mysql-db-dumper-dest-int}")
    protected String serviceTargetInstanceMysql;

    @Value("${int.cf.service.name.postgresql:elephantsql}")
    protected String serviceNamePostgres;
    @Value("${int.cf.service.plan.postgresql:turtle}")
    protected String servicePlanPostgres;
    @Value("${int.cf.service.instance.source.postgresql:postgres-db-dumper-src-int}")
    protected String serviceSourceInstancePostgres;
    @Value("${int.cf.service.instance.target.postgresql:postgres-db-dumper-dest-int}")
    protected String serviceTargetInstancePostgres;

    @Value("${int.cf.service.name.mongodb:mongolab}")
    protected String serviceNameMongo;
    @Value("${int.cf.service.plan.mongodb:sandbox}")
    protected String servicePlanMongo;
    @Value("${int.cf.service.instance.source.mongodb:mongodb-db-dumper-src-int}")
    protected String serviceSourceInstanceMongo;
    @Value("${int.cf.service.instance.target.mongodb:mongodb-db-dumper-dest-int}")
    protected String serviceTargetInstanceMongo;

    @Value("${int.cf.service.name.redis:rediscloud}")
    protected String serviceNameRedis;
    @Value("${int.cf.service.plan.redis:30mb}")
    protected String servicePlanRedis;
    @Value("${int.cf.service.instance.source.redis:redis-db-dumper-src-int}")
    protected String serviceSourceInstanceRedis;
    @Value("${int.cf.service.instance.target.redis:redis-db-dumper-dest-int}")
    protected String serviceTargetInstanceRedis;

    protected CloudFoundryClient cfClientToPopulate;

    @Autowired
    protected CloudFoundryClientFactory clientFactory;
    @Autowired
    @Qualifier("cfAdminUser")
    protected String cfAdminUser;
    @Autowired
    @Qualifier("cfAdminPassword")
    protected String cfAdminPassword;
    @Autowired
    @Qualifier("cloudControllerUrl")
    protected String cloudControllerUrl;
    @Value("${test.cf.admin.org:#{null}}")
    protected String org;
    @Value("${test.cf.admin.space:#{null}}")
    protected String space;
    @Value("${test.timeout.creating.service:5}")
    protected int timeoutCreatingService;
    @Autowired
    @Qualifier("cloudFoundryClientAsAdmin")
    protected CloudFoundryClient cfAdminClient;

    @Override
    @Before
    public void init() throws DatabaseExtractionException {
        super.init();
    }

    @Override
    public void doBeforeTest(DatabaseType databaseType) throws DatabaseExtractionException,
            CannotFindDatabaseDumperException, InterruptedException, IOException {
        if (this.cfAdminUser == null || this.cfAdminUser.isEmpty() || this.cfAdminPassword == null
                || this.cfAdminPassword.isEmpty() || this.cloudControllerUrl == null
                || this.cloudControllerUrl.isEmpty()) {
            String skipMessage = "Please define properties: cf.admin.user, cf.admin.password, cloud.controller.url to run this test. This test is skipped.";
            this.reportIntegration.setSkipped(true);
            this.reportIntegration.setSkippedReason(skipMessage);
            assumeTrue(skipMessage, false);
        }

        cfClientToPopulate = this.clientFactory.createCloudFoundryClient(cfAdminUser, cfAdminPassword,
                cloudControllerUrl, org, space);

        DatabaseAccess databaseAccess = this.databaseAccessMap.get(databaseType);
        boolean isServiceExists = isServiceExist(databaseAccess.getServiceName(), databaseAccess.getServicePlan());
        if (!isServiceExists) {
            this.skipCleaning = true;
            String skipMessage = String.format(
                    "The service %s with plan %s doesn't exists please set properties 'test.cf.service.name.%s' and 'test.cf.service.plan.%s'",
                    databaseAccess.getServiceName(), databaseAccess.getServicePlan(),
                    databaseAccess.generateDatabaseRef().getType().toString().toLowerCase(),
                    databaseAccess.generateDatabaseRef().getType().toString().toLowerCase());
            this.reportIntegration.setSkipped(true);
            this.reportIntegration.setSkippedReason(skipMessage);
            assumeTrue(skipMessage, false);
        }

        CloudService cloudServiceSource = new CloudService(null, databaseAccess.getServiceSourceInstanceName());
        cloudServiceSource.setPlan(databaseAccess.getServicePlan());
        cloudServiceSource.setLabel(databaseAccess.getServiceName());
        this.createService(cloudServiceSource);
        if (!databaseAccess.getServiceTargetInstanceName().equals(databaseAccess.getServiceSourceInstanceName())) {
            CloudService cloudServiceTarget = new CloudService(null, databaseAccess.getServiceTargetInstanceName());
            cloudServiceTarget.setPlan(databaseAccess.getServicePlan());
            cloudServiceTarget.setLabel(databaseAccess.getServiceName());
            this.createService(cloudServiceTarget);
        }
        OAuth2AccessToken accessToken = cfClientToPopulate.login();
        this.requestForge.setUserToken(accessToken.getValue());
        this.requestForge.setOrg(org);
        this.requestForge.setSpace(space);
        super.doBeforeTest(databaseType);
    }

    @Override
    public void cleanDatabase(DatabaseType databaseType) throws DatabaseExtractionException,
            CannotFindDatabaseDumperException, InterruptedException, IOException {

    }

    @Override
    @After
    public void cleanAfterTest() throws DatabaseExtractionException, CannotFindDatabaseDumperException,
            InterruptedException, IOException, ServiceBrokerAsyncRequiredException, ServiceBrokerException {
        if (this.cfAdminUser == null || this.cfAdminUser.isEmpty() || this.cfAdminPassword == null
                || this.cfAdminPassword.isEmpty() || this.cloudControllerUrl == null
                || this.cloudControllerUrl.isEmpty()) {
            return;
        }
        loadBeforeAction();
        for (DatabaseType databaseType : this.databaseAccessMap.keySet()) {
            DatabaseAccess databaseAccess = this.databaseAccessMap.get(databaseType);
            List<CloudServiceKey> cloudServiceKeys = this.cfClientToPopulate.getServiceKeys();
            for (CloudServiceKey cloudServiceKey : cloudServiceKeys) {
                if (cloudServiceKey.getService().getName().equals(databaseAccess.getServiceSourceInstanceName())
                        || cloudServiceKey.getService().getName()
                                .equals(databaseAccess.getServiceTargetInstanceName())) {
                    this.cfClientToPopulate.deleteServiceKey(cloudServiceKey);
                }
            }
            this.cfClientToPopulate.deleteService(databaseAccess.getServiceSourceInstanceName());
            this.cfClientToPopulate.deleteService(databaseAccess.getServiceTargetInstanceName());
        }
        if (this.skipCleaning) {
            return;
        }
        this.requestForge.createDefaultData();
        super.cleanAfterTest();
    }

    @Override
    protected void loadBeforeAction() {
        //action like restore, dump or populating data can be long, we ask to have a new token
        try {
            cfClientToPopulate = this.clientFactory.createCloudFoundryClient(cfAdminUser, cfAdminPassword,
                    cloudControllerUrl, org, space);
        } catch (MalformedURLException e) {
            //can't happens here
        }
        OAuth2AccessToken accessToken = cfClientToPopulate.login();
        this.requestForge.setUserToken(accessToken.getValue());
        this.requestForge.setOrg(org);
        this.requestForge.setSpace(space);
        super.loadBeforeAction();
    }

    @Override
    protected boolean isServerListening(DatabaseType databaseType) throws DatabaseExtractionException {
        DatabaseAccess databaseAccess = this.databaseAccessMap.get(databaseType);
        DatabaseRef sourceDatabase = null;
        DatabaseRef targetDatabase = null;
        try {
            sourceDatabase = this.databaseRefManager.getDatabaseRef(databaseAccess.getServiceSourceInstanceName(),
                    requestForge.getUserToken(), requestForge.getOrg(), requestForge.getSpace());
            targetDatabase = this.databaseRefManager.getDatabaseRef(databaseAccess.getServiceTargetInstanceName(),
                    requestForge.getUserToken(), requestForge.getOrg(), requestForge.getSpace());
        } catch (ServiceKeyException e) {
            throw new DatabaseExtractionException(e.getMessage(), e);
        }
        boolean result = this.isSocketOpen(sourceDatabase.getHost(), sourceDatabase.getPort())
                && this.isSocketOpen(targetDatabase.getHost(), targetDatabase.getPort());
        this.databaseRefManager.deleteServiceKey(sourceDatabase);
        this.databaseRefManager.deleteServiceKey(targetDatabase);
        return result;
    }

    @Override
    public void populateData(DatabaseType databaseType) throws DatabaseExtractionException,
            CannotFindDatabaseDumperException, IOException, InterruptedException {
        DatabaseAccess databaseAccess = this.databaseAccessMap.get(databaseType);
        File fakeData = databaseAccess.getFakeDataFile();
        if (fakeData == null) {
            fail("Cannot find file for database: " + databaseType);
            return;
        }
        DatabaseRef sourceDatabase = null;
        try {
            sourceDatabase = this.databaseRefManager.getDatabaseRef(databaseAccess.getServiceSourceInstanceName(),
                    requestForge.getUserToken(), requestForge.getOrg(), requestForge.getSpace());
        } catch (ServiceKeyException e) {
            throw new DatabaseExtractionException(e.getMessage(), e);
        }
        this.populateDataToDatabaseRefFromFile(fakeData, sourceDatabase);
        this.databaseRefManager.deleteServiceKey(sourceDatabase);
    }

    @Override
    protected void populateDatabaseAccessMap() throws DatabaseExtractionException {
        super.populateDatabaseAccessMap();
        DatabaseAccess mysqlAccess = this.databaseAccessMap.get(DatabaseType.MYSQL);
        mysqlAccess.setServiceName(serviceNameMysql);
        mysqlAccess.setServicePlan(servicePlanMysql);
        mysqlAccess.setServiceSourceInstanceName(this.generateServiceName(serviceSourceInstanceMysql));
        mysqlAccess.setServiceTargetInstanceName(this.generateServiceName(serviceTargetInstanceMysql));

        DatabaseAccess postgresAccess = this.databaseAccessMap.get(DatabaseType.POSTGRESQL);
        postgresAccess.setServiceName(serviceNamePostgres);
        postgresAccess.setServicePlan(servicePlanPostgres);
        postgresAccess.setServiceSourceInstanceName(this.generateServiceName(serviceSourceInstancePostgres));
        postgresAccess.setServiceTargetInstanceName(this.generateServiceName(serviceTargetInstancePostgres));

        DatabaseAccess mongoAccess = this.databaseAccessMap.get(DatabaseType.MONGODB);
        mongoAccess.setServiceName(serviceNameMongo);
        mongoAccess.setServicePlan(servicePlanMongo);
        mongoAccess.setServiceSourceInstanceName(this.generateServiceName(serviceSourceInstanceMongo));
        mongoAccess.setServiceTargetInstanceName(this.generateServiceName(serviceTargetInstanceMongo));

        DatabaseAccess redisAccess = this.databaseAccessMap.get(DatabaseType.REDIS);
        redisAccess.setServiceName(serviceNameRedis);
        redisAccess.setServicePlan(servicePlanRedis);
        String generatedSourceInstanceRedis = this.generateServiceName(serviceSourceInstanceRedis);
        redisAccess.setServiceSourceInstanceName(generatedSourceInstanceRedis);
        if (serviceNameRedis.equals("rediscloud")) {
            redisAccess.setServiceTargetInstanceName(generatedSourceInstanceRedis);
        } else {
            redisAccess.setServiceTargetInstanceName(this.generateServiceName(serviceTargetInstanceRedis));
        }

    }

    protected String generateServiceName(String serviceName) {
        String randomUUID = UUID.randomUUID().toString();
        randomUUID = randomUUID.replace("-", "");
        return serviceName + "-" + randomUUID.substring(0, 5);
    }

    protected void createService(CloudService cloudService) {
        try {
            logger.info("Creating service {} from {} with plan {} ", cloudService.getName(),
                    cloudService.getLabel(), cloudService.getPlan());
            cfClientToPopulate.createService(cloudService);
            if (!this.isFinishedCreatingService(cloudService)) {
                fail("Cannot create service '" + cloudService.getName() + "'");
            }
        } catch (HttpServerErrorException e) {
            if (!e.getStatusCode().equals(HttpStatus.BAD_GATEWAY)) {
                throw e;
            } else {
                String skipMessage = "Bad gateway error, skipping test";
                this.reportIntegration.setSkipped(true);
                this.reportIntegration.setSkippedReason(skipMessage);
                assumeTrue(skipMessage, false);
            }
        }

    }

    public boolean isFinishedCreatingService(CloudService cloudService) {

        ExecutorService executor = Executors.newCachedThreadPool();
        Callable<Boolean> task = () -> {
            while (true) {
                CloudService cloudServiceFound = cfClientToPopulate.getService(cloudService.getName());
                if (cloudServiceFound.getCloudServiceLastOperation() == null) {
                    return true;
                }
                logger.info("State for service '{}' : {}", cloudServiceFound,
                        cloudServiceFound.getCloudServiceLastOperation().getState());
                switch (cloudServiceFound.getCloudServiceLastOperation().getState()) {
                case "succeeded":
                    return true;
                case "in progress":
                    break;
                case "failed":
                case "internal error":
                    return false;
                }
                Thread.sleep(5000L);// we yield the task for 5seconds to let the service do is work (actually, Cloud Controller hit getServiceInstance every 30sec)
            }
        };
        Future<Boolean> future = executor.submit(task);
        try {
            Boolean result = future.get(timeoutCreatingService, TimeUnit.MINUTES);
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();
            future.cancel(true);
            fail("Timeout reached.", ex);
        }
        return false;
    }

    public boolean isServiceExist(String serviceName, String plan) {
        List<CloudServiceOffering> offeringList = cfClientToPopulate.getServiceOfferings();
        for (CloudServiceOffering offering : offeringList) {
            if (!offering.getName().equals(serviceName)) {
                continue;
            }
            for (CloudServicePlan servicePlan : offering.getCloudServicePlans()) {
                if (servicePlan.getName().equals(plan)) {

                    return true;
                }
            }
        }
        return false;
    }
}