Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pipelines): add pipelineNameFilter to /{application}/pipelineConfigs endpoint #1839

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ List<Map> getApplicationHistory(

@GET("/pipelines/{app}")
List<Map> getPipelineConfigsForApplication(
@Path("app") String app, @Query("refresh") boolean refresh);
@Path("app") String app,
@Query("pipelineNameFilter") String pipelineNameFilter,
@Query("refresh") boolean refresh);

@GET("/pipelines/{app}/name/{name}")
Map getPipelineConfigByApplicationAndName(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,9 @@ class ApplicationController {

@ApiOperation(value = "Retrieve a list of an application's pipeline configurations", response = List.class)
@RequestMapping(value = "/{application}/pipelineConfigs", method = RequestMethod.GET)
List getPipelineConfigsForApplication(@PathVariable("application") String application) {
applicationService.getPipelineConfigsForApplication(application)
List getPipelineConfigsForApplication(@PathVariable("application") String application,
@RequestParam(required = false, value="pipelineNameFilter") String pipelineNameFilter) {
applicationService.getPipelineConfigsForApplication(application, pipelineNameFilter)
}

@ApiOperation(value = "Retrieve a pipeline configuration", response = HashMap.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ class PipelineController {
)
}

return front50Service.getPipelineConfigsForApplication((String) pipeline.get("application"), true)?.find {
return front50Service.getPipelineConfigsForApplication((String) pipeline.get("application"), null, true)?.find {
id == (String) it.get("id")
}
}
Expand Down Expand Up @@ -279,7 +279,7 @@ class PipelineController {
String pipelineName = pipelineMap.get("name");
String application = pipelineMap.get("application");

List<Map> pipelineConfigs = front50Service.getPipelineConfigsForApplication(application, true)
List<Map> pipelineConfigs = front50Service.getPipelineConfigsForApplication(application, null, true)

if (pipelineConfigs!=null && !pipelineConfigs.isEmpty()){
Optional<Map> filterResult = pipelineConfigs.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,11 @@ class ApplicationService {
}

List<Map> getPipelineConfigsForApplication(String app) {
return front50Service.getPipelineConfigsForApplication(app, true)
return getPipelineConfigsForApplication(app, null);
}

List<Map> getPipelineConfigsForApplication(String app, String pipelineNameFilter) {
return front50Service.getPipelineConfigsForApplication(app, pipelineNameFilter, true)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,24 @@

package com.netflix.spinnaker.gate.controllers

import com.fasterxml.jackson.databind.ObjectMapper
import com.netflix.spinnaker.gate.config.ApplicationConfigurationProperties
import com.netflix.spinnaker.gate.config.ServiceConfiguration
import com.netflix.spinnaker.gate.services.ApplicationService
import com.netflix.spinnaker.gate.services.internal.ClouddriverService
import com.netflix.spinnaker.gate.services.internal.ClouddriverServiceSelector
import com.netflix.spinnaker.gate.services.internal.Front50Service
import com.squareup.okhttp.mockwebserver.MockWebServer
import groovy.json.JsonSlurper
import org.springframework.http.MediaType
import org.springframework.mock.web.MockHttpServletResponse
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import org.springframework.web.util.NestedServletException
import spock.lang.Specification
import spock.lang.Unroll

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status

class ApplicationControllerSpec extends Specification {

Expand Down Expand Up @@ -62,9 +63,66 @@ class ApplicationControllerSpec extends Specification {
mockMvc = MockMvcBuilders.standaloneSetup(new ApplicationController(applicationService: applicationService)).build()
}

@Unroll
void 'should return configs for an application' (){
given: "random configs"
def configs = [
[
name: 'pipelineA',
some: 'some-random-x',
],
[
name: 'pipelineB',
some: 'some-random-F',
],
]

when: "all configs are requested"
def response = mockMvc.perform(get(endpoint)
.accept(MediaType.APPLICATION_JSON))

then: "we only call front50 once, and do not pass through the pipelineNameFilter"
1 * front50Service.getPipelineConfigsForApplication('true-app', null, true) >> configs
0 * front50Service._

and: "we get all configs"
response.andExpect status().isOk()
response.andExpect content().string(new ObjectMapper().writeValueAsString(configs))

where:
endpoint << ["/applications/true-app/pipelineConfigs"]
}

@Unroll
void 'should return configs for an application with pipelineNameFilter' (){
given: "only one config"
def configs = [
[
name: 'pipelineA',
some: 'some-random-x',
],
]

when: "configs are requested with a filter"
def response = mockMvc.perform(get(endpoint)
.accept(MediaType.APPLICATION_JSON))

then: "we only call front50 once, and we do pass through the pipelineNameFilter"
1 * front50Service.getPipelineConfigsForApplication('true-app', 'pipelineA', true) >> configs
0 * front50Service._

and: "only filtered configs are returned"
response.andExpect status().isOk()
response.andExpect content().string(new ObjectMapper().writeValueAsString(configs))

where:
endpoint << ["/applications/true-app/pipelineConfigs?pipelineNameFilter=pipelineA"]
}


@Unroll
void 'should return 200 with info on pipeline that exists with config' (){
given:
def configs = [
[
name: 'some-true-pipeline',
Expand All @@ -77,35 +135,34 @@ class ApplicationControllerSpec extends Specification {
someY: 'some-random-Z'
],
]
given:
1 * front50Service.getPipelineConfigsForApplication('true-app', true) >> configs
when:
MockHttpServletResponse response = mockMvc.perform(get(endpoint)
.accept(MediaType.APPLICATION_JSON)).andReturn().response
def response = mockMvc.perform(get(endpoint)
.accept(MediaType.APPLICATION_JSON))

then:
new JsonSlurper().parseText(response.contentAsString) == configs[0]
response.status == 200
1 * front50Service.getPipelineConfigsForApplication('true-app', null, true) >> configs
response.andExpect status().isOk()
response.andExpect content().string(new ObjectMapper().writeValueAsString(configs[0]))

where:
endpoint << ["/applications/true-app/pipelineConfigs/some-true-pipeline"]
}

@Unroll
void 'should return 404 on pipeline that does not exists' (){
given:
def configs = [
[
name: 'some-true-pipeline',
some: 'some-random-x',
someY: 'some-random-y'
]
]
given:
1 * front50Service.getPipelineConfigsForApplication('true-app', true) >> configs
when:
mockMvc.perform(get(endpoint))

then:
1 * front50Service.getPipelineConfigsForApplication('true-app', null, true) >> configs
NestedServletException ex = thrown()
ex.message.contains('Pipeline config (id: some-fake-pipeline) not found for Application (id: true-app)')

Expand All @@ -115,6 +172,7 @@ class ApplicationControllerSpec extends Specification {

@Unroll
void 'should return 200 with strategy configuration for strategy exists' (){
given:
def configs = [
[
name: 'some-true-strategy',
Expand All @@ -127,35 +185,34 @@ class ApplicationControllerSpec extends Specification {
someY: 'some-random-Z'
],
]
given:
1 * front50Service.getStrategyConfigs('true-app') >> configs
when:
MockHttpServletResponse response = mockMvc.perform(get(endpoint)
.accept(MediaType.APPLICATION_JSON)).andReturn().response
def response = mockMvc.perform(get(endpoint)
.accept(MediaType.APPLICATION_JSON))

then:
new JsonSlurper().parseText(response.contentAsString) == configs[0]
response.status == 200
1 * front50Service.getStrategyConfigs('true-app') >> configs
response.andExpect status().isOk()
response.andExpect content().string(new ObjectMapper().writeValueAsString(configs[0]))

where:
endpoint << ["/applications/true-app/strategyConfigs/some-true-strategy"]
}

@Unroll
void 'should return 404 with strategy configuration for strategy not exists' (){
given:
def configs = [
[
name: 'some-true-strategy',
some: 'some-random-x',
someY: 'some-random-y'
]
]
given:
1 * front50Service.getStrategyConfigs('true-app') >> configs
when:
mockMvc.perform(get(endpoint))

then:
1 * front50Service.getStrategyConfigs('true-app') >> configs
NestedServletException ex = thrown()
ex.message.contains('Strategy config (id: some-fake-strategy) not found for Application (id: true-app)')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class PipelineControllerSpec extends Specification {
]
]
]) >> { [id: 'task-id', application: 'application', status: 'SUCCEEDED'] }
1 * front50Service.getPipelineConfigsForApplication('application', true) >> []
1 * front50Service.getPipelineConfigsForApplication('application', null, true) >> []
}

def "should propagate pipeline template errors"() {
Expand Down