Skip to content

Latest commit

 

History

History
406 lines (292 loc) · 13.2 KB

hybrid-testing.md

File metadata and controls

406 lines (292 loc) · 13.2 KB
label synopsis permalink status uacp
Hybrid Testing
How to locally test your application with real cloud services.
advanced/hybrid-testing
released

Hybrid Testing { #hybrid-testing}

CAP enables you to run and test your CAP application using a local SQLite database and mocks to a large extent. However, you might want to test with actual cloud services at some point.

Hybrid testing capabilities help you stay in a local development environment and avoid long turnaround times of cloud deployments, by selectively connecting to services in the cloud.

Bind to Cloud Services

Services on Cloud Foundry

cds bind -2 bookshop-db

Binds your local CAP application to the service bookshop-db, using your currently targeted Cloud Foundry space. Here, bookshop-db is a managed service of type hana with plan hdi-shared.

::: tip cds bind automatically creates a service key for you If no service key for your service <srv> is specified, a <srv>-key is automatically created. :::

Got errors? See our troubleshooting for connection issues with SAP HANA Cloud.{.learn-more}

Output:

[bind] - Retrieving data from Cloud Foundry...
[bind] - Binding db to Cloud Foundry managed service bookshop-db:bookshop-db-key with kind hana.
[bind] - Saving bindings to .cdsrc-private.json in profile hybrid.
[bind] -
[bind] - TIP: Run with cloud bindings: cds watch --profile hybrid

For most commonly used services, CAP can automatically infer the service type and kind — in our example, the db CDS service is bound and set to the hana kind without additional parameters.

::: code-group

{
  "requires": {
    "[hybrid]": {
      "db": {
        "kind": "hana",
        "binding": {
          "type": "cf",
          "apiEndpoint": "https://api.sap.hana.ondemand.com",
          "org": "your-cf-org",
          "space": "your-cf-space",
          "instance": "bookshop-db",
          "key": "bookshop-db-key",
          "vcap": {
            "label": "hana",
            "plan": "hdi-shared"
          },
          "resolved": false
        }
      }
    }
  }
}

:::

Bindings are assigned to the hybrid profile by default.

::: tip No credentials are saved on-disk Only the information about where the credentials can be obtained is stored on your machine. :::

User-Provided Services on Cloud Foundry { #binding-user-provided-services}

cds bind my-ups -2 my-user-provided-service

Binds your local CAP application to the user provided service instance my-user-provided-service. The service name my-ups has to match the service name used in the CDS requires service configuration.

Output:

[bind] - Retrieving data from Cloud Foundry...
[bind] - Binding my-ups to Cloud Foundry user provided service my-user-provided-service.
[bind] - Saving bindings to .cdsrc-private.json in profile hybrid.
[bind] -
[bind] - TIP: Run with cloud bindings: cds watch --profile hybrid

cds watch --profile hybrid will automatically resolve user-provided service instance bindings using the same technique as for any other managed service binding.

Services on Kubernetes

You can bind to Service Bindings of Open Service Broker service instances, such as SAP BTP services, on your Kubernetes cluster and to plain Kubernetes Secrets by adding the --on k8s option to the cds bind command:

cds bind -2 ‹service binding or secret› --on k8s

The command uses your current Kubernetes context. That is your current server and namespace. You need to be logged in as a precondition.

Bind to Kubernetes Service Bindings

To list all Service Bindings in your current Kubernetes context, you can use the kubectl get servicebindings command:

NAME                   SERVICE-INSTANCE  SECRET-NAME           STATUS  AGE
bookshop-auth-binding  bookshop-auth     bookshop-auth-secret  Ready   11s

Use the service binding name for the -2 option:

cds bind -2 bookshop-auth-binding --on k8s

Output:

[bind] - Retrieving data from Kubernetes...
[bind] - Binding uaa to Kubernetes service binding bookshop-auth-binding with kind xsuaa
[bind] - Saving bindings to .cdsrc-private.json in profile hybrid
[bind] -
[bind] - TIP: Run with cloud bindings: cds watch --profile hybrid

The binding information is stored in the .cdsrc-private.json file of your project in the requires section:

::: code-group

{
  "requires": {
    "[hybrid]": {
      "auth": {
        "binding": {
          "type": "k8s",
          "name": "bookshop-auth-binding",
          "cluster": "https://apiserver.d9a6204.kyma-stage.shoot.live.k8s-hana.ondemand.com",
          "instance": "bookshop-auth",
          "namespace": "dev",
          "secret": "bookshop-auth-secret",
          "resolved": false,
          "vcap": {
            "label": "xsuaa",
            "plan": "application"
          }
        },
        "kind": "xsuaa"
      }
    }
  }
}

:::

Bind to Kubernetes Secrets

Alternatively, you can bind to Kubernetes Secrets.

You can use the kubectl get secrets command to list all secrets in your current Kubernetes context:

NAME                                    TYPE                                  DATA   AGE
bookshop-db                       Opaque                                11     44h

Use the secret name for the -2 option.

You need to provide either the service argument or the --kind option as well, because secrets have no service metadata.

cds bind -2 bookshop-db --on k8s --kind hana

Output:

[bind] - Retrieving data from Kubernetes...
[bind] - Binding db to Kubernetes secret bookshop-db with kind hana
[bind] - Saving bindings to .cdsrc-private.json in profile hybrid
[bind] -
[bind] - TIP: Run with cloud bindings: cds watch --profile hybrid

::: warning Service bindings take precedence If a service binding with the same name as the Kubernetes secret exists, cds bind will connect to the service binding instead. :::

Run with Service Bindings

Run CAP Node.js Apps with Service Bindings { #node}

Now, you can run your CAP service locally using the cloud service bindings:

cds watch --profile hybrid

It will resolve the cloud bindings in your configuration:

  1. Bindings to Cloud Foundry: The credentials are downloaded from the service key of the Cloud Foundry API endpoint, org, and space that were targeted when cds bind was called. This requires you to be logged in to the correct Cloud Foundry API endpoint.
  2. Bindings to Kubernetes: The credentials are downloaded from the service bindings and secrets of the Kubernetes cluster and namespace that were in the current context when cds bind was called.

You can also resolve and display credentials using the cds env command:

cds env get requires.db.credentials --profile hybrid --resolve-bindings

Example output:

{
  url: 'jdbc:sap://BDB9AC0F20CB46B494E6742047C4F99A.hana.eu10.hanacloud.ondemand.com:443?encrypt=true&validateCertificate=true&currentschema=BDB9AC0F20CB46B494E6742047C4F99A',
  host: 'bdb9ac0f20cb46b494e6742047c4f99a.hana.eu10.hanacloud.ondemand.com',
  port: '443',
  driver: 'com.sap.db.jdbc.Driver',
  schema: 'BDB9AC0F20CB46B494E6742047C4F99A',
  hdi_user: 'BDB9AC0F20CB46B494E6742047C4F99A_DT',
  hdi_password: 'abc...xyz',
  user: 'BDB9AC0F20CB46B494E6742047C4F99A_RT',
  password: 'abc....xyz',
  certificate: '-----BEGIN CERTIFICATE-----\n' +
    '...' +
    '-----END CERTIFICATE-----'
}

Run Arbitrary Commands with Service Bindings

With cds bind you avoid storing credentials on your hard disk. If you need to start other local applications with cloud service bindings, you can use the exec option.

For example, you can run the approuter from an approuter child directory:

::: code-group

cds bind --exec -- npm start --prefix approuter
cds bind --exec -- npm start --prefix approuter
cds bind --exec '--' npm start --prefix approuter

:::

This works by constructing a VCAP_SERVICES environment variable. You can output the content of this variable as follows:

::: code-group

cds bind --exec -- node -e 'console.log(process.env.VCAP_SERVICES)'
cds bind --exec -- node -e 'console.log(process.env.VCAP_SERVICES)'
cds bind --exec '--' node -e 'console.log(process.env.VCAP_SERVICES)'

:::

Run CAP Java Apps with Service Bindings

Start your CAP Java application with cds bind --exec to use remote service bindings:

cds bind --exec mvn spring-boot:run

Bindings from a Cloud Application

Instead of binding to specific cloud services, you can bind to all supported service bindings of an application running on the SAP BTP Cloud Foundry environment:

cds bind --to-app-services bookshop-srv

cds bind Usage { #cds-bind-usage}

By Cloud Service Only

The shortest way to use cds bind is to specify only the Cloud Foundry service instance name:

cds bind -2 bookshop-db

You can specify a different key after a colon (":"):

cds bind -2 bookshop-db:my-custom-key

With CDS Service and Kind

If kind or CDS service cannot be determined automatically by cds bind, you need to specify it:

cds bind credstore -2 my-credstore --kind credstore

You are informed with an error message if this is required.

Bind Multiple Services with One Command

There is a handy shortcut to bind multiple services with one command:

cds bind -2 my-hana,my-destination,my-xsuaa

::: tip This shortcut is only possible if you don't need to provide a service or a kind. :::

With Profile and Output File

By default, the bindings for the hybrid profile are stored in the .cdsrc-private.json file in your current working directory.

This can be overwritten using the --profile and --output-file options.

Execute Commands with Bindings { #cds-bind-exec}

You can start arbitrary command line programs with your bindings.

The service bindings are resolved from the cloud and provided in the VCAP_SERVICES env variable to the application. So it works with every application that can consume Cloud Foundry credentials.

cds bind --exec [--] <command> <args ...>

Use the double-dash (--) if your command has args starting with a dash (-) character. Otherwise the cds command line will try to parse them as their own options.

On PowerShell you need to quote the double dash (--) when an option with double dash follows, e.g.

cds bind --exec '--' somecmd --someflag --some-double-dash-parameter 42

Profiles can be set using the optional --profile parameter. By default the hybrid profile is used.

cds bind --exec --profile <profile> [--] <command> <args ...>

The --profile parameter must follow exec directly.

Use Cases

Most of the following use cases are shown for Node.js, but can be easily adapted for Java.

Destinations

Learn how to connect to remote services locally using SAP BTP destinations.

Authentication and Authorization using XSUAA

Learn how to do hybrid testing using the XSUAA service in the CAP Node.js authentication documentation.

Integration Tests

cds bind can be handy for testing with real cloud services in your CI/CD pipeline.

Configure your required bindings for testing and save them to your project's package.json file for your tests' profile:

cds bind -2 integration-test-hana -o package.json -p integration-test

No credentials are saved!

In your CI/CD pipeline you can resolve the bindings and inject them into the test commands:

# Install DK for "cds env"
npm i @sap/cds-dk --no-save

# Login
cf auth $USER $PASSWORD

## Uncomment if your service bindings have
## no "org" and "space" set (see note below)
# cf target -o $ORG -s $SPACE

# Set profile
export CDS_ENV=integration-test
# Set resolved bindings
export cds_requires="$(cds env get requires --resolve-bindings)"

# Execute test
npm run integration-test

With CDS_ENV, you specify the configuration profile for the test, where you previously put the service binding configuration.

cds env get requires prints the requires section of the configuration as a JSON string. By adding the --resolve-bindings option, it includes the credentials of the service bindings from the cloud. To make the credentials available for all subsequent cds commands and the tests, the requires JSON string is put into the cds_requires variable.

::: tip Service bindings created by cds bind contain the Cloud Foundry API endpoint, org, and space. You can allow your services to connect to the currently targeted Cloud Foundry org and space by removing these properties from the binding structure. :::