blob: 8d9aad4ec75975d06f9421b6cf24804b45b62b8f [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 com.epam.dlab.automation.test;
import com.epam.dlab.automation.cloud.VirtualMachineStatusChecker;
import com.epam.dlab.automation.docker.Docker;
import com.epam.dlab.automation.helper.*;
import com.epam.dlab.automation.http.ApiPath;
import com.epam.dlab.automation.http.ContentType;
import com.epam.dlab.automation.http.HttpRequest;
import com.epam.dlab.automation.http.HttpStatusCode;
import com.epam.dlab.automation.jenkins.JenkinsService;
import com.epam.dlab.automation.model.Lib;
import com.epam.dlab.automation.model.LoginDto;
import com.epam.dlab.automation.model.NotebookConfig;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.response.Response;
import com.jayway.restassured.response.ResponseBody;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import static org.testng.Assert.fail;
@Test(singleThreaded = true)
public class TestServices {
private final static Logger LOGGER = LogManager.getLogger(TestServices.class);
// This time 3 notebooks are tested in parallel - so 3 threads are used,
// restartNotebookAndRedeployToTerminate are a pool for future notebooks grow.
// needed to investigate Amazon behaviour when same AIM requests set of
// computation resources in parallel
// looks like running test in 1 thread mostly succeeds, running in 2 and more
// threads - usually fails.
private static final int N_THREADS = 10;
private static final long NOTEBOOK_CREATION_DELAY = 60000;
private long testTimeMillis;
private List<NotebookConfig> notebookConfigs;
private List<Lib> skippedLibs;
@BeforeClass
public void Setup() throws IOException {
testTimeMillis = System.currentTimeMillis();
// Load properties
ConfigPropertyValue.getJenkinsJobURL();
ObjectMapper mapper = new ObjectMapper();
notebookConfigs = mapper.readValue(ConfigPropertyValue.getNotebookTemplates(),
new TypeReference<ArrayList<NotebookConfig>>() {
});
skippedLibs = mapper.readValue(ConfigPropertyValue.getSkippedLibs(),
new TypeReference<ArrayList<Lib>>() {
});
}
@AfterClass
public void Cleanup() {
testTimeMillis = System.currentTimeMillis() - testTimeMillis;
LOGGER.info("Test time {} ms", testTimeMillis);
}
@Test
public void runTest() throws Exception {
testJenkinsJob();
testLoginSsnService();
RestAssured.baseURI = NamingHelper.getSsnURL();
NamingHelper.setSsnToken(ssnLoginAndKeyUpload());
runTestsInNotebooks();
}
private void testJenkinsJob() throws Exception {
/*
* LOGGER.info("1. Jenkins Job will be started ...");
*
* JenkinsService jenkins = new
* JenkinsService(ConfigPropertyValue.getJenkinsUsername(),
* ConfigPropertyValue.getJenkinsPassword()); String buildNumber =
* jenkins.runJenkinsJob(ConfigPropertyValue.getJenkinsJobURL());
* LOGGER.info(" Jenkins Job has been completed");
*/
LOGGER.info("1. Looking for last Jenkins Job ...");
JenkinsService jenkins = new JenkinsService();
String buildNumber = jenkins.getJenkinsJob();
LOGGER.info(" Jenkins Job found:");
LOGGER.info("Build number is: {}", buildNumber);
NamingHelper.setSsnURL(jenkins.getSsnURL().replaceAll(" ", ""));
NamingHelper.setServiceBaseName(jenkins.getServiceBaseName().replaceAll(" ", ""));
Assert.assertNotNull(NamingHelper.getSsnURL(), "Jenkins URL was not generated");
Assert.assertNotNull(NamingHelper.getServiceBaseName(), "Service BaseName was not generated");
LOGGER.info("Self-Service URL is: " + NamingHelper.getSsnURL());
LOGGER.info("ServiceBaseName is: " + NamingHelper.getServiceBaseName());
}
private ResponseBody<?> login(String username, String password, int expectedStatusCode, String errorMessage) {
final String ssnLoginURL = NamingHelper.getSelfServiceURL(ApiPath.LOGIN);
LoginDto requestBody = new LoginDto(username, password);
Response response = new HttpRequest().webApiPost(ssnLoginURL, ContentType.JSON, requestBody);
LOGGER.info(" login response body for user {} is {}", username, response.getBody().asString());
Assert.assertEquals(response.statusCode(), expectedStatusCode, errorMessage);
return response.getBody();
}
private void testLoginSsnService() throws Exception {
String cloudProvider = ConfigPropertyValue.getCloudProvider();
LOGGER.info("Check status of SSN node on {}: {}", cloudProvider.toUpperCase(), NamingHelper.getSsnName());
String publicSsnIp = CloudHelper.getInstancePublicIP(NamingHelper.getSsnName(), true);
LOGGER.info("Public IP is: {}", publicSsnIp);
String privateSsnIp = CloudHelper.getInstancePrivateIP(NamingHelper.getSsnName(), true);
LOGGER.info("Private IP is: {}", privateSsnIp);
if (publicSsnIp == null || privateSsnIp == null) {
Assert.fail("There is not any virtual machine in " + cloudProvider + " with name " + NamingHelper.getSsnName());
return;
}
NamingHelper.setSsnIp(PropertiesResolver.DEV_MODE ? publicSsnIp : privateSsnIp);
VirtualMachineStatusChecker.checkIfRunning(NamingHelper.getSsnName(), true);
LOGGER.info("{} instance state is running", cloudProvider.toUpperCase());
LOGGER.info("2. Waiting for SSN service ...");
Assert.assertTrue(WaitForStatus.selfService(ConfigPropertyValue.getTimeoutSSNStartup()), "SSN service was " +
"not" +
" " +
"started");
LOGGER.info(" SSN service is available");
LOGGER.info("3. Check login");
final String ssnLoginURL = NamingHelper.getSelfServiceURL(ApiPath.LOGIN);
LOGGER.info(" SSN login URL is {}", ssnLoginURL);
ResponseBody<?> responseBody;
// TODO Choose username and password for this check
// if (!ConfigPropertyValue.isRunModeLocal()) {
// responseBody = login(ConfigPropertyValue.getNotIAMUsername(),
// ConfigPropertyValue.getNotIAMPassword(),
// HttpStatusCode.UNAUTHORIZED, "Unauthorized user " +
// ConfigPropertyValue.getNotIAMUsername());
// Assert.assertEquals(responseBody.asString(), "Please contact AWS
// administrator to create corresponding IAM User");
// }
responseBody = login(ConfigPropertyValue.getNotDLabUsername(), ConfigPropertyValue.getNotDLabPassword(),
HttpStatusCode.UNAUTHORIZED, "Unauthorized user " + ConfigPropertyValue.getNotDLabUsername());
Assert.assertEquals(responseBody.path("message"), "Username or password is invalid");
if (!ConfigPropertyValue.isRunModeLocal()) {
responseBody = login(ConfigPropertyValue.getUsername(), ".", HttpStatusCode.UNAUTHORIZED,
"Unauthorized user " + ConfigPropertyValue.getNotDLabUsername());
Assert.assertEquals(responseBody.path("message"), "Username or password is invalid");
}
LOGGER.info("Logging in with credentials {}/***", ConfigPropertyValue.getUsername());
responseBody = login(ConfigPropertyValue.getUsername(), ConfigPropertyValue.getPassword(), HttpStatusCode.OK,
"User login " + ConfigPropertyValue.getUsername() + " was not successful");
LOGGER.info("4. Check logout");
final String ssnlogoutURL = NamingHelper.getSelfServiceURL(ApiPath.LOGOUT);
LOGGER.info(" SSN logout URL is {}", ssnlogoutURL);
Response responseLogout = new HttpRequest().webApiPost(ssnlogoutURL, ContentType.ANY);
LOGGER.info("responseLogout.statusCode() is {}", responseLogout.statusCode());
Assert.assertEquals(responseLogout.statusCode(), HttpStatusCode.UNAUTHORIZED,
"User log out was not successful"/*
* Replace to HttpStatusCode.OK when EPMCBDCCSS-938 will be fixed
* and merged
*/);
}
private String ssnLoginAndKeyUpload() throws Exception {
LOGGER.info("5. Login as {} ...", ConfigPropertyValue.getUsername());
final String ssnLoginURL = NamingHelper.getSelfServiceURL(ApiPath.LOGIN);
final String ssnUploadKeyURL = NamingHelper.getSelfServiceURL(ApiPath.UPLOAD_KEY);
LOGGER.info(" SSN login URL is {}", ssnLoginURL);
LOGGER.info(" SSN upload key URL is {}", ssnUploadKeyURL);
ResponseBody<?> responseBody = login(ConfigPropertyValue.getUsername(), ConfigPropertyValue.getPassword(),
HttpStatusCode.OK, "Failed to login");
String token = responseBody.asString();
LOGGER.info(" Logged in. Obtained token: {}", token);
LOGGER.info("5.a Checking for user Key...");
Response respCheckKey = new HttpRequest().webApiGet(ssnUploadKeyURL, token);
if (respCheckKey.getStatusCode() == HttpStatusCode.NOT_FOUND) {
LOGGER.info("5.b Upload Key will be started ...");
Response respUploadKey = new HttpRequest().webApiPost(ssnUploadKeyURL, ContentType.FORMDATA, token);
LOGGER.info(" respUploadKey.getBody() is {}", respUploadKey.getBody().asString());
Assert.assertEquals(respUploadKey.statusCode(), HttpStatusCode.OK, "The key uploading was not successful");
int responseCodeAccessKey = WaitForStatus.uploadKey(ssnUploadKeyURL, token, HttpStatusCode.ACCEPTED,
ConfigPropertyValue.getTimeoutUploadKey());
LOGGER.info(" Upload Key has been completed");
LOGGER.info("responseAccessKey.statusCode() is {}", responseCodeAccessKey);
Assert.assertEquals(responseCodeAccessKey, HttpStatusCode.OK, "The key uploading was not successful");
} else if (respCheckKey.getStatusCode() == HttpStatusCode.OK) {
LOGGER.info(" Key has been uploaded already");
} else {
Assert.assertEquals(200, respCheckKey.getStatusCode(), "Failed to check User Key.");
}
final String nodePrefix = ConfigPropertyValue.getUsernameSimple();
Docker.checkDockerStatus(nodePrefix + "_create_edge_", NamingHelper.getSsnIp());
VirtualMachineStatusChecker.checkIfRunning(NamingHelper.getEdgeName(), true);
final String ssnExpEnvURL = NamingHelper.getSelfServiceURL(ApiPath.EXP_ENVIRONMENT);
LOGGER.info(" SSN exploratory environment URL is {}", ssnExpEnvURL);
final String ssnProUserResURL = NamingHelper.getSelfServiceURL(ApiPath.PROVISIONED_RES);
LOGGER.info(" SSN provisioned user resources URL is {}", ssnProUserResURL);
return token;
}
private void populateNotebookConfigWithSkippedLibs(NotebookConfig notebookCfg) {
if (Objects.isNull(notebookCfg.getSkippedLibraries())) {
notebookCfg.setSkippedLibraries(skippedLibs);
}
}
private void runTestsInNotebooks() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(
ConfigPropertyValue.getExecutionThreads() > 0 ? ConfigPropertyValue.getExecutionThreads() : N_THREADS);
notebookConfigs.forEach(this::populateNotebookConfigWithSkippedLibs);
List<FutureTask<Boolean>> futureTasks = new ArrayList<>();
if (CloudProvider.GCP_PROVIDER.equals(ConfigPropertyValue.getCloudProvider())) {
LOGGER.debug("Image creation tests are skipped for all types of notebooks in GCP.");
notebookConfigs.forEach(config -> config.setImageTestRequired(false));
}
LOGGER.info("Testing the following notebook configs: {}", notebookConfigs);
for (NotebookConfig notebookConfig : notebookConfigs) {
if (!ConfigPropertyValue.isRunModeLocal() &&
CloudProvider.AZURE_PROVIDER.equals(ConfigPropertyValue.getCloudProvider())) {
LOGGER.debug("Waiting " + NOTEBOOK_CREATION_DELAY / 1000 + " sec to start notebook creation...");
TimeUnit.SECONDS.sleep(NOTEBOOK_CREATION_DELAY / 1000);
}
FutureTask<Boolean> runScenarioTask = new FutureTask<>(new TestCallable(notebookConfig));
futureTasks.add(runScenarioTask);
executor.execute(runScenarioTask);
}
final long checkThreadTimeout = ConfigPropertyValue.isRunModeLocal() ? 1000 : 5000;
while (true) {
boolean done = allScenariosDone(futureTasks);
if (done) {
verifyResults(futureTasks);
executor.shutdown();
return;
} else {
TimeUnit.SECONDS.sleep(checkThreadTimeout / 1000);
}
}
}
private void verifyResults(List<FutureTask<Boolean>> futureTasks) {
List<Exception> resExceptions = new ArrayList<>();
for (FutureTask<Boolean> ft : futureTasks) {
try {
ft.get();
} catch (Exception exception) {
resExceptions.add(exception);
}
}
if (resExceptions.size() > 0) {
for (Exception exception : resExceptions) {
LOGGER.error("{} :\n {} ", exception, exception.getStackTrace());
exception.printStackTrace();
}
fail("There were failed tests with " + resExceptions.size() + " from " + futureTasks.size()
+ " notebooks, see stacktrace above.");
}
}
private boolean allScenariosDone(List<FutureTask<Boolean>> futureTasks) {
boolean done = true;
for (FutureTask<Boolean> ft : futureTasks) {
if (!ft.isDone()) {
done = ft.isDone();
}
}
return done;
}
}