| /* |
| * 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; |
| } |
| } |