io.pravega.test.system.framework.RemoteSequential.java Source code

Java tutorial

Introduction

Here is the source code for io.pravega.test.system.framework.RemoteSequential.java

Source

/**
 * Copyright (c) 2017 Dell Inc., or its subsidiaries. All Rights Reserved.
 *
 * 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
 */
package io.pravega.test.system.framework;

import io.pravega.common.concurrent.FutureHelpers;
import io.pravega.test.system.framework.metronome.AuthEnabledMetronomeClient;
import io.pravega.test.system.framework.metronome.Metronome;
import io.pravega.test.system.framework.metronome.MetronomeException;
import io.pravega.test.system.framework.metronome.model.v1.Artifact;
import io.pravega.test.system.framework.metronome.model.v1.Job;
import io.pravega.test.system.framework.metronome.model.v1.Restart;
import io.pravega.test.system.framework.metronome.model.v1.Run;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.NotImplementedException;

import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import static io.netty.handler.codec.http.HttpResponseStatus.CREATED;

/**
 * Remote Sequential is TestExecutor which runs the test as Mesos Task.
 * This is used to execute tests sequentially.
 */
@Slf4j
public class RemoteSequential implements TestExecutor {
    private static final Metronome CLIENT = AuthEnabledMetronomeClient.getClient();
    private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);

    @Override
    public CompletableFuture<Void> startTestExecution(Method testMethod) {

        log.debug("Starting test execution for method: {}", testMethod);

        String className = testMethod.getDeclaringClass().getName();
        String methodName = testMethod.getName();
        String jobId = (methodName + ".testJob").toLowerCase(); //All jobIds should have lowercase for metronome.

        return CompletableFuture.runAsync(() -> {
            CLIENT.createJob(newJob(jobId, className, methodName));
            Response response = CLIENT.triggerJobRun(jobId);
            if (response.status() != CREATED.code()) {
                throw new TestFrameworkException(TestFrameworkException.Type.ConnectionFailed,
                        "Error while starting " + "test " + testMethod);
            }
        }).thenCompose(v2 -> waitForJobCompletion(jobId)).<Void>thenApply(v1 -> {
            if (CLIENT.getJob(jobId).getHistory().getFailureCount() != 0) {
                throw new AssertionError("Test failed, detailed logs can be found at "
                        + "https://MasterIP/mesos, under metronome framework tasks. MethodName: " + methodName);
            }
            return null;
        }).whenComplete((v, ex) -> {
            deleteJob(jobId); //deletejob once execution is complete.
            if (ex != null) {
                log.error("Error while executing the test. ClassName: {}, MethodName: {}", className, methodName);

            }
        });
    }

    @Override
    public CompletableFuture<Void> stopTestExecution(String testID) {
        throw new NotImplementedException("Stop Execution is not used for Remote sequential execution");
    }

    private CompletableFuture<Void> waitForJobCompletion(final String jobId) {
        return FutureHelpers.loop(() -> isTestRunning(jobId),
                () -> FutureHelpers.delayedFuture(Duration.ofSeconds(3), executorService), executorService);
    }

    private Job newJob(String id, String className, String methodName) {
        Map<String, String> labels = new HashMap<>(1);
        labels.put("testMethodName", methodName);

        //This can be used to set environment variables while executing the job on Metronome.
        Map<String, String> env = new HashMap<>(2);
        env.put("masterIP", System.getProperty("masterIP"));
        env.put("env2", "value102");

        Artifact art = new Artifact();
        art.setCache(false); // It caches the artifacts, disabling it for now.
        art.setExecutable(false); // jar is not executable.
        art.setExtract(false);
        art.setUri(System.getProperty("testArtifactUrl", "InvalidTestArtifactURL"));

        Restart restart = new Restart();
        restart.setActiveDeadlineSeconds(120); // the tests are expected to finish in 2 mins, this can be changed to
        // a higher value if required.
        restart.setPolicy("NEVER");

        Run run = new Run();
        run.setArtifacts(Collections.singletonList(art));

        run.setCmd("docker run --rm -v $(pwd):/data " + System.getProperty("dockerImageRegistry") + "/java:8 java"
                + " -DmasterIP=" + LoginClient.MESOS_MASTER + " -DskipServiceInstallation="
                + Utils.isSkipServiceInstallationEnabled() + " -cp /data/pravega-test-system-"
                + System.getProperty("testVersion") + ".jar io.pravega.test.system.SingleJUnitTestRunner "
                + className + "#" + methodName + " > server.log 2>&1" + "; exit $?");

        run.setCpus(0.5);
        run.setMem(64.0);
        run.setDisk(50.0);
        run.setEnv(env);
        run.setMaxLaunchDelay(3600);
        run.setRestart(restart);
        run.setUser("root");

        Job job = new Job();
        job.setId(id);
        job.setDescription(id);
        job.setLabels(labels);
        job.setRun(run);

        return job;
    }

    private boolean isTestRunning(String jobId) {
        Job jobStatus = CLIENT.getJob(jobId);
        boolean isRunning = false;
        if (jobStatus.getHistory() == null) {
            isRunning = true;
        } else if ((jobStatus.getHistory().getSuccessCount() == 0)
                && (jobStatus.getHistory().getFailureCount() == 0)) {
            isRunning = true;
        }
        return isRunning;
    }

    private void deleteJob(String jobId) {
        try {
            CLIENT.deleteJob(jobId);
        } catch (MetronomeException e) {
            throw new TestFrameworkException(TestFrameworkException.Type.RequestFailed,
                    "Error while deleting the " + "test run job", e);
        }
    }
}