<commit_before>/*
 * Copyright 2014 Netflix, 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.netflix.spinnaker.orca.kato.pipeline

import com.netflix.spinnaker.orca.Task
import com.netflix.spinnaker.orca.TaskResult
import com.netflix.spinnaker.orca.batch.StageStatusPropagationListener
import com.netflix.spinnaker.orca.batch.TaskTaskletAdapter
import com.netflix.spinnaker.orca.jackson.OrcaObjectMapper
import com.netflix.spinnaker.orca.oort.OortService
import com.netflix.spinnaker.orca.pipeline.model.Pipeline
import com.netflix.spinnaker.orca.pipeline.model.PipelineStage
import com.netflix.spinnaker.orca.pipeline.model.Stage
import com.netflix.spinnaker.orca.pipeline.persistence.DefaultExecutionRepository
import com.netflix.spinnaker.orca.pipeline.persistence.memory.InMemoryOrchestrationStore
import com.netflix.spinnaker.orca.pipeline.persistence.memory.InMemoryPipelineStore
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory
import org.springframework.batch.core.repository.JobRepository
import org.springframework.context.ApplicationContext
import org.springframework.transaction.PlatformTransactionManager
import retrofit.client.Response
import retrofit.mime.TypedInput
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Subject

class DeployStageSpec extends Specification {

  def configJson = """\
          {
            "type":"deploy",
            "cluster":{
                "strategy":"IMPLEMENTED_IN_SPEC",
                "application":"pond",
                "stack":"prestaging",
                "instanceType":"m3.medium",
                "securityGroups":[
                  "nf-infrastructure-vpc",
                  "nf-datacenter-vpc"
                ],
                "subnetType":"internal",
                "availabilityZones":{
                  "us-west-1":[

                  ]
                },
                "capacity":{
                  "min":1,
                  "max":1,
                  "desired":1
                },
                "loadBalancers":[
                  "pond-prestaging-frontend"
                ]
            },
            "account":"prod"
          }
  """.stripIndent()

  def mapper = new OrcaObjectMapper()
  def objectMapper = new OrcaObjectMapper()
  def pipelineStore = new InMemoryPipelineStore(objectMapper)
  def orchestrationStore = new InMemoryOrchestrationStore(objectMapper)
  def executionRepository = new DefaultExecutionRepository(orchestrationStore, pipelineStore)

  @Subject DeployStage deployStage

  @Shared OortService oortService
  @Shared DisableAsgStage disableAsgStage
  @Shared DestroyAsgStage destroyAsgStage

  def setup() {
    oortService = Mock(OortService)
    disableAsgStage = Mock(DisableAsgStage)
    destroyAsgStage = Mock(DestroyAsgStage)

    deployStage = new DeployStage(oort: oortService, disableAsgStage: disableAsgStage, destroyAsgStage: destroyAsgStage,
      mapper: mapper)
    deployStage.steps = new StepBuilderFactory(Stub(JobRepository), Stub(PlatformTransactionManager))
    deployStage.taskTaskletAdapter = new TaskTaskletAdapter(executionRepository)
    deployStage.stageStatusPropagationListener = new StageStatusPropagationListener(executionRepository)
    deployStage.applicationContext = Stub(ApplicationContext)
  }

  void "should create tasks of basicDeploy and disableAsg when strategy is redblack"() {
    setup:
    def pipeline = new Pipeline()
    def config = mapper.readValue(configJson, Map)
    config.cluster.strategy = "redblack"
    def stage = new PipelineStage(pipeline, config.remove("type") as String, config)
    def disableAsgTask = deployStage.buildStep("foo", TestTask)

    when:
    def steps = deployStage.buildSteps(stage)

    then:
    "should call to oort to get the last ASG so that we know what to disable"
    1 * oortService.getCluster(config.cluster.application, config.account, "pond-prestaging") >> {
      def cluster = [serverGroups: [[
                                      name  : "pond-prestaging-v000",
                                      region: "us-east-1"
                                    ]]]
      def typedInput = Stub(TypedInput)
      typedInput.in() >> new ByteArrayInputStream(mapper.writeValueAsString(cluster).bytes)
      def response = new Response("foo", 200, "ok", [], typedInput)
      response
    }
    1 * disableAsgStage.buildSteps(stage) >> [disableAsgTask]
    steps[-1] == disableAsgTask
  }

  void "should create tasks of basicDeploy and destroyAsg when strategy is highlander"() {
    setup:
    def pipeline = new Pipeline()
    def config = mapper.readValue(configJson, Map)
    config.cluster.strategy = "highlander"
    def stage = new PipelineStage(pipeline, config.remove("type") as String, config)
    def destroyAsgTask = deployStage.buildStep("foo", TestTask)

    when:
    def steps = deployStage.buildSteps(stage)

    then:
    "should call to oort to get the last ASG so that we know what to disable"
    stage.context.containsKey("destroyAsgDescriptions")
    1 == stage.context.destroyAsgDescriptions.size()
    1 * oortService.getCluster(config.cluster.application, config.account, "pond-prestaging") >> {
      def cluster = [serverGroups: [[
                                      name  : "pond-prestaging-v000",
                                      region: "us-east-1"
                                    ]]]
      def typedInput = Stub(TypedInput)
      typedInput.in() >> new ByteArrayInputStream(mapper.writeValueAsString(cluster).bytes)
      def response = new Response("foo", 200, "ok", [], typedInput)
      response
    }
    1 * destroyAsgStage.buildSteps(stage) >> [destroyAsgTask]
    steps[-1] == destroyAsgTask
  }

  void "should create basicDeploy tasks when no strategy is chosen"() {
    setup:
    def pipeline = new Pipeline()
    def config = mapper.readValue(configJson, Map)
    def stage = new PipelineStage(pipeline, config.remove("type") as String, config)

    when:
    def steps = deployStage.buildSteps(stage)

    then:
    steps*.name.collect {
      it.tokenize('.')[1]
    } == deployStage.basicSteps()*.name.collect { it.tokenize('.')[1] }
  }

  static class TestTask implements Task {

    @Override
    TaskResult execute(Stage stage) {
      return null
    }
  }
}
<commit_msg>replaced weird stub usage with simpler code<commit_after>/*
 * Copyright 2014 Netflix, 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.netflix.spinnaker.orca.kato.pipeline

import com.netflix.spinnaker.orca.Task
import com.netflix.spinnaker.orca.TaskResult
import com.netflix.spinnaker.orca.batch.StageStatusPropagationListener
import com.netflix.spinnaker.orca.batch.TaskTaskletAdapter
import com.netflix.spinnaker.orca.jackson.OrcaObjectMapper
import com.netflix.spinnaker.orca.oort.OortService
import com.netflix.spinnaker.orca.pipeline.model.Pipeline
import com.netflix.spinnaker.orca.pipeline.model.PipelineStage
import com.netflix.spinnaker.orca.pipeline.model.Stage
import com.netflix.spinnaker.orca.pipeline.persistence.DefaultExecutionRepository
import com.netflix.spinnaker.orca.pipeline.persistence.memory.InMemoryOrchestrationStore
import com.netflix.spinnaker.orca.pipeline.persistence.memory.InMemoryPipelineStore
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory
import org.springframework.batch.core.repository.JobRepository
import org.springframework.context.ApplicationContext
import org.springframework.transaction.PlatformTransactionManager
import retrofit.client.Response
import retrofit.mime.TypedByteArray
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Subject

class DeployStageSpec extends Specification {

  def configJson = """\
          {
            "type":"deploy",
            "cluster":{
                "strategy":"IMPLEMENTED_IN_SPEC",
                "application":"pond",
                "stack":"prestaging",
                "instanceType":"m3.medium",
                "securityGroups":[
                  "nf-infrastructure-vpc",
                  "nf-datacenter-vpc"
                ],
                "subnetType":"internal",
                "availabilityZones":{
                  "us-west-1":[

                  ]
                },
                "capacity":{
                  "min":1,
                  "max":1,
                  "desired":1
                },
                "loadBalancers":[
                  "pond-prestaging-frontend"
                ]
            },
            "account":"prod"
          }
  """.stripIndent()

  def mapper = new OrcaObjectMapper()
  def objectMapper = new OrcaObjectMapper()
  def pipelineStore = new InMemoryPipelineStore(objectMapper)
  def orchestrationStore = new InMemoryOrchestrationStore(objectMapper)
  def executionRepository = new DefaultExecutionRepository(orchestrationStore, pipelineStore)

  @Subject DeployStage deployStage

  @Shared OortService oortService
  @Shared DisableAsgStage disableAsgStage
  @Shared DestroyAsgStage destroyAsgStage

  def setup() {
    oortService = Mock(OortService)
    disableAsgStage = Mock(DisableAsgStage)
    destroyAsgStage = Mock(DestroyAsgStage)

    deployStage = new DeployStage(oort: oortService, disableAsgStage: disableAsgStage, destroyAsgStage: destroyAsgStage,
      mapper: mapper)
    deployStage.steps = new StepBuilderFactory(Stub(JobRepository), Stub(PlatformTransactionManager))
    deployStage.taskTaskletAdapter = new TaskTaskletAdapter(executionRepository)
    deployStage.stageStatusPropagationListener = new StageStatusPropagationListener(executionRepository)
    deployStage.applicationContext = Stub(ApplicationContext)
  }

  void "should create tasks of basicDeploy and disableAsg when strategy is redblack"() {
    setup:
    def pipeline = new Pipeline()
    def config = mapper.readValue(configJson, Map)
    config.cluster.strategy = "redblack"
    def stage = new PipelineStage(pipeline, config.remove("type") as String, config)
    def disableAsgTask = deployStage.buildStep("foo", TestTask)

    when:
    def steps = deployStage.buildSteps(stage)

    then:
    "should call to oort to get the last ASG so that we know what to disable"
    1 * oortService.getCluster(config.cluster.application, config.account, "pond-prestaging") >> {
      def cluster = [serverGroups: [[
                                      name  : "pond-prestaging-v000",
                                      region: "us-east-1"
                                    ]]]
      new Response(
          "foo", 200, "ok", [],
          new TypedByteArray(
              "application/json",
              objectMapper.writeValueAsBytes(cluster)
          )
      )
    }
    1 * disableAsgStage.buildSteps(stage) >> [disableAsgTask]
    steps[-1] == disableAsgTask
  }

  void "should create tasks of basicDeploy and destroyAsg when strategy is highlander"() {
    setup:
    def pipeline = new Pipeline()
    def config = mapper.readValue(configJson, Map)
    config.cluster.strategy = "highlander"
    def stage = new PipelineStage(pipeline, config.remove("type") as String, config)
    def destroyAsgTask = deployStage.buildStep("foo", TestTask)

    when:
    def steps = deployStage.buildSteps(stage)

    then:
    "should call to oort to get the last ASG so that we know what to disable"
    stage.context.containsKey("destroyAsgDescriptions")
    1 == stage.context.destroyAsgDescriptions.size()
    1 * oortService.getCluster(config.cluster.application, config.account, "pond-prestaging") >> {
      def cluster = [serverGroups: [[
                                      name  : "pond-prestaging-v000",
                                      region: "us-east-1"
                                    ]]]
      new Response(
          "foo", 200, "ok", [],
          new TypedByteArray(
              "application/json",
              objectMapper.writeValueAsBytes(cluster)
          )
      )
    }
    1 * destroyAsgStage.buildSteps(stage) >> [destroyAsgTask]
    steps[-1] == destroyAsgTask
  }

  void "should create basicDeploy tasks when no strategy is chosen"() {
    setup:
    def pipeline = new Pipeline()
    def config = mapper.readValue(configJson, Map)
    def stage = new PipelineStage(pipeline, config.remove("type") as String, config)

    when:
    def steps = deployStage.buildSteps(stage)

    then:
    steps*.name.collect {
      it.tokenize('.')[1]
    } == deployStage.basicSteps()*.name.collect { it.tokenize('.')[1] }
  }

  static class TestTask implements Task {

    @Override
    TaskResult execute(Stage stage) {
      return null
    }
  }
}

{'fraction_non_alphanumeric': 0.09402963180284582, 'fraction_numerical': 0.005280915358662168, 'mean_word_length': 2.846262341325811, 'pattern_counts': {'":': 32, '<': 3, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3114501', 'n_tokens_mistral': 3862, 'n_tokens_neox': 3768, 'n_words': 872}