org.ligoj.app.plugin.prov.aws.ProvAwsTerraformServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for org.ligoj.app.plugin.prov.aws.ProvAwsTerraformServiceTest.java

Source

/*
 * Licensed under MIT (https://github.com/ligoj/ligoj/blob/master/LICENSE)
 */
package org.ligoj.app.plugin.prov.aws;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.IntStream;

import javax.transaction.Transactional;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.ligoj.app.AbstractServerTest;
import org.ligoj.app.dao.SubscriptionRepository;
import org.ligoj.app.model.Node;
import org.ligoj.app.model.Parameter;
import org.ligoj.app.model.ParameterValue;
import org.ligoj.app.model.Project;
import org.ligoj.app.model.Subscription;
import org.ligoj.app.plugin.prov.QuoteVo;
import org.ligoj.app.plugin.prov.model.ProvInstancePrice;
import org.ligoj.app.plugin.prov.model.ProvInstancePriceTerm;
import org.ligoj.app.plugin.prov.model.ProvInstanceType;
import org.ligoj.app.plugin.prov.model.ProvLocation;
import org.ligoj.app.plugin.prov.model.ProvQuote;
import org.ligoj.app.plugin.prov.model.ProvQuoteInstance;
import org.ligoj.app.plugin.prov.model.ProvQuoteStorage;
import org.ligoj.app.plugin.prov.model.ProvStoragePrice;
import org.ligoj.app.plugin.prov.model.ProvStorageType;
import org.ligoj.app.plugin.prov.model.VmOs;
import org.ligoj.app.plugin.prov.terraform.Context;
import org.ligoj.app.plugin.prov.terraform.TerraformUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

/**
 * Test class of {@link ProvAwsTerraformService}
 */
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "classpath:/META-INF/spring/application-context-test.xml")
@Rollback
@Transactional
public class ProvAwsTerraformServiceTest extends AbstractServerTest {
    private static final File MOCK_PATH = new File("target/test-classes/terraform-it").getAbsoluteFile();
    private static final File EXPECTED_PATH = new File("target/test-classes/terraform").getAbsoluteFile();

    @Autowired
    private SubscriptionRepository subscriptionRepository;

    private Subscription subscription;

    @AfterEach
    @BeforeEach
    public void cleanupFiles() throws IOException {
        FileUtils.deleteDirectory(MOCK_PATH);
        FileUtils.forceMkdir(MOCK_PATH);
    }

    @BeforeEach
    public void prepareData() throws IOException {
        persistSystemEntities();
        persistEntities("csv", new Class[] { Node.class, Project.class, Parameter.class, Subscription.class,
                ParameterValue.class }, StandardCharsets.UTF_8.name());
        subscription = subscriptionRepository.findBy("node.id", "service:prov:aws:test");
    }

    @Test
    public void writeSimpleCentos() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.CENTOS, null, 1, 1, 10, 8);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-centos.tf", "eu-west-3/vm-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-centos.tf").exists());
    }

    @Test
    public void writeSimpleAmz() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.LINUX, null, 1, 1, 10, 8);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-amazon.tf", "eu-west-3/vm-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
        assertEquals("dashboard-ec2.tf", "eu-west-3/dashboard.tf");
        assertEquals("dashboard-ec2-widgets.tpl.md", "eu-west-3/dashboard-widgets.tpl.md");
        assertEquals("dashboard-ec2-widgets.tpl.json", "eu-west-3/dashboard-widgets.tpl.json");
        assertTrue(new File(MOCK_PATH, "eu-west-3.keep.tf").exists());
    }

    @Test
    public void writeSimpleAmzRootOnly() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.LINUX, null, 1, 1, 10);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-amazon-1-device.tf", "eu-west-3/vm-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
    }

    @Test
    public void writeSimpleAmz3Devices() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.LINUX, null, 1, 1, 10, 11, 12);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-amazon-3-devices.tf", "eu-west-3/vm-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
    }

    @Test
    public void writeSimpleWindows() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.WINDOWS, null, 1, 1, 10, 8);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-windows.tf", "eu-west-3/vm-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-windows.tf").exists());
    }

    @Test
    public void writeSimpleRHEL() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.RHEL, null, 1, 1, 10, 8);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-rhel.tf", "eu-west-3/vm-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-rhel.tf").exists());
    }

    @Test
    public void writeSpotAmz() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.LINUX, 0.1, 1, 1, 10, 8);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-spot.tf", "eu-west-3/ephemeral-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
        assertEquals("dashboard-spot.tf", "eu-west-3/dashboard.tf");
        assertEquals("dashboard-spot-widgets.tpl.md", "eu-west-3/dashboard-widgets.tpl.md");
        assertEquals("dashboard-spot-widgets.tpl.json", "eu-west-3/dashboard-widgets.tpl.json");
    }

    @Test
    public void writeAutoScaling() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.LINUX, null, 1, 2, 10, 8);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-auto_scaling.tf", "eu-west-3/auto_scaling-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
    }

    @Test
    public void writeAutoScaling1Device() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.LINUX, null, 1, 2, 10);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-auto_scaling-1-device.tf", "eu-west-3/auto_scaling-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
    }

    @Test
    public void writeAutoScaling3Devices() throws IOException {
        final ProvQuoteInstance instance = newQuoteInstance("InstanceA", VmOs.LINUX, null, 1, 2, 10, 11, 12);
        write(subscription, newQuoteVo(instance));
        assertEquals("instance-auto_scaling-3-devices.tf", "eu-west-3/auto_scaling-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
    }

    @Test
    public void writeAutoScalingUnbound() throws IOException {
        final ProvQuoteInstance instanceA = newQuoteInstance("InstanceA", VmOs.LINUX, null, 2, null, 10, 8);
        write(subscription, newQuoteVo(instanceA));
        assertEquals("instance-auto_scaling-unbound.tf", "eu-west-3/auto_scaling-instancea.tf");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
    }

    @Test
    public void writeMutliple() throws IOException {
        final ProvQuoteInstance instanceA = newQuoteInstance("InstanceEC21", VmOs.LINUX, null, 1, 1, 10, 8);
        final ProvQuoteInstance instanceB = newQuoteInstance("InstanceEC22", VmOs.WINDOWS, null, 1, 1, 10, 8);
        final ProvQuoteInstance instanceC = newQuoteInstance("InstanceSpot1", VmOs.LINUX, 0.1, 1, 1, 10, 8);
        final ProvQuoteInstance instanceD = newQuoteInstance("InstanceSpot2", VmOs.WINDOWS, 0.1, 1, 1, 10, 8);
        final ProvQuoteInstance instanceE = newQuoteInstance("InstanceAS1", VmOs.LINUX, null, 1, 2, 10, 8);
        final ProvQuoteInstance instanceF = newQuoteInstance("InstanceAS2", VmOs.WINDOWS, null, 1, null, 10, 8);
        write(subscription, newQuoteVo(instanceA, instanceB, instanceC, instanceD, instanceE, instanceF));
        assertEquals("dashboard-multiple.tf", "eu-west-3/dashboard.tf");
        assertEquals("dashboard-multiple-widgets.tpl.md", "eu-west-3/dashboard-widgets.tpl.md");
        assertEquals("dashboard-multiple-widgets.tpl.json", "eu-west-3/dashboard-widgets.tpl.json");
        assertEquals("secrets.auto.tfvars", "secrets.auto.tfvars");
        assertTrue(new File(new File(MOCK_PATH, "eu-west-3"), "ami-amazon.tf").exists());
    }

    /**
     * Call Terraform generation and check the result is same as input file content
     *
     * @param subscription
     *            subscription
     * @param quoteVo
     *            quote
     */
    private void write(final Subscription subscription, final QuoteVo quoteVo) throws IOException {
        final Context context = new Context();
        context.setSubscription(subscription);
        context.setQuote(quoteVo);
        newProvAwsTerraformService().write(context);
    }

    /**
     * generate a quote instance for test purpose
     *
     * @param type
     *            instance type (Spot or OnDemand
     * @return quote instance
     */
    private ProvQuoteInstance newQuoteInstance(final String name, final VmOs os, final Double maxVariableCost,
            final int min, final Integer max, int... storages) {
        final ProvQuoteInstance quoteInstance = new ProvQuoteInstance();
        final ProvInstanceType instance = new ProvInstanceType();
        instance.setName("t2.micro");
        final ProvInstancePrice instancePrice = new ProvInstancePrice();
        instancePrice.setType(instance);
        instancePrice.setOs(os);
        final ProvInstancePriceTerm instancePriceType = new ProvInstancePriceTerm();
        instancePriceType.setName("some");
        instancePrice.setTerm(instancePriceType);
        quoteInstance.setPrice(instancePrice);
        quoteInstance.setId(1);
        quoteInstance.setName(name);
        quoteInstance.setMaxVariableCost(maxVariableCost);
        quoteInstance.setMinQuantity(min);
        quoteInstance.setMaxQuantity(max);
        quoteInstance.setOs(os);
        quoteInstance.setStorages(new ArrayList<>());
        IntStream.range(0, storages.length).forEach(idx -> {
            final ProvQuoteStorage storage = new ProvQuoteStorage();
            storage.setQuoteInstance(quoteInstance);
            ProvStoragePrice price = new ProvStoragePrice();
            ProvStorageType type = new ProvStorageType();
            type.setName("gp2");
            price.setType(type);
            storage.setPrice(price);
            storage.setName(name + "-storage-" + idx);
            storage.setSize(storages[idx]);
            quoteInstance.getStorages().add(storage);
        });

        return quoteInstance;
    }

    private ProvAwsTerraformService newProvAwsTerraformService() {
        final ProvAwsTerraformService resource = new ProvAwsTerraformService();
        applicationContext.getAutowireCapableBeanFactory().autowireBean(resource);
        resource.utils = new TerraformUtils() {

            @Override
            public File toFile(final Subscription subscription, final String... fragments) throws IOException {
                final File file = fragments.length == 0 ? MOCK_PATH
                        : new File(MOCK_PATH, String.join("/", fragments));
                FileUtils.forceMkdirParent(file);
                return file;
            }
        };
        return resource;
    }

    private void assertEquals(final String expected, final String generated) throws IOException {
        final File expected2 = new File(EXPECTED_PATH, expected).getAbsoluteFile();
        Assertions.assertTrue(expected2.exists());
        final File generatedFile = new File(MOCK_PATH, generated).getAbsoluteFile();
        Assertions.assertTrue(generatedFile.exists());
        Assertions.assertEquals(IOUtils.toString(expected2.toURI(), StandardCharsets.UTF_8),
                IOUtils.toString(generatedFile.toURI(), StandardCharsets.UTF_8));
    }

    private QuoteVo newQuoteVo(final ProvQuoteInstance... instances) {
        final QuoteVo quoteVo = new QuoteVo();
        final ProvLocation location = new ProvLocation();
        location.setName("eu-west-3");
        quoteVo.setInstances(Arrays.asList(instances));
        ProvQuote configuration = new ProvQuote();
        configuration.setLocation(location);
        Arrays.stream(instances).forEach(i -> {
            i.setConfiguration(configuration);
            i.getStorages().stream().forEach(s -> s.setConfiguration(configuration));
        });
        quoteVo.setLocation(location);
        return quoteVo;
    }
}