| /* |
| * 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 org.apache.hadoop.yarn.service; |
| |
| import static org.junit.Assert.*; |
| |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import javax.servlet.http.HttpServletRequest; |
| import javax.ws.rs.Path; |
| import javax.ws.rs.core.Response; |
| import javax.ws.rs.core.Response.Status; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.yarn.service.api.records.Artifact; |
| import org.apache.hadoop.yarn.service.api.records.Artifact.TypeEnum; |
| import org.apache.hadoop.yarn.service.api.records.Component; |
| import org.apache.hadoop.yarn.service.api.records.Resource; |
| import org.apache.hadoop.yarn.service.api.records.Service; |
| import org.apache.hadoop.yarn.service.api.records.ServiceState; |
| import org.apache.hadoop.yarn.service.api.records.ServiceStatus; |
| import org.apache.hadoop.yarn.service.client.ServiceClient; |
| import org.apache.hadoop.yarn.service.webapp.ApiServer; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.Mockito; |
| |
| /** |
| * Test case for ApiServer REST API. |
| * |
| */ |
| public class TestApiServer { |
| private ApiServer apiServer; |
| private HttpServletRequest request; |
| |
| @Before |
| public void setup() throws Exception { |
| request = Mockito.mock(HttpServletRequest.class); |
| Mockito.when(request.getRemoteUser()) |
| .thenReturn(System.getProperty("user.name")); |
| ServiceClient mockServerClient = new ServiceClientTest(); |
| Configuration conf = new Configuration(); |
| conf.set("yarn.api-service.service.client.class", |
| ServiceClientTest.class.getName()); |
| apiServer = new ApiServer(conf); |
| apiServer.setServiceClient(mockServerClient); |
| } |
| |
| @Test |
| public void testPathAnnotation() { |
| assertNotNull(this.apiServer.getClass().getAnnotation(Path.class)); |
| assertTrue("The controller has the annotation Path", |
| this.apiServer.getClass().isAnnotationPresent(Path.class)); |
| final Path path = this.apiServer.getClass() |
| .getAnnotation(Path.class); |
| assertEquals("The path has /v1 annotation", "/v1", path.value()); |
| } |
| |
| @Test |
| public void testGetVersion() { |
| final Response actual = apiServer.getVersion(); |
| assertEquals("Version number is", Response.ok().build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadCreateService() { |
| Service service = new Service(); |
| // Test for invalid argument |
| final Response actual = apiServer.createService(request, service); |
| assertEquals("Create service is ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testGoodCreateService() throws Exception { |
| String json = "{\"auths\": " |
| + "{\"https://index.docker.io/v1/\": " |
| + "{\"auth\": \"foobarbaz\"}," |
| + "\"registry.example.com\": " |
| + "{\"auth\": \"bazbarfoo\"}}}"; |
| File dockerTmpDir = new File("target", "docker-tmp"); |
| FileUtils.deleteQuietly(dockerTmpDir); |
| dockerTmpDir.mkdirs(); |
| String dockerConfig = dockerTmpDir + "/config.json"; |
| BufferedWriter bw = new BufferedWriter(new FileWriter(dockerConfig)); |
| bw.write(json); |
| bw.close(); |
| Service service = new Service(); |
| service.setName("jenkins"); |
| service.setVersion("v1"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<Component>(); |
| Component c = new Component(); |
| c.setName("jenkins"); |
| c.setNumberOfContainers(1L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| final Response actual = apiServer.createService(request, service); |
| assertEquals("Create service is ", |
| Response.status(Status.ACCEPTED).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testInternalServerErrorDockerClientConfigMissingCreateService() { |
| Service service = new Service(); |
| service.setName("jenkins"); |
| service.setVersion("v1"); |
| service.setDockerClientConfig("/does/not/exist/config.json"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<>(); |
| Component c = new Component(); |
| c.setName("jenkins"); |
| c.setNumberOfContainers(1L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| final Response actual = apiServer.createService(request, service); |
| assertEquals("Create service is ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadGetService() { |
| final Response actual = apiServer.getService(request, "no-jenkins"); |
| assertEquals("Get service is ", |
| Response.status(Status.NOT_FOUND).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadGetService2() { |
| final Response actual = apiServer.getService(request, null); |
| assertEquals("Get service is ", |
| Response.status(Status.NOT_FOUND).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testGoodGetService() { |
| final Response actual = apiServer.getService(request, "jenkins"); |
| assertEquals("Get service is ", |
| Response.status(Status.OK).build().getStatus(), actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadDeleteService() { |
| final Response actual = apiServer.deleteService(request, "no-jenkins"); |
| assertEquals("Delete service is ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadDeleteService2() { |
| final Response actual = apiServer.deleteService(request, null); |
| assertEquals("Delete service is ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadDeleteService3() { |
| final Response actual = apiServer.deleteService(request, |
| "jenkins-doesn't-exist"); |
| assertEquals("Delete service is ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadDeleteService4() { |
| final Response actual = apiServer.deleteService(request, |
| "jenkins-error-cleaning-registry"); |
| assertEquals("Delete service is ", |
| Response.status(Status.INTERNAL_SERVER_ERROR).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testGoodDeleteService() { |
| final Response actual = apiServer.deleteService(request, "jenkins"); |
| assertEquals("Delete service is ", |
| Response.status(Status.OK).build().getStatus(), actual.getStatus()); |
| } |
| |
| @Test |
| public void testDeleteStoppedService() { |
| final Response actual = apiServer.deleteService(request, |
| "jenkins-already-stopped"); |
| assertEquals("Delete service is ", |
| Response.status(Status.OK).build().getStatus(), actual.getStatus()); |
| } |
| |
| @Test |
| public void testDecreaseContainerAndStop() { |
| Service service = new Service(); |
| service.setState(ServiceState.STOPPED); |
| service.setName("jenkins"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<Component>(); |
| Component c = new Component(); |
| c.setName("jenkins"); |
| c.setNumberOfContainers(0L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| final Response actual = apiServer.updateService(request, "jenkins", |
| service); |
| assertEquals("update service is ", |
| Response.status(Status.OK).build().getStatus(), actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadDecreaseContainerAndStop() { |
| Service service = new Service(); |
| service.setState(ServiceState.STOPPED); |
| service.setName("no-jenkins"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<Component>(); |
| Component c = new Component(); |
| c.setName("no-jenkins"); |
| c.setNumberOfContainers(-1L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| System.out.println("before stop"); |
| final Response actual = apiServer.updateService(request, "no-jenkins", |
| service); |
| assertEquals("flex service is ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testIncreaseContainersAndStart() { |
| Service service = new Service(); |
| service.setState(ServiceState.STARTED); |
| service.setName("jenkins"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<Component>(); |
| Component c = new Component(); |
| c.setName("jenkins"); |
| c.setNumberOfContainers(2L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| final Response actual = apiServer.updateService(request, "jenkins", |
| service); |
| assertEquals("flex service is ", |
| Response.status(Status.OK).build().getStatus(), actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadStartServices() { |
| Service service = new Service(); |
| service.setState(ServiceState.STARTED); |
| service.setName("no-jenkins"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<Component>(); |
| Component c = new Component(); |
| c.setName("jenkins"); |
| c.setNumberOfContainers(2L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| final Response actual = apiServer.updateService(request, "no-jenkins", |
| service); |
| assertEquals("start service is ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testGoodStartServices() { |
| Service service = new Service(); |
| service.setState(ServiceState.STARTED); |
| service.setName("jenkins"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<Component>(); |
| Component c = new Component(); |
| c.setName("jenkins"); |
| c.setNumberOfContainers(2L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| final Response actual = apiServer.updateService(request, "jenkins", |
| service); |
| assertEquals("start service is ", |
| Response.status(Status.OK).build().getStatus(), actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadStopServices() { |
| Service service = new Service(); |
| service.setState(ServiceState.STOPPED); |
| service.setName("no-jenkins"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<Component>(); |
| Component c = new Component(); |
| c.setName("no-jenkins"); |
| c.setNumberOfContainers(-1L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| System.out.println("before stop"); |
| final Response actual = apiServer.updateService(request, "no-jenkins", |
| service); |
| assertEquals("stop service is ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| } |
| |
| @Test |
| public void testGoodStopServices() { |
| Service service = new Service(); |
| service.setState(ServiceState.STOPPED); |
| service.setName("jenkins"); |
| System.out.println("before stop"); |
| final Response actual = apiServer.updateService(request, "jenkins", |
| service); |
| assertEquals("stop service is ", |
| Response.status(Status.OK).build().getStatus(), actual.getStatus()); |
| } |
| |
| @Test |
| public void testBadSecondStopServices() throws Exception { |
| Service service = new Service(); |
| service.setState(ServiceState.STOPPED); |
| service.setName("jenkins-second-stop"); |
| // simulates stop on an already stopped service |
| System.out.println("before second stop"); |
| final Response actual = apiServer.updateService(request, |
| "jenkins-second-stop", service); |
| assertEquals("stop service should have thrown 400 Bad Request: ", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| ServiceStatus serviceStatus = (ServiceStatus) actual.getEntity(); |
| assertEquals("Stop service should have failed with service already stopped", |
| "Service jenkins-second-stop is already stopped", |
| serviceStatus.getDiagnostics()); |
| } |
| |
| @Test |
| public void testUpdateService() { |
| Service service = new Service(); |
| service.setState(ServiceState.STARTED); |
| service.setName("no-jenkins"); |
| Artifact artifact = new Artifact(); |
| artifact.setType(TypeEnum.DOCKER); |
| artifact.setId("jenkins:latest"); |
| Resource resource = new Resource(); |
| resource.setCpus(1); |
| resource.setMemory("2048"); |
| List<Component> components = new ArrayList<Component>(); |
| Component c = new Component(); |
| c.setName("no-jenkins"); |
| c.setNumberOfContainers(-1L); |
| c.setArtifact(artifact); |
| c.setLaunchCommand(""); |
| c.setResource(resource); |
| components.add(c); |
| service.setComponents(components); |
| System.out.println("before stop"); |
| final Response actual = apiServer.updateService(request, "no-jenkins", |
| service); |
| assertEquals("update service is ", |
| Response.status(Status.BAD_REQUEST) |
| .build().getStatus(), actual.getStatus()); |
| } |
| |
| @Test |
| public void testUpdateComponent() { |
| Response actual = apiServer.updateComponent(request, "jenkins", |
| "jenkins-master", null); |
| ServiceStatus serviceStatus = (ServiceStatus) actual.getEntity(); |
| assertEquals("Update component should have failed with 400 bad request", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| assertEquals("Update component should have failed with no data error", |
| "No component data provided", serviceStatus.getDiagnostics()); |
| |
| Component comp = new Component(); |
| actual = apiServer.updateComponent(request, "jenkins", "jenkins-master", |
| comp); |
| serviceStatus = (ServiceStatus) actual.getEntity(); |
| assertEquals("Update component should have failed with 400 bad request", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| assertEquals("Update component should have failed with no count error", |
| "No container count provided", serviceStatus.getDiagnostics()); |
| |
| comp.setNumberOfContainers(-1L); |
| actual = apiServer.updateComponent(request, "jenkins", "jenkins-master", |
| comp); |
| serviceStatus = (ServiceStatus) actual.getEntity(); |
| assertEquals("Update component should have failed with 400 bad request", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| assertEquals("Update component should have failed with no count error", |
| "Invalid number of containers specified -1", serviceStatus.getDiagnostics()); |
| |
| comp.setName("jenkins-slave"); |
| comp.setNumberOfContainers(1L); |
| actual = apiServer.updateComponent(request, "jenkins", "jenkins-master", |
| comp); |
| serviceStatus = (ServiceStatus) actual.getEntity(); |
| assertEquals("Update component should have failed with 400 bad request", |
| Response.status(Status.BAD_REQUEST).build().getStatus(), |
| actual.getStatus()); |
| assertEquals( |
| "Update component should have failed with component name mismatch " |
| + "error", |
| "Component name in the request object (jenkins-slave) does not match " |
| + "that in the URI path (jenkins-master)", |
| serviceStatus.getDiagnostics()); |
| } |
| } |