Skip to content

Commit

Permalink
Merge branch 'master' into preflight-api
Browse files Browse the repository at this point in the history
  • Loading branch information
marques-work committed Dec 20, 2018
2 parents 2f050b9 + 62e1d11 commit 111d874
Show file tree
Hide file tree
Showing 34 changed files with 1,654 additions and 174 deletions.
27 changes: 27 additions & 0 deletions api/api-elastic-profile-operation-v1/build.gradle
@@ -0,0 +1,27 @@
/*
* Copyright 2018 ThoughtWorks, Inc.
*
* 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
*
* 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.
*/

apply plugin: 'jacoco'
apply plugin: 'groovy'

dependencies {
compile project(':api:api-base')

testCompile project(path: ':api:api-base', configuration: 'testOutput')

testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: project.versions.junit5
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: project.versions.junit5
}
@@ -0,0 +1,74 @@
/*
* Copyright 2018 ThoughtWorks, Inc.
*
* 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
*
* 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.thoughtworks.go.apiv1.elasticprofileoperation;

import com.thoughtworks.go.api.ApiController;
import com.thoughtworks.go.api.ApiVersion;
import com.thoughtworks.go.api.spring.ApiAuthenticationHelper;
import com.thoughtworks.go.apiv1.elasticprofileoperation.representers.ElasticProfileUsageRepresenter;
import com.thoughtworks.go.config.exceptions.RecordNotFoundException;
import com.thoughtworks.go.domain.ElasticProfileUsage;
import com.thoughtworks.go.server.service.ElasticProfileService;
import com.thoughtworks.go.spark.Routes;
import com.thoughtworks.go.spark.spring.SparkSpringController;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import spark.Request;
import spark.Response;

import java.util.Collection;

import static spark.Spark.*;

@Component
public class ElasticProfileOperationControllerV1 extends ApiController implements SparkSpringController {
private static final String PROFILE_ID_PARAM = "profile_id";
private ElasticProfileService elasticProfileService;
private final ApiAuthenticationHelper apiAuthenticationHelper;

@Autowired
public ElasticProfileOperationControllerV1(ElasticProfileService elasticProfileService, ApiAuthenticationHelper apiAuthenticationHelper) {
super(ApiVersion.v1);
this.elasticProfileService = elasticProfileService;
this.apiAuthenticationHelper = apiAuthenticationHelper;
}

@Override
public String controllerBasePath() {
return Routes.ElasticProfileAPI.INTERNAL_BASE;
}

@Override
public void setupRoutes() {
path(controllerBasePath(), () -> {
before("", this::setContentType);
before("/*", this::setContentType);
before("", mimeType, apiAuthenticationHelper::checkAdminUserOrGroupAdminUserAnd403);
before("/*", mimeType, apiAuthenticationHelper::checkAdminUserOrGroupAdminUserAnd403);

get(Routes.ElasticProfileAPI.ID + Routes.ElasticProfileAPI.USAGES, mimeType, this::usages);
exception(RecordNotFoundException.class, this::notFound);
});
}

public String usages(Request request, Response response) {
final String elasticProfileId = StringUtils.stripToEmpty(request.params(PROFILE_ID_PARAM));
final Collection<ElasticProfileUsage> jobsUsingElasticProfile = elasticProfileService.getUsageInformation(elasticProfileId);
return ElasticProfileUsageRepresenter.toJSON(jobsUsingElasticProfile);
}
}
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.thoughtworks.go.apiv1.elasticprofile.representers;
package com.thoughtworks.go.apiv1.elasticprofileoperation.representers;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
Expand Down
@@ -0,0 +1,118 @@
/*
* Copyright 2018 ThoughtWorks, Inc.
*
* 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
*
* 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.thoughtworks.go.apiv1.elasticprofileoperation

import com.thoughtworks.go.api.SecurityTestTrait
import com.thoughtworks.go.api.spring.ApiAuthenticationHelper
import com.thoughtworks.go.config.exceptions.RecordNotFoundException
import com.thoughtworks.go.domain.ElasticProfileUsage
import com.thoughtworks.go.server.service.ElasticProfileService
import com.thoughtworks.go.spark.ControllerTrait
import com.thoughtworks.go.spark.GroupAdminUserSecurity
import com.thoughtworks.go.spark.SecurityServiceTrait
import groovy.json.JsonBuilder
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.mockito.Mock

import static org.mockito.Mockito.when
import static org.mockito.MockitoAnnotations.initMocks

class ElasticProfileOperationControllerV1Test implements SecurityServiceTrait, ControllerTrait<ElasticProfileOperationControllerV1> {

@Mock
private ElasticProfileService elasticProfileService

@BeforeEach
void setup() {
initMocks(this)
}

@Override
ElasticProfileOperationControllerV1 createControllerInstance() {
new ElasticProfileOperationControllerV1(elasticProfileService, new ApiAuthenticationHelper(securityService, goConfigService))
}


@Nested
class Usages {
@Nested
class Security implements SecurityTestTrait, GroupAdminUserSecurity {

@Override
String getControllerMethodUnderTest() {
return "usages"
}

@Override
void makeHttpCall() {
getWithApiHeader(controller.controllerPath("/docker/usages"))
}
}

@Nested
class AsAGroupAdmin {

@BeforeEach
void setUp() {
enableSecurity()
loginAsGroupAdmin()
}

@Test
void 'should list jobs associated with a profile id'() {
def elasticProfileUsages = Arrays.asList(
new ElasticProfileUsage("LinuxPR", "build", "compile", "linux-pr"),
new ElasticProfileUsage("LinuxPR", "build", "test", "linux-pr"),

new ElasticProfileUsage("WindowsPR", "clean", "clean-dirs"),
new ElasticProfileUsage("WindowsPR", "clean", "clean-artifacts")
)

when(elasticProfileService.getUsageInformation("docker")).thenReturn(elasticProfileUsages)

getWithApiHeader(controller.controllerPath("/docker/usages"))

def expectedResponse = [
[pipeline_name: "LinuxPR", stage_name: "build", job_name: "compile", template_name: "linux-pr"],
[pipeline_name: "LinuxPR", stage_name: "build", job_name: "test", template_name: "linux-pr"],

[pipeline_name: "WindowsPR", stage_name: "clean", job_name: "clean-dirs"],
[pipeline_name: "WindowsPR", stage_name: "clean", job_name: "clean-artifacts"]
]

assertThatResponse()
.isOk()
.hasContentType(controller.mimeType)
.hasBodyWithJson(new JsonBuilder(expectedResponse).toString())
}

@Test
void 'should return 404 when profile with id does not exist'() {
when(elasticProfileService.getUsageInformation("docker")).thenThrow(new RecordNotFoundException("docker"))

getWithApiHeader(controller.controllerPath("/docker/usages"))

assertThatResponse()
.isNotFound()
.hasContentType(controller.mimeType)
.hasJsonMessage("Either the resource you requested was not found, or you are not authorized to perform this action.")
}
}
}
}
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.thoughtworks.go.apiv1.elasticprofile.representers
package com.thoughtworks.go.apiv1.elasticprofileoperation.representers

import com.thoughtworks.go.domain.ElasticProfileUsage
import org.junit.jupiter.api.Test
Expand Down
Expand Up @@ -23,12 +23,10 @@
import com.thoughtworks.go.api.spring.ApiAuthenticationHelper;
import com.thoughtworks.go.api.util.GsonTransformer;
import com.thoughtworks.go.apiv1.elasticprofile.representers.ElasticProfileRepresenter;
import com.thoughtworks.go.apiv1.elasticprofile.representers.ElasticProfileUsageRepresenter;
import com.thoughtworks.go.apiv1.elasticprofile.representers.ElasticProfilesRepresenter;
import com.thoughtworks.go.config.PluginProfiles;
import com.thoughtworks.go.config.elastic.ElasticProfile;
import com.thoughtworks.go.config.exceptions.RecordNotFoundException;
import com.thoughtworks.go.domain.ElasticProfileUsage;
import com.thoughtworks.go.server.service.ElasticProfileService;
import com.thoughtworks.go.server.service.EntityHashingService;
import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult;
Expand All @@ -41,7 +39,6 @@
import spark.Response;

import java.io.IOException;
import java.util.Collection;
import java.util.function.Consumer;

import static com.thoughtworks.go.api.util.HaltApiResponses.*;
Expand Down Expand Up @@ -78,7 +75,7 @@ public void setupRoutes() {

get("", mimeType, this::index);
get(Routes.ElasticProfileAPI.ID, mimeType, this::show);
get(Routes.ElasticProfileAPI.ID + Routes.ElasticProfileAPI.USAGES, mimeType, this::usages);

post("", mimeType, this::create);
put(Routes.ElasticProfileAPI.ID, mimeType, this::update);
delete(Routes.ElasticProfileAPI.ID, mimeType, this::destroy);
Expand Down Expand Up @@ -141,11 +138,6 @@ public String destroy(Request request, Response response) throws IOException {
return renderHTTPOperationResult(result, request, response);
}

public String usages(Request request, Response response) {
final String elasticProfileId = StringUtils.stripToEmpty(request.params(PROFILE_ID_PARAM));
final Collection<ElasticProfileUsage> jobsUsingElasticProfile = elasticProfileService.getUsageInformation(elasticProfileId);
return ElasticProfileUsageRepresenter.toJSON(jobsUsingElasticProfile);
}


private boolean isRenameAttempt(String profileIdFromRequestParam, String profileIdFromRequestBody) {
Expand Down
Expand Up @@ -23,8 +23,6 @@ import com.thoughtworks.go.apiv1.elasticprofile.representers.ElasticProfileRepre
import com.thoughtworks.go.apiv1.elasticprofile.representers.ElasticProfilesRepresenter
import com.thoughtworks.go.config.elastic.ElasticProfile
import com.thoughtworks.go.config.elastic.ElasticProfiles
import com.thoughtworks.go.config.exceptions.RecordNotFoundException
import com.thoughtworks.go.domain.ElasticProfileUsage
import com.thoughtworks.go.i18n.LocalizedMessage
import com.thoughtworks.go.server.domain.Username
import com.thoughtworks.go.server.service.ElasticProfileService
Expand Down Expand Up @@ -538,64 +536,4 @@ class ElasticProfileControllerV1Test implements SecurityServiceTrait, Controller
}
}
}

@Nested
class Usages {
@Nested
class Security implements SecurityTestTrait, GroupAdminUserSecurity {

@Override
String getControllerMethodUnderTest() {
return "usages"
}

@Override
void makeHttpCall() {
getWithApiHeader(controller.controllerPath("/docker/usages"))
}
}

@Nested
class AsAGroupAdmin {
@Test
void 'should list jobs associated with a profile id'() {
def elasticProfileUsages = Arrays.asList(
new ElasticProfileUsage("LinuxPR", "build", "compile", "linux-pr"),
new ElasticProfileUsage("LinuxPR", "build", "test", "linux-pr"),

new ElasticProfileUsage("WindowsPR", "clean", "clean-dirs"),
new ElasticProfileUsage("WindowsPR", "clean", "clean-artifacts")
)

when(elasticProfileService.getUsageInformation("docker")).thenReturn(elasticProfileUsages)

getWithApiHeader(controller.controllerPath("/docker/usages"))

def expectedResponse = [
[pipeline_name: "LinuxPR", stage_name: "build", job_name: "compile", template_name: "linux-pr"],
[pipeline_name: "LinuxPR", stage_name: "build", job_name: "test", template_name: "linux-pr"],

[pipeline_name: "WindowsPR", stage_name: "clean", job_name: "clean-dirs"],
[pipeline_name: "WindowsPR", stage_name: "clean", job_name: "clean-artifacts"]
]

assertThatResponse()
.isOk()
.hasContentType(controller.mimeType)
.hasBodyWithJson(new JsonBuilder(expectedResponse).toString())
}

@Test
void 'should return 404 when profile with id does not exist'() {
when(elasticProfileService.getUsageInformation("docker")).thenThrow(new RecordNotFoundException("docker"))

getWithApiHeader(controller.controllerPath("/docker/usages"))

assertThatResponse()
.isNotFound()
.hasContentType(controller.mimeType)
.hasJsonMessage("Either the resource you requested was not found, or you are not authorized to perform this action.")
}
}
}
}
6 changes: 3 additions & 3 deletions build.gradle
Expand Up @@ -110,12 +110,12 @@ List<String> partitionFiles(Collection originalFiles) {

def COPYRIGHT_YEAR = '2018'
def GO_VERSION_SEGMENTS = [
year : 18,
releaseInYear: 12,
year : 19,
releaseInYear: 1,
patch : 0
]
def GO_VERSION = [GO_VERSION_SEGMENTS.year, GO_VERSION_SEGMENTS.releaseInYear, GO_VERSION_SEGMENTS.patch].join('.')
def GO_VERSION_PREVIOUS = '18.11.0'
def GO_VERSION_PREVIOUS = '18.12.0'
def DIST_VERSION = releaseRevision()
def GIT_REVISION = gitRevision()

Expand Down

0 comments on commit 111d874

Please sign in to comment.