CoolFace
Datasetpublic

GSaha567/seq_level_training_data

sourceHugging Faceupdated 8mo agoView on Hugging Face
0likes52downloads
shard_000013.csv90790 linesDownload Raw Back to root
1text,length,is_long_context,metric_val,label_metric2"== Step-by-step Cloud Foundry migration3 4=== Preview5https://docs.google.com/presentation/d/e/2PACX-1vSsEHn8cJfz8oWIwwUhdULt7nZzz3bBLK7OqM8UInkZ0LbQBCpPdhMoxsYGPe_90h9OvCu7dFlAimMJ/pub?start=false&loop=false&delayms=3000[Click here] to6check out the slides by https://twitter.com/ciberkleid[Cora Iberkleid] where she7migrates a setup of applications to be compliant with Spring Cloud Pipelines.8 9=== Introduction10 11This tutorial covers refactoring applications to comply with, and take advantage of, Spring Cloud Pipelines.12 13We will use a simple 3-tier application as an example:14 15image::{cf-migration-root-docs}/use_case_logical.png[title=""Use Case - Logical View""]16 17At the end of this tutorial, it will be possible to instantly create a Concourse pipeline for each app and run successfully through a full lifecycle, from source code commit to production deployment, following the lifecycle stages for testing and deployment recommended by Spring Cloud Pipelines. The app code bases will be improved with organized test coverage, a contract-based API, and a versioned database schema, enabling Spring Cloud Pipelines to carry out stubbed testing and to ensure backward compatibility for API and database schema changes.18 19=== Sample application - initial state20 21The sample application is implemented using Spring Boot apps for the UI and service tiers, and MySQL for the database.22 23The apps are built using Maven and pushed manually to Cloud Foundry. They leverage the three Pivotal Spring Cloud Services: Config Server, Service Discovery, and Circuit Breaker Dashboard. Rabbit is used to propagate Config Server refresh triggers.24 25The source code for the two Spring Boot apps is stored on GitHub, as is the backing repo for Config Server.26 27image::{cf-migration-root-docs}/use_case_implementation.png[title=""Use Case - Implementation""]28 29=== Sample application - end state30 31Through this tutorial, we will be adding Concourse and JFrog Bintray to manage the application lifecycle.32 33We will also be refactoring the application to comply with Spring Cloud Pipelines requirements and recommendations, including adding/organizing tests and introducing database versioning using Flyway and API contracts using Spring Cloud Contract.34 35=== Tutorial - toolset36 37* *GitHub* - sample app source code and config repositories,  a sample stubrunner app repository, and the Spring Cloud Pipelines code base38- https://github.com/ciberkleid/greeting-ui[greeting-ui]39- https://github.com/ciberkleid/fortune-service[fortune-service]40- https://github.com/ciberkleid/app-config[app-config]41- https://github.com/spring-cloud-samples/cloudfoundry-stub-runner-boot[cloudfoundry-stub-runner-boot]42- https://github.com/spring-cloud/spring-cloud-pipelines[spring-cloud-pipelines]43* *Pivotal Web Services* - public hosted Cloud Foundry offering http://run.pivotal.io[free trial accounts] and including MySQL, Rabbit, and Pivotal Spring Cloud Services in the Marketplace44* *Concourse*45* *JFrog Bintray* - public hosted Maven repository offering free https://bintray.com/signup/oss[OSS accounts]46* *Client Tools* - on your local machine, you will need an IDE as well as the mvn, git, cf, and fly (Concourse) CLIs47 48=== Tutorial - overview49 50The migration steps are broken down into three stages:51 52. *Scaffolding*53- Minimal refactoring to comply with basic Spring Cloud Pipelines requirements.54- At the end of this stage, each app will have a corresponding pipeline on Concourse. The pipelines will successfully build the apps, store the artifacts in Bintray, tag the GitHub repositories, and deploy the apps to Test, Stage, and Prod spaces in Cloud Foundry.55. *Tests*56- Add/organize tests to comply with Spring Cloud Pipelines recommendations. Incorporate flyway for database schema versioning and initial data loading.57- At the end of this stage, the pipelines will trigger unit and integration tests during the Build stage, smoke tests in the Test environment, and end-to-end tests in the Stage environment. The pipelines will also ensure backward compatibility for the database, such that you can safely roll back the backend service app, even after the database schema has been updated.58. *Contracts*59- Incorporate Spring Cloud Contract to define the API between the UI and service apps and auto-generate tests and stubs.60- At the end of this stage, the pipelines will catch breaking API changes during the Build stage and ensure backward compatibility for the API, such that you can safely roll back the backend service (producer) app, even after an API change.61 62=== Tutorial - step-by-step63 64==== Prep: Before you begin65 66If you want to simply review the migration steps explained below, you can look at the various branches in the https://github.com/ciberkleid/greeting-ui[greeting-ui] and https://github.com/ciberkleid/fortune-service[fortune-service] repositories - there is a branch representing the end-state of each stage:67 68image::{cf-migration-root-docs}/github_branches.png[title=""GitHub Branches""]69 70If you want to use this tutorial as a hands-on lab, fork each of the following repositories:71 72- https://github.com/ciberkleid/greeting-ui[greeting-ui]73- https://github.com/ciberkleid/fortune-service[fortune-service]74- https://github.com/ciberkleid/app-config[app-config]75 76Then, create a new directory on your local machine. You may name it anything you like; we will refer to it as `$SCP_HOME` throughout this tutorial.77 78In `$SCP_HOME`, clone your forks of `greeting-ui` and `fortune-service`, as well as the following two repositories:79 80- https://github.com/spring-cloud-samples/cloudfoundry-stub-runner-boot[cloudfoundry-stub-runner-boot]81- https://github.com/spring-cloud/spring-cloud-pipelines[spring-cloud-pipelines]82 83Finally, create a directory called `$SCP_HOME/credentials`. Leave it empty for now.84 85==== Stage 1: Scaffolding86 87In this stage, we make minimal changes to satisfy basic Spring Cloud Pipelines requirements so that the apps can run through the entire pipeline without error. We make ""scaffolding"" changes only - no code changes.88 89The steps in this stage must be completed for both `greeting-ui` and `fortune-service`.90 91===== 1.1 Create GitHub branches92 93```bash94git branch version95git checkout -b sc-pipelines96```97Branch *version* is required to exist, though it can be created as an empty branch. It is used by Spring Coud Pipelines to generate a version number for each new pipeline execution.98 99Branch *sc-pipelines* is optional and can be named anything you wish. The intention is for you to use it as a  working branch for the changes suggested in this tutorial (hence we create it and also check it out).100 101===== 1.2 Add Maven wrapper102 103```bash104mvn -N io.takari:maven:wrapper105```106This commands adds 4 files to a project:107 108[source,bash]109----110.111├── mvnw112├── mvnw.cmd113└── .mvn114    └── wrapper115        ├── maven-wrapper.jar116        └── maven-wrapper.properties117----118 119Make sure all four files are tracked by Git. For example, you can add the following to the `.gitignore` file:120```121#Exceptions122!/mvnw123!/mvnw.cmd124!/.mvn/wrapper/maven-wrapper.jar125!/.mvn/wrapper/maven-wrapper.properties126```127 128===== 1.3 Create Bintray maven repo package129 130We are using Bintray as the maven repository. Bintray requires that a package exist before any app artifacts can be uploaded.131 132Log into the Bintray UI and create the packages as follows. You can use the `Import from GitHub` option to create these:133 134image::{cf-migration-root-docs}/bintray_packages.png[title=""Bintray Packages""]135 136===== 1.4 Configure distribution management using Bintray maven repo137 138Edit the app `pom.xml` files as follows. Make sure the Bintray URLs match the URLs of the corresponding packages created in the previous step. The values you use will be different from the example shown below.139```xml140<properties>141...142<distribution.management.release.id>bintray</distribution.management.release.id>143<distribution.management.release.url>https://api.bintray.com/maven/ciberkleid/maven-repo/fortune-service</distribution.management.release.url>144</properties>145 146...147 148<distributionManagement>149<repository>150<id>${distribution.management.release.id}</id>151<url>${distribution.management.release.url}</url>152</repository>153</distributionManagement>154```155 156Though not required by Spring Cloud Pipelines, it makes sense to also configure your local maven settings with the credentials to your Bintray maven repo. To do so, edit your maven settings file, usually `~/.m2/settings.xml`. If the file does not exist, create it.157 158Note that the `id` must match the id specified in the previous step. Also, make sure to use your username and API token (not account password) instead of the sample values shown below.159```xml160<?xml version=""1.0"" encoding=""UTF-8""?>161<settings>162  <servers>163    <server>164      <id>bintray</id>165      <username>ciberkleid</username>166      <password>my-super-secret-api-token</password>167   </server>168 </servers>169</settings>170```171 172===== 1.5 Push changes to GitHub173 174Push the above changes to GitHub. You should be pushing the following to each of the two app repos:175 176* 4 new maven wrapper files177* a modified .gitignore file178* a modified pom.xml179 180===== 1.6 Add Spring Cloud Pipelines credentials file181In `$SCP_HOME/credentials`, make two copies of the file `$SCP_HOME/spring-cloud-pipelines/concourse/credentials-sample-cf.yml`. Rename them as `credentials-fortune-service.yml` and `credentials-greeting-ui.yml`.182 183CAUTION: These files will contain credentials to your GitHub repo, your Bintray repo, and your Cloud Foundry foundation. Hence, we opt to put them in a separate directory. You may choose to store these files in a private git repo, but do not push them to a public repo.184 185Edit the git properties of each credentials file. Make sure to replace the sample values shown below as appropriate. For `tools-branch`, you may opt to use a fixed release (use v1.0.0.M8 or later for Cloud Foundry). Leave other values as they are, we will update those in later steps.186```yml187app-url: git@github.com:ciberkleid/fortune-service.git188app-branch: sc-pipelines189tools-scripts-url: https://github.com/spring-cloud/spring-cloud-pipelines.git190tools-branch: master191build-options: """"192 193github-private-key: |194  -----BEGIN RSA PRIVATE KEY-----195  MIIJKQIBAAKCAgEAvwkL97vBllOSE39Wa5ppczT1cr5Blmkhadfoa1Va2/IBVyvk196  NJ9PqoTI+BahF2EgzweyiDSvKsstlTsG7QgiM9So8Voi2PlDOrXL6uOfCuAS/G8X197  ...198  -----END RSA PRIVATE KEY-----199git-email: ciberkleid@pivotal.io200git-name: Cora Iberkleid201```202 203Edit the maven repo properties of each credentials file. Make sure to replace the sample values shown below as appropriate. Bintray requires separate URLs for uploads and downloads. If you are using a different artifact repository, such as Artifactory or Nexus, and the repository URL is the same for uploads and downloads, then you do not need to set `repo-with-binaries-for-upload`.204```yml205m2-settings-repo-id: bintray206m2-settings-repo-username: ciberkleid207m2-settings-repo-password: my-super-secret-api-token208 209repo-with-binaries: https://ciberkleid:my-super-secret-api-token@dl.bintray.com/ciberkleid/maven-repo210 211repo-with-binaries-for-upload: https://api.bintray.com/maven/ciberkleid/maven-repo/fortune-service212```213===== 1.7 Set Concourse pipeline214 215At this point, all of the build jobs, which run on Concourse workers, will succeed.216 217To verify this, log in to your Concourse target and set the Concourse pipelines. Update the target name in the example below as appropriate.218 219```bash220# Set greeting-ui pipeline221fly -t myTarget set-pipeline -p greeting-ui -c ""${SCP_HOME}/spring-cloud-pipelines/concourse/pipeline.yml"" -l ""${SCP_HOME}/credentials/credentials-greeting-ui.yml"" -n222 223# Set fortune-service pipeline224fly -t myTarget set-pipeline -p fortune-service -c ""${SCP_HOME}/spring-cloud-pipelines/concourse/pipeline.yml"" -l ""${SCP_HOME}/credentials/credentials-fortune-service.yml"" -n225```226 227Log into the Concourse UI and unpause the pipelines. Start each. You should see that the build jobs all succeed.228 229image::{cf-migration-root-docs}/concourse_build_success.png[title=""Build Success""]230 231In addition, you will see a new dev/<version_number> tag in each GitHub repo, as well as the app jars uploaded into Bintray.232 233The test, stage, and prod jobs will fail because we have not yet added scaffolding for deployment to Cloud Foundry. We will do that next.234 235===== 1.8 Add Cloud Foundry manifest236 237If you are deploying to Cloud Foundry, you may already be routinely including manifest files with your apps. Our sample apps did not have manifest files, so we add them now.238 239In the `greeting-ui` repo, create a `manifest.yml` file as follows:240```yml241---242applications:243- name: greeting-ui244  timeout: 120245  services:246  - config-server247  - cloud-bus248  - service-registry249  - circuit-breaker-dashboard250  env:251    JAVA_OPTS: -Djava.security.egd=file:///dev/urandom252    TRUST_CERTS: api.run.pivotal.io253```254 255In the `fortune-service` repo, create a `manifest.yml` file as follows:256```yml257---258applications:259- name: fortune-service260  timeout: 120261  services:262  - fortune-db263  - config-server264  - cloud-bus265  - service-registry266  - circuit-breaker-dashboard267  env:268    JAVA_OPTS: -Djava.security.egd=file:///dev/urandom269    TRUST_CERTS: api.run.pivotal.io270```271 272The `TRUST_CERTS` variable is used by the Pivotal Spring Cloud Services (Config Server, Service Registry, and Circuit Breaker Dashboard), which we are using in this example. The value specified above assumes deployment to Pivotal Web Services. Update it accordingly if you are deploying to a different Cloud Foundry foundation, or you can leave it out altogether if you are replacing the Pivotal Spring Cloud Services with alternative implementations (e.g. deploying the services as apps and exposing them as user-provided services).273 274You may add additional values to the manifest files if you wish, for example if additional values are useful for any manual deployment you may still want to do, or desirable in your Spring Cloud Pipelines deployment. For example, an alternative manifest.yml for `fortune-service` could be as follows:275 276```yml277---278applications:279- name: fortune-service280  timeout: 120281  instances: 3282  memory: 1024M283  buildpack: https://github.com/cloudfoundry/java-buildpack.git284  random-route: true285  path: ./target/fortune-service-0.0.1-SNAPSHOT.jar286  services:287  - fortune-db288  - config-server289  - cloud-bus290  - service-registry291  - circuit-breaker-dashboard292  env:293    SPRING_PROFILES_ACTIVE: someProfile294    JAVA_OPTS: -Djava.security.egd=file:///dev/urandom295    TRUST_CERTS: api.run.pivotal.io296```297 298Note that `random-route` and `path` are ignored by Spring Cloud Pipelines. `instances` is honored in stage and prod, but overridden with a value of 1 for test.299 300===== 1.9 Add Spring Cloud Pipelines manifest301 302The Cloud Foundry manifest created in the previous step includes the logical names of the services to which the apps should be bound, but it does describe how the services can be provisioned. Hence, we add a second manifest file so that Spring Cloud Pipelines can provision the services.303 304Add a file called `sc-pipelines.yml` to each app, and include the same list of services as in the corresponding `manifest.yml`. Add the necessary details such that Spring Cloud Pipelines can construct a `cf create-service` command.305 306NOTE: The `type: broker' parameter shown below instructs Spring Cloud Pipelines to provision a service using `cf create-service'. Other service types are also supported: cups, syslog, route, app, and stubrunner.307 308More specifically, for `greeting-ui`, create an `sc-pipelines.yml` file with the following content:309 310```yml311test:312  services:313    - name: config-server314      type: broker315      broker: p-config-server316      plan: standard317      params:318        git:319          uri: https://github.com/ciberkleid/app-config320      useExisting: true321    - name: cloud-bus322      type: broker323      broker: cloudamqp324      plan: lemur325      useExisting: true326    - name: service-registry327      type: broker328      broker: p-service-registry329      plan: standard330      useExisting: true331    - name: circuit-breaker-dashboard332      type: broker333      broker: p-circuit-breaker-dashboard334      plan: standard335      useExisting: true336```337 338The `sc-pipelines.yml` file for `fortune-service` is similar, with the addition of the `fortune-db` service:339```yml340test:341  # list of required services342  services:343    - name: fortune-db344      type: broker345      broker: cleardb346      plan: spark347      useExisting: true348    - name: config-server349      type: broker350      broker: p-config-server351      plan: standard352      params:353        git:354          uri: https://github.com/ciberkleid/app-config355      useExisting: true356    - name: cloud-bus357      type: broker358      broker: cloudamqp359      plan: lemur360      useExisting: true361    - name: service-registry362      type: broker363      broker: p-service-registry364      plan: standard365      useExisting: true366    - name: circuit-breaker-dashboard367      type: broker368      broker: p-circuit-breaker-dashboard369      plan: standard370      useExisting: true371```372 373The values above assume deployment to Pivotal Web Services. If you are deploying to a different Cloud Foundry foundation, please update the values accordingly. Also, make sure to replace the `config-server` uri with the address of your fork of the https://github.com/ciberkleid/app-config[app-config] repo.374 375TIP: Notice the `useExisting: true` parameter above. By default, Spring Cloud Pipelines will delete and recreate services in the `test` space. To override this behavior and re-use existing services, we set `useExisting: true`. This is helpful in cases where services  may take time to provision and initialize, where there is no risk in re-using them between pipeline runs, or where it is desirable to retain the service instance from the last pipeline run (e.g. a database migration).376 377===== 1.10 Push changes to GitHub378 379Push the above changes to GitHub. You should be pushing the following to each of the two app repos:380 381* new app manifest file382* new sc-pipelines manifest file383 384===== 1.11 Create Cloud Foundry Orgs/Spaces385 386Spring Cloud Pipelines requires that the Cloud Foundry test, stage, and prod spaces exist before a pipeline is run. If you wish, you can use different foundations, orgs, and users for each. For simplicity, in this example, we use a single foundation (PWS), a single org, and a single user.387 388 389You can name the org(s) and spaces anything you like. Each app requires its own test space. The stage and prod spaces are shared.390 391For this example, create the following spaces:392```bash393cf create-space scp-test-greeting-ui394cf create-space scp-test-fortune-service395cf create-space scp-stage396cf create-space scp-prod397```398 399===== 1.12 Create Cloud Foundry stage and prod service instances400 401Spring Cloud Pipelines will dynamically create the services in the test spaces as per the `sc-pipelines.yml` file we created previously. Optionally, a second section can be added to the `sc-pipelines.yml` file for the stage environment, and these will be created dynamically as well. Prod services, however, must always be created manually.402 403For this example, we will create the stage and prod services manually.404 405Create the services listed in the app manifest files in both `scp-stage` and `scp-prod`.406 407===== 1.13 Update Spring Cloud Pipelines credentials file408Update the `greeting-ui` and `fortune-service` credentials files with Cloud Foundry information. Replace values in the example below as appropriate for your Cloud Foundry environment.409 410Notice that the test space name specified is a prefix, unlike the stage and prod space names, which are literals. Spring Cloud Pipelines will append the app name to the test space name, thereby matching the test space names we created manually. The stage and prod space names are not prefixes and will not be altered by Spring Cloud Pipelines.411 412Note also the `paas-hostname-uuid`. The value will be included in each route created. This value is optional, but it is useful in shared/multi-tenant environments such as PWS, as it helps ensure routes are unique. Change it to a unique uuid of your choosing.413 414```yml415pipeline-descriptor: sc-pipelines.yml416 417paas-type: cf418 419paas-hostname-uuid: cyi420 421# test values422paas-test-api-url: https://api.run.pivotal.io423paas-test-username: ciberkleid@pivotal.io424paas-test-password: secret425paas-test-org: S1Pdemo12426paas-test-space-prefix: scp-test427 428# stage values429paas-stage-api-url: https://api.run.pivotal.io430paas-stage-username: ciberkleid@pivotal.io431paas-stage-password: my-super-secret-password432paas-stage-org: S1Pdemo12433paas-stage-space: scp-stage434 435# prod values436paas-prod-api-url: https://api.run.pivotal.io437paas-prod-username: ciberkleid@pivotal.io438paas-prod-password: my-super-secret-password439paas-prod-org: S1Pdemo12440paas-prod-space: scp-prod441```442 443===== 1.14 Update Concourse pipeline with updated credentials files444 445Set the Concourse pipelines again, as we did previously, to update them with the values added to the credentials files. The test, stage, and prod jobs will all now succeed.446 447image::{cf-migration-root-docs}/concourse_test_stage_prod_success.png[title=""Test, Stage, & Prod Success""]448 449On Cloud Foundry, you will now see the apps deployed in the test, stage, and prod spaces. The image below shows the deployment of `fortune-service` to its dedicated test space. Notice that the 5 services declared in its manifest files (`sc-pipelines.yml` for provisioning, and `manifest.yml` for binding) have also been automatically provisioned. The image also shows the deployment of the same app to the shared prod space. Notice that the instance of the previous version has been renamed as *""venerable""* and stopped. If a rollback were deemed necessary, the `prod-rollback` job in the pipeline could be triggered to remove the currently running version, remove the `prod/<version_number>` tag from GitHub, and re-start the former (*""venerable""*) version.450 451image::{cf-migration-root-docs}/cf_test_and_prod_deployed.png[title=""Cloud Foundry Test and Prod Deployment""]452 453===== Stage 1 Recap & next steps454 455What have we accomplished?456 457* By adding the basic scaffolding needed to enable Spring Cloud Pipelines to manage the lifecycle of `greeting-ui` and `fortune-service` from source code commit to production deploy, we have made it possible for the app dev teams to instantly and easily create pipelines for each app using a common, standardized template458* We can count on the pipelines to:459- automatically provision services in test spaces, and optionally in stage as well460- dynamically clean up the test spaces between pipeline executions461- upload the app artifacts to the maven repo (e.g. Bintray)462- tag the git repositories with `dev/<version_number>` and `prod/<version_number>`463* After each successful pipeline run, we are in a position to roll back to the last deployed version using the `prod-rollback` job, if necessary464 465These accomplishments are extremely valuable, but in order to derive confidence and reliability from the pipelines, we need to incorporate testing. We do this in Stage 2 of the app migration.466 467==== Stage 2: Tests468 469In this stage, we enable Spring Cloud Pipelines to execute tests so that we can increase confidence in the code being deployed. We do so by adding test profiles to the pom.xml files, and then organizing and/or adding tests in a way that corresponds to the profiles. By doing so, we are establishing standards around testing across development teams in the enterprise.470 471We will also enable database schema versioning in this stage, thereby providing the foundation for rollback testing during schema changes.472 473===== 2.1 Add Maven profiles474 475For both `greeting-ui` and `fortune-service`, add a `profiles` section to the `pom.xml` file, as shown below. Note that we are adding four profiles:476 477* default478** For unit and integration tests. Note that this profile includes all tests except those that will explicitly be called by the smoke and e2e profiles.479** Tests matching this profile will be executed during the build-and-upload job480* apicompatibility481** For ensuring backward compatibility in case of API changes. Note that this is not effective until Stage 3, when we will add contracts. However, we add this profile now to ensure the api-compatibility-check job does not execute other tests.482* smoke483** For tests to be run against the app deployed in the test space.484* e2e485** For tests to be run against the app deployed in the stage space.486 487```xml488  <profiles>489    <profile>490      <id>default</id>491      <activation>492        <activeByDefault>true</activeByDefault>493      </activation>494      <build>495        <plugins>496          <plugin>497            <groupId>org.apache.maven.plugins</groupId>498            <artifactId>maven-surefire-plugin</artifactId>499            <configuration>500              <includes>501                <include>**/*Tests.java</include>502                <include>**/*Test.java</include>503              </includes>504              <excludes>505                <exclude>**/smoke/**</exclude>506                <exclude>**/e2e/**</exclude>507              </excludes>508            </configuration>509          </plugin>510          <plugin>511            <groupId>org.springframework.boot</groupId>512            <artifactId>spring-boot-maven-plugin</artifactId>513          </plugin>514        </plugins>515      </build>516    </profile>517    <profile>518      <id>apicompatibility</id>519      <build>520        <plugins>521          <plugin>522            <groupId>org.apache.maven.plugins</groupId>523            <artifactId>maven-surefire-plugin</artifactId>524            <configuration>525              <includes>526                <include>**/contracttests/**/*Tests.java</include>527                <include>**/contracttests/**/*Test.java</include>528              </includes>529            </configuration>530          </plugin>531        </plugins>532      </build>533    </profile>534    <profile>535      <id>smoke</id>536      <build>537        <plugins>538          <plugin>539            <groupId>org.apache.maven.plugins</groupId>540            <artifactId>maven-surefire-plugin</artifactId>541            <configuration>542              <includes>543                <include>smoke/**/*Tests.java</include>544                <include>smoke/**/*Test.java</include>545              </includes>546            </configuration>547          </plugin>548        </plugins>549      </build>550    </profile>551    <profile>552      <id>e2e</id>553      <build>554        <plugins>555          <plugin>556            <groupId>org.apache.maven.plugins</groupId>557            <artifactId>maven-surefire-plugin</artifactId>558            <configuration>559              <includes>560                <include>e2e/**/*Tests.java</include>561                <include>e2e/**/*Test.java</include>562              </includes>563            </configuration>564          </plugin>565        </plugins>566      </build>567    </profile>568  </profiles>569```570 571===== 2.2 Add/organize tests572 573Next, we ensure that we have a matching test package structure in our apps:574 575image::{cf-migration-root-docs}/test_package_structure.png[title=""Test Package Structure""]576 577Note that we are creating matching packages for the default, smoke, and e2e profiles only. We will address the package for the apicompatibility profile in Stage 3.578 579When working with your own apps, if you have existing tests, you would move the files into one of these packages now, and rename them so that they are included by the filters declared in the profiles (i.e. the file names end in `Test.java` or `Tests.java`)580 581In the case of our sample apps, there are no tests, so we add some now as follows.582 583*fortune-service default tests*584 585Add your unit and integration tests so that they match the default profile as defined in the `fortune-service` `pom.xml` file. These will be executed on Concourse against the `fortune-service` application running on the Concourse worker in the `build-and-upload` job.586 587As an example, we will add two tests, one that loads the context, and another that verifies the number of rows expected in the database:588 589```java590package io.pivotal;591 592import org.junit.Test;593import org.junit.runner.RunWith;594import org.springframework.beans.factory.annotation.Autowired;595import org.springframework.boot.test.context.SpringBootTest;596import org.springframework.test.context.junit4.SpringRunner;597 598import org.springframework.jdbc.core.JdbcTemplate;599import static org.assertj.core.api.Assertions.assertThat;600 601import static org.junit.Assert.*;602 603@RunWith(SpringRunner.class)604@SpringBootTest(classes = FortuneServiceApplication.class)605public class FortuneServiceApplicationTests {606 607    @Test608    public void contextLoads() throws Exception {609 610    }611 612    @Autowired613    private JdbcTemplate template;614 615    @Test616    public void testDefaultSettings() throws Exception {617        assertThat(this.template.queryForObject(""SELECT COUNT(*) from FORTUNE"",618                Integer.class)).isEqualTo(7);619    }620 621}622```623 624*fortune-service smoke tests*625 626Add your smoke tests so that they match the smoke profile as defined in the `fortune-service` `pom.xml` file. These will be executed on Concourse against the `fortune-service` application deployed in the Cloud Foundry `scp-test-fortune-service` space. Two versions of these tests are executed against the app:627 628. the current version, in the `test-smoke` job629. the latest prod version, in the `test-rollback-smoke` job630 631image::{cf-migration-root-docs}/fortune_service_smoke_tests.png[title=""fortune-service Smoke Tests""]632 633In the test environment, we choose to verify that `fortune-service` is retrieving a fortune from `fortune-db`, and not returning its Hystrix fallback response:634 635```java636package smoke;637 638import org.assertj.core.api.BDDAssertions;639import org.junit.Test;640import org.junit.runner.RunWith;641import org.springframework.beans.factory.annotation.Value;642import org.springframework.boot.autoconfigure.EnableAutoConfiguration;643import org.springframework.boot.test.context.SpringBootTest;644import org.springframework.http.ResponseEntity;645import org.springframework.test.context.junit4.SpringRunner;646import org.springframework.web.client.RestTemplate;647 648@RunWith(SpringRunner.class)649@SpringBootTest(classes = SmokeTests.class,650        webEnvironment = SpringBootTest.WebEnvironment.NONE)651@EnableAutoConfiguration652public class SmokeTests {653 654	@Value(""${application.url}"") String applicationUrl;655 656	RestTemplate restTemplate = new RestTemplate();657 658	@Test659	public void should_return_a_fortune() {660		ResponseEntity<String> response = this.restTemplate661				.getForEntity(""http://"" + this.applicationUrl + ""/"", String.class);662 663		BDDAssertions.then(response.getStatusCodeValue()).isEqualTo(200);664 665		// Filter out the known Hystrix fallback response666		BDDAssertions.then(response.getBody()).doesNotContain(""The fortuneteller will be back soon."");667	}668 669}670```671 672*fortune-service e2e tests*673 674Add your e2e tests so that they match the e2e profile as defined in the `fortune-service` `pom.xml` file. These will be executed on Concourse against the `fortune-service` application deployed in the Cloud Foundry `scp-stage` space. This space is shared, so we assume `greeting-ui` is also present.675 676image::{cf-migration-root-docs}/fortune_service_e2e_tests.png[title=""fortune-service E2E Tests""]677 678In the e2e environment, we choose to use a string replacement to obtain the URL for `greeting-ui`. We also choose to verify that we are hitting `fortune-db` and not receiving Hystrix fallback responses from either application:679 680```java681package e2e;682 683import org.assertj.core.api.BDDAssertions;684import org.junit.Test;685import org.junit.runner.RunWith;686import org.springframework.beans.factory.annotation.Value;687import org.springframework.boot.autoconfigure.EnableAutoConfiguration;688import org.springframework.boot.test.context.SpringBootTest;689import org.springframework.http.ResponseEntity;690import org.springframework.test.context.junit4.SpringRunner;691import org.springframework.web.client.RestTemplate;692 693@RunWith(SpringRunner.class)694@SpringBootTest(classes = E2eTests.class,695		webEnvironment = SpringBootTest.WebEnvironment.NONE)696@EnableAutoConfiguration697public class E2eTests {698 699	// The app is running in CF but the tests are executed from Concourse worker,700	// so the test will deduce the url to greeting-ui: it will assume the same host701	// as fortune-service, and simply replace ""fortune-service"" with ""greeting-ui"" in the url702 703	@Value(""${application.url}"") String applicationUrl;704 705	RestTemplate restTemplate = new RestTemplate();706 707	@Test708	public void should_return_a_fortune() {709		ResponseEntity<String> response = this.restTemplate710				.getForEntity(""http://"" + this.applicationUrl.replace(""fortune-service"", ""greeting-ui"") + ""/"", String.class);711 712		BDDAssertions.then(response.getStatusCodeValue()).isEqualTo(200);713 714		// Filter out the known Hystrix fallback responses from both fortune and greeting715		BDDAssertions.then(response.getBody()).doesNotContain(""This fortune is no good. Try another."").doesNotContain(""The fortuneteller will be back soon."");716	}717 718}719```720 721*greeting-ui default tests*722 723Add your unit and integration tests so that they match the default profile as defined in the `greeting-ui` `pom.xml` file. These will be executed on Concourse against the `greeting-ui` application running on the Concourse worker in the `build-and-upload` job.724 725As an example, we will add one test that loads the context:726 727```java728package io.pivotal;729 730import org.junit.Test;731import org.junit.runner.RunWith;732import org.springframework.boot.test.context.SpringBootTest;733import org.springframework.test.context.junit4.SpringRunner;734 735@RunWith(SpringRunner.class)736@SpringBootTest(classes = GreetingUIApplication.class)737public class GreetingUIApplicationTests {738 739    @Test740    public void contextLoads() throws Exception {741 742    }743 744}745```746 747*greeting-ui smoke tests*748 749Add your smoke tests so that they match the smoke profile as defined in the `greeting-ui` `pom.xml` file. These will be executed on Concourse against the `greeting-ui` application deployed in the Cloud Foundry `scp-test-greeting-ui` space. Two versions of these tests are executed against the app:750 751. the current version, in the `test-smoke` job752. the latest prod version, in the `test-rollback-smoke` job753 754image::{cf-migration-root-docs}/greeting_ui_smoke_tests.png[title=""greeting-ui Smoke Tests""]755 756Since `fortune-service` is not deployed to the `scp-test-greeting-ui` space, we expect to receive the Hystrix fallback response defined in `greeting-ui`. Hence, our smoke test validates that condition:757```java758package smoke;759 760import org.assertj.core.api.BDDAssertions;761import org.junit.Test;762import org.junit.runner.RunWith;763import org.springframework.beans.factory.annotation.Value;764import org.springframework.boot.autoconfigure.EnableAutoConfiguration;765import org.springframework.boot.test.context.SpringBootTest;766import org.springframework.http.ResponseEntity;767import org.springframework.test.context.junit4.SpringRunner;768import org.springframework.web.client.RestTemplate;769 770@RunWith(SpringRunner.class)771@SpringBootTest(classes = SmokeTests.class,772        webEnvironment = SpringBootTest.WebEnvironment.NONE)773@EnableAutoConfiguration774public class SmokeTests {775 776    @Value(""${application.url}"") String applicationUrl;777 778    RestTemplate restTemplate = new RestTemplate();779 780    @Test781    public void should_return_a_fallback_fortune() {782        ResponseEntity<String> response = this.restTemplate783                .getForEntity(""http://"" + this.applicationUrl + ""/"", String.class);784 785        BDDAssertions.then(response.getStatusCodeValue()).isEqualTo(200);786 787        // Expect the hystrix fallback response788        BDDAssertions.then(response.getBody()).contains(""This fortune is no good. Try another."");789    }790 791}792```793 794*greeting-ui e2e tests*795 796Add your e2e tests so that they match the e2e profile as defined in the `greeting-ui` `pom.xml` file. These will be executed on Concourse against the `greeting-ui` application deployed in the Cloud Foundry `scp-stage` space. This space is shared, so we assume `fortune-service` is also present.797 798image::{cf-migration-root-docs}/greeting_ui_e2e_tests.png[title=""greeting-ui E2E Tests""]799 800In the e2e environment, we choose to verify that we are hitting `fortune-service` and not receiving the Hystrix fallback response from `greeting-ui`:801 802```java803package e2e;804 805import org.assertj.core.api.BDDAssertions;806import org.junit.Test;807import org.junit.runner.RunWith;808import org.springframework.beans.factory.annotation.Value;809import org.springframework.boot.autoconfigure.EnableAutoConfiguration;810import org.springframework.boot.test.context.SpringBootTest;811import org.springframework.http.ResponseEntity;812import org.springframework.test.context.junit4.SpringRunner;813import org.springframework.web.client.RestTemplate;814 815@RunWith(SpringRunner.class)816@SpringBootTest(classes = E2eTests.class,817		webEnvironment = SpringBootTest.WebEnvironment.NONE)818@EnableAutoConfiguration819public class E2eTests {820 821	@Value(""${application.url}"") String applicationUrl;822 823	RestTemplate restTemplate = new RestTemplate();824 825	@Test826	public void should_return_a_fortune() {827		ResponseEntity<String> response = this.restTemplate828				.getForEntity(""http://"" + this.applicationUrl + ""/"", String.class);829 830		BDDAssertions.then(response.getStatusCodeValue()).isEqualTo(200);831 832		// Filter out the known Hystrix fallback response833		BDDAssertions.then(response.getBody()).doesNotContain(""This fortune is no good. Try another."");834	}835 836}837```838 839===== 2.3 Enable database versioning840 841At this point we will also incorporate https://flywaydb.org/[Flyway], an OSS database migration tool, to track database schema versions and handle schema changes and data loading.842 843This change only needs to be made to `fortune-service`, since `fortune-service` owns the interaction with `fortune-db`.844 845*Add Flyway dependency*846 847We first add the Flyway dependency to the `fortune-service` `pom.xml`. We need not add a version as Spring Boot will take care of that for us.848 849```xml850    <dependency>851      <groupId>org.flywaydb</groupId>852      <artifactId>flyway-core</artifactId>853    </dependency>854    <dependency>855```856 857*Create Flyway migration*858 859Next, we create a migration directory and our initial migration file following Flyway's file naming convention:860 861image::{cf-migration-root-docs}/fortune_service_flyway_file_name.png[title=""fortune-service Flyway File Name""]862 863Note the filename specifies the version (`V1`), followed by two underscore characters.864 865We place our CREATE TABLE and INSERT statements in our `src/main/resources/db/migration/V1__init.sql` file:866 867```sql868CREATE TABLE fortune (869  id BIGINT PRIMARY KEY AUTO_INCREMENT,870  text varchar(255) not null871);872 873INSERT INTO fortune (text) VALUES ('Do what works.');874 875INSERT INTO fortune (text) VALUES ('Do the right thing.');876 877INSERT INTO fortune (text) VALUES ('Always be kind.');878 879INSERT INTO fortune (text) VALUES ('You learn from your mistakes... You will learn a lot today.');880 881INSERT INTO fortune (text) VALUES ('You can always find happiness at work on Friday.');882 883INSERT INTO fortune (text) VALUES ('You will be hungry again in one hour.');884 885INSERT INTO fortune (text) VALUES ('Today will be an awesome day!');886```887*Disable JPA DDL initialization*888 889Now that we are relying on Flyway to create and populate the schema, we need to disable JPA-based database initialization. We can set `ddl-auto` to `validate`, which will validate the schema against the application entities and throw an error in case of a mismatch, but not actually generate the schema:890```yml891spring:892  jpa:893    hibernate:894      ddl-auto: validate895```896 897There are a few options for where to store the `ddl-auto` configuration, both in terms of location (in the `fortune-service` app or on the `app-config` GitHub repo) and in terms of file name. For this example, update the `application.yml` in the `fortune-service` app for local testing. Additionally, save these values in a new file called `application-flyway.yml` on your fork of https://github.com/ciberkleid/app-config[app-config].898 899By convention, `fortune-service` will pick up the configurations in `application-flyway.yml` if the string `flyway` is in the list of active Spring profiles. Thus, we add `flyway` to the environment variable `SPRING_PROFILES_ACTIVE` via the `fortune-service` `manifest.yml`:900 901```yml902---903applications:904- name: fortune-service905  timeout: 120906  services:907  - fortune-db908  - config-server909  - cloud-bus910  - service-registry911  - circuit-breaker-dashboard912  env:913    SPRING_PROFILES_ACTIVE: flyway914    JAVA_OPTS: -Djava.security.egd=file:///dev/urandom915    TRUST_CERTS: api.run.pivotal.io916```917*Remove non-Flyway data loading*918 919We can now remove the old code that populated the database. In our sample app, this was found in class `io.pivotal.FortuneServiceApplication`. The following shows the code we now remove:920 921```java922@Bean923    CommandLineRunner loadDatabase(FortuneRepository fortuneRepo) {924        return args -> {925//            logger.debug(""loading database.."");926//            fortuneRepo.save(new Fortune(1L, ""Do what works.""));927//            fortuneRepo.save(new Fortune(2L, ""Do the right thing.""));928//            fortuneRepo.save(new Fortune(3L, ""Always be kind.""));929//            fortuneRepo.save(new Fortune(4L, ""You learn from your mistakes... You will learn a lot today.""));930//            fortuneRepo.save(new Fortune(5L, ""You can always find happiness at work on Friday.""));931//            fortuneRepo.save(new Fortune(6L, ""You will be hungry again in one hour.""));932//            fortuneRepo.save(new Fortune(7L, ""Today will be an awesome day!""));933            logger.debug(""record count: {}"", fortuneRepo.count());934            fortuneRepo.findAll().forEach(x -> logger.debug(x.toString()));935        };936 937    }938```939 940We also no longer need the Fortune entity constructors, so we can comment these out in class `io.pivotal.fortune.Fortune` as shown below:941```java942//    public Fortune() {943//    }944//945//    public Fortune(Long id, String text) {946//        super();947//        this.id = id;948//        this.text = text;949//    }950```951 952*Flyway integration summary*953 954With that, we have completed the setup for Flyway and our database schema is now versioned. From this point onward, Spring Boot will call `Flyway.migrate()` to perform the database migration. As long as we follow Flyway conventions for future schema changes, Flyway will take care of tracking the schema version and migrating the database for us.955 956From a rollback perspective, Spring Cloud Pipelines includes two jobs in the `test` phase - `test-rollback-deploy` and `test-rollback-smoke` - wherein it validates that the latest prod jar works against the newly updated database. The purpose is to ensure that we can roll back the application in prod if a problem is discovered after the prod database schema has been updated, and avoid the burden of rolling back the database.957 958Read more about https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html#howto-use-a-higher-level-database-migration-tool[Spring Boot database initialization with Flyway] for further information, including Flyway configuration options.959 960===== 2.4 Push changes to GitHub961 962For `greeting-ui`, you should be pushing the following new or modified files:963 964* pom.xml965* src/test/java/e2e/E2eTests.java966* src/test/java/io/pivotal/GreetingUIApplicationTests.java967* src/test/java/smoke/SmokeTests.java968 969 970For `fortune-service`, you should be pushing the following new or modified files:971 972* pom.xml973* src/test/java/e2e/E2eTests.java974* src/test/java/io/pivotal/FortuneServiceApplicationTests.java975* src/test/java/smoke/SmokeTests.java976* src/main/resources/db/migration/V1__init.sql977* src/main/resources/application.yml978* manifest.yml979* src/main/java/io/pivotal/FortuneServiceApplication.java980* src/main/java/io/pivotal/fortune/Fortune.java981 982For `app-config`, you should be pushing the following new or modified files:983 984* application-flyway.yml985 986 987===== 2.5 Re-run the pipelines988 989Run through the pipelines again and view the output for the jobs that run the default, smoke, and e2e tests. You will see that the tests we added in this stage were executed.990 991As you run through the pipelines a second time, you will see the smoke tests from the latest prod version run against the database in the `test-rollback-smoke` job. In this case there is no schema upgrade, but nonetheless the tests confirm that the latest prod version of the app can be used with the current database schema.992 993You can see the database version information stored in the database by Flyway either by querying the database itself or by hitting the flyway endpoint on the `fortune-service` URL. Here is an example from the scp-stage environment:994 995image::{cf-migration-root-docs}/fortune_service_flyway_schema_info.png[title=""fortune-service Flyway Schema Info""]996 997===== Stage 2 Recap & next steps998 999What have we accomplished?1000 1001* By integrating our applications with the testing strategy built into Spring Cloud Pipelines, we have increased the effectiveness of the pipelines, as well as our confidence in them1002* Established a standard approach to organizing tests that will bring consistency within and across development teams1003* Enabled auto-managed database versioning and backward compatibility testing that will alleviate database schema management throughout the release management lifecycle1004 1005We are now positioned to add any unit, integration, smoke, and end-to-end tests to our code base and extract a very high level of reliability and confidence from our pipelines. We are also better positioned to ensure that our dev teams conform to these practices, given the structure established by Spring Cloud Pipelines and the fast feedback and visibility we gain from the pipelines as they execute the tests.1006 1007However, we could benefit further by incorporating contracts to define and test the API integration points between applications. We do this in Stage 3 of the app migration.1008 1009==== Stage 3: Contracts1010 1011In this stage, we introduce contract-based programming practices into our sample application. Doing so improves API management capabilities, including defining, communicating, and testing API semantics. It also enables us to catch breaking API changes (i.e. validate API backward compatibility) in the build phase. This will extend the effectiveness of the pipelines, encourage better communication and programming practices across development teams, and provide faster feedback to developers.1012 1013We will integrate Spring Cloud Contract and add contracts, stubs, and a stub runner. We will also now complete and make use of the apicompatibility profile defined in Stage 2.1014 1015===== 3.1 Create a contract1016 1017Let's start by creating the contract for the interaction between `greeting-ui` and `fortune-service`. The contract should describe the following expectation:1018 1019* `greeting-ui` makes a `GET` request to the root URL of `fortune-service` and expects a response with status 200 and a string (""foo fortune"") in the body1020 1021We codify this using groovy syntax as follows:1022 1023```groovy1024import org.springframework.cloud.contract.spec.Contract1025 1026Contract.make {1027    description(""""""1028should return a fortune string1029"""""")1030    request {1031        method GET()1032        url ""/""1033    }1034    response {1035        status 2001036        body ""foo fortune""1037    }1038}1039```1040 1041Save this contract in the `fortune-service` code base in the following location, which is compliant with Spring Cloud Contract convention (`src/test/resources/contracts/<service-name>/<contract-file>`):1042 1043image::{cf-migration-root-docs}/fortune_service_contract_file.png[title=""fortune-service Flyway Contract File""]1044 1045NOTE: You can optionally enable your IDE to assist with contract syntax by adding the Spring Cloud Contract Verifier to your `pom.xml` file. It is pluggable, and includes groovy and pact by default.1046 1047```xml1048    <dependency>1049      <groupId>org.springframework.cloud</groupId>1050      <artifactId>spring-cloud-starter-contract-verifier</artifactId>1051      <scope>test</scope>1052    </dependency>1053```1054 1055===== 3.2 Create a base class for contract tests1056 1057Now that we have a codified contract, we want to enable auto-generation of contract-based tests. The auto-generation, which we will configure in the next steps, requires a base class that stubs out the service that satisfies the API call, so that we can run the test without external dependencies (e.g. the DB). The objective is to focus on testing API semantics.1058 1059We create the base class in the `fortune-service` test package as follows:1060 1061 1062```java1063package io.pivotal.fortune;1064 1065import io.restassured.module.mockmvc.RestAssuredMockMvc;1066import org.junit.Before;1067import org.mockito.BDDMockito;1068 1069public class BaseClass {1070 1071    @Before1072    public void setup() {1073        FortuneService service = BDDMockito.mock(FortuneService.class);1074        BDDMockito.given(service.getFortune()).willReturn(""foo fortune"");1075        RestAssuredMockMvc.standaloneSetup(new FortuneController(service));1076    }1077}1078```1079 1080===== 3.3 Enable automated contract-based testing1081 1082Now that we have a contract and a base class, we can use the *Spring Cloud Contract maven plugin* to auto-generate contract tests, stubs, and a stub jar.1083 1084First we add the Spring Cloud Contract version to the list of properties in the `fortune-service` `pom.xml` file, since we will reference it when we enable the Spring Cloud Contract maven plugin:1085 1086```xml1087  <properties>1088...1089    <spring-cloud-contract.version>1.2.1.RELEASE</spring-cloud-contract.version>1090...1091</properties>1092```1093 1094Next, we edit the `default` profile in the `fortune-service` `pom.xml` file as follows:1095 1096* Add a plugin block for Spring Cloud Contract maven plugin1097* Configure it to use our base class (`io.pivotal.fortune.BaseClass`) to generate tests1098* Configure it to place auto-generated tests in the test package `io.pivotal.fortune.contracttests`1099 1100Note that the package of the contracttests will be included by the `include` filter in the `default` profile, so these tests will be run against the app during the `build-and-upload` job. For `fortune-service`, this serves to validate that the app conforms to the contract.1101 1102Here is the complete profile:1103```xml1104    <profile>1105      <id>default</id>1106      <activation>1107        <activeByDefault>true</activeByDefault>1108      </activation>1109      <build>1110        <plugins>1111          <plugin>1112            <groupId>org.apache.maven.plugins</groupId>1113            <artifactId>maven-surefire-plugin</artifactId>1114            <configuration>1115              <includes>1116                <include>**/*Tests.java</include>1117                <include>**/*Test.java</include>1118              </includes>1119              <excludes>1120                <exclude>**/smoke/**</exclude>1121                <exclude>**/e2e/**</exclude>1122              </excludes>1123            </configuration>1124          </plugin>1125          <plugin>1126            <groupId>org.springframework.boot</groupId>1127            <artifactId>spring-boot-maven-plugin</artifactId>1128          </plugin>1129          <!--Spring Cloud Contract maven plugin -->1130          <plugin>1131            <groupId>org.springframework.cloud</groupId>1132            <artifactId>spring-cloud-contract-maven-plugin</artifactId>1133            <version>${spring-cloud-contract.version}</version>1134            <extensions>true</extensions>1135            <configuration>1136              <baseClassForTests>io.pivotal.fortune.BaseClass</baseClassForTests>1137              <basePackageForTests>io.pivotal.fortune.contracttests</basePackageForTests>1138            </configuration>1139          </plugin>1140        </plugins>1141      </build>1142    </profile>1143```1144 1145When the app is built, the Spring Cloud Contract maven plugin will also now produce a stub and a stub jar containing the contract and stub. This stub jar will be uploaded to Bintray, along with the usual app jar. As we will see shortly, this stub jar can be used by the `greeting-ui` dev team while they wait for `fortune-service` to be completed. In other words, this gives the `greeting-ui` dev team a producer to test against that is based on a mutually agreed-upon contract without the lead time of having to wait for `fortune-service` to implement anything more than a base class, and without having to manually stub out calls to `fortune-service` based on arbitrary or static responses.1146 1147TIP: Package the project locally (run `mvn package`) to observe the tests, stubs, and stub jar that the Spring Cloud Contract maven plugin generates. See the image below for reference.1148 1149image::{cf-migration-root-docs}/fortune_service_generated_tests.png[title=""Generated Tests and Stubs""]1150 1151===== 3.4 Enable backward compatibility API check1152 1153To enable Spring Cloud Pipelines to catch any breaking API changes during the `build-api-compatibility-check` job, we add the Spring Cloud Contract maven plugin to the `apicompatibility` profile as well.1154 1155In this case, we want the plugin to generate tests based on contracts outside of the project (the ones from the latest prod version), so we configure the plugin to download the latest prod stub jar, which contains the old contract. The plugin will use the old contract and the specified base class, which in our example is the same as the one in the previous step, to generate contract tests. These tests are run against the new code to validate that it is still compatible with consumers complying with the prior contract. This ensures backward compatibility for the API.1156 1157In short, we edit the apicompatibility profile in the `fortune-service` `pom.xml` file as follows:1158 1159* Add a plugin block for Spring Cloud Contract maven plugin1160* Configure it to download the latest prod stub jar from Bintray to obtain the old contract1161* Configure it to use our base class (`io.pivotal.fortune.BaseClass`) to generate tests (we are using the same one as in the prior step)1162* Configure it to place auto-generated tests in the test package `io.pivotal.fortune.contracttests`1163 1164Note that the package of the contracttests matches the `include` filter in the `apicompatibility` profile, so these tests will be run against the app during the `build-api-compatibility-check` job. For `fortune-service`, this serves to validate that the app conforms to the old contract.1165 1166Here is the complete profile:1167 1168```xml1169    <profile>1170      <id>apicompatibility</id>1171      <build>1172        <plugins>1173          <plugin>1174            <groupId>org.apache.maven.plugins</groupId>1175            <artifactId>maven-surefire-plugin</artifactId>1176            <configuration>1177              <includes>1178                <include>**/contracttests/**/*Tests.java</include>1179                <include>**/contracttests/**/*Test.java</include>1180              </includes>1181            </configuration>1182          </plugin>1183          <!--Spring Cloud Contract maven plugin -->1184          <plugin>1185            <groupId>org.springframework.cloud</groupId>1186            <artifactId>spring-cloud-contract-maven-plugin</artifactId>1187            <version>${spring-cloud-contract.version}</version>1188            <extensions>true</extensions>1189            <configuration>1190              <contractsRepositoryUrl>${repo.with.binaries}</contractsRepositoryUrl>1191              <contractDependency>1192                <groupId>${project.groupId}</groupId>1193                <artifactId>${project.artifactId}</artifactId>1194                <classifier>stubs</classifier>1195                <version>${latest.production.version}</version>1196              </contractDependency>1197              <contractsPath>/</contractsPath>1198              <baseClassForTests>io.pivotal.fortune.BaseClass</baseClassForTests>1199              <basePackageForTests>io.pivotal.fortune.contracttests</basePackageForTests>1200            </configuration>

Showing the first 1,200 of 90790 lines. Download the file for the rest.