Executing from Cucumber

Cucumber is the most common behavior-driven development language for testers. This perfectly dovetails with the capabilities of API Fortress, as both are focused on making testing more intelligent and powerful without adding complication. The Cucumber tool, combined with API Fortress, is a great method of creating smart tests easily.

With the flexibility of the API Fortress, you can easily invoke API Fortress tests within your Cucumber Automation Scripts. Simply make an HTTP request to our webhook to kick off a test from your Cucumber test. Have a link to the report printed out into your console, or print the results directly on the console.

Below, we will show you how to easily integrate an API test into your Cucumber scripts.

You can find an example script on out Github.

First lets walk through the files and method used in the example:

  1. config.jsonThis is where you fill configure your API Fortress Project names and their associated webhooks. This allows you to invoke the tests by simply passing the Project name in the feature file.
  2. apifun.featureThis is where you define the scenario and the steps using the Gherkin syntax. In this file you will define the Given, When, Then steps. In this example we pass in an API Fortress Project name in the “Given” step.
  3. Stepdefs.javaIn this example we are using Java, however Cucumber supports many programming languages. The example file contains a few things:
    1. Stepdefs class
      1. In this class you will define what happens in each step from your feature file (Given, When, Then)
      2. Given – will take in the inputed Api Fortress Project name and call the getProjInfo method to get the webhook for this project
      3. When – will take the url of the webhook and call the callAPI method running all the API Fortress tests contained within that project
      4. Then – will parse through the response of the API Fortress webhook to provide the amount of failures, links to the API Fortress test results, and will indicate which tests passed and which failed
    2. getProjInfo methodThis method will parse the config.json file and match the Project name provided in the Given step to the Project name defined in the config file. This method will then return the associated webhook.
    3. callAPI methodThis method will take the webhook url from the When step and make a call to the API running all API Fortress tests within that project. This method will return the response from the API.

Disable SSL Validation

To disable the SSL validation in the downloader do the following steps:

We will assume you’re using a docker-compose based deployment, if you are not please reach out to support.
– First access the machine that runs the downloader service (likely the one that runs the rest of API Fortress as well)
– Then navigate to the “downloader/” directory
– Stop the downloader by issuing:
sudo docker-compose stop
– Next edit the “docker-compose.yml” file
– In the “environment” section, add the following entry (mind the annoying YAML format):
disable_ssl_validation: ‘true’
– Save and exit the file
– Now restart the downloader by issuing:
sudo docker-compose up -d
This downloader will now ignore invalid and not matching certificates.

Automating 3-Legged OAuth

Does your API require 3-leg authentication? Well with the help of a small helper container you can achieve automation of 3-leg using the API Fortress platform. Thanks to the helper, your local machine can help in the automation of your tests logging in using 3-leg auths such as Facebook, Twitter, and Google.

First let’s deploy the helper container, which can be found at the below link:
https://github.com/apifortress/3loa

Once you have the 3loa folder downloaded, navigate to that folder within a terminal window. Then run the following command to start the 3loa container:
“sudo docker-compose up -d”

The 3-leg helper is now live and can be access from API Fortress using the following URL:
“http://3loa.apifortress:3000/oauth”

Now that we have that up and running, watch the short video below to learn how to use this in API Fortress to automate your 3-leg OAuth:

Generating Fake Test Data

*Introduced in API Fortress 17.1.0*

Does your API or test require random full names, valid/invalid ids, or various types of input data? Well now you can generate these random data points directly in API Fortress with the Fake Data Generator.

There are a couple of ways you can generate this data:

You can directly reference the method within your variable, API call, or anywhere in the test where you can type in the following syntax: “${F.zipCode()}”

For example:

You can use the “Fake data generation” component to generate this data.

There are a few different ways this component can be used. You can use it to generate a string, array, or an object. See below for examples.

  1. Generate a String

Var – name of variable in which data will be stored (for referencing in the test elsewhere)
Variable mode – String (single piece of data)
String – Here you will put the name of the type of data you want. See the list below for all options. Some examples are firstName, lastName, and emailAddress.
Count – How many examples of this data type would you like to generate.

2. Generate an Array

Var – name of variable in which data will be stored (for referencing in the test elsewhere)
Variable mode – Array (multiple data points)
Array – Here you will put the name of the type of data you want. See the list below for all options. Some examples are firstName, lastName, and emailAddress.
Count – How many arrays of these data types would you like to generate. (Notice that the count field has been left blank, in that case the system will generate 1 iteration of the data)

3. Generate an Object

Var – name of variable in which data will be stored (for referencing in the test elsewhere)
Variable mode – Object (a map of name:data point). This is often used to create JSON objects.
Array – Here you will put the name of the type of data you want. See the list below for all options. Some examples are firstName, lastName, and emailAddress.
Count – How many strings of this data type would you like to generate.

List of Methods

Please note that the method itself is listed below. When using the Fake data component only use the name of the method without the “()”

Addresses and Countries

  • streetName(): provides random street name
  • streetAddressNumber(): provides random address number
  • streetAddress(): provides random street and address number. If secondary specified provides apt number.
  • secondaryAddress(): provides random apt number
  • zipCode(): provides random zip code. If state provided provides proper zip code for the state **(valid only for US states)
  • streetSuffix(): provides random street suffix
  • streetPrefix(): provides random street prefix
  • citySuffix(): provides random city suffix
  • cityPrefix(): provides random city prefix
  • city(): provides random city Name
  • cityName(): provides random city Name
  • state(): provides random state/province
  • buildingNumber(): provides random build number
  • fullAddress(): provides random full address
  • country(): provides random country
  • countryCode(): provides random country code
  • countryCodeSL(): provides random country code in small letters
  • countryCodeSL3d(): provides random country code in small letters on 3 digits
  • capital(): provides random capital city

People and People identity

  • fullName(): provides random full name
  • firstName(): provides random first name
  • lastName(): provides random last name
  • profession(): provides random profession
  • timeZone(): provides random time zone
  • validID(): provides random valid ID
  • invalidID(): provides random invalid ID
  • validSSN(): provides random valid SSN
  • invalidSSN(): provides random invalid SSN
  • phone(): provides random phone number
  • mobile(): provides random mobile number

Internet

  • emailAddress(): provides random email address
  • domainName(): provides random domain name
  • domainWord(): provides random word
  • domainSuffix(): provides random suffix
  • url(): provides random url
  • password: provides random password
    • Syntax: (<minimumLength,maximumLength,includeUppercase,includeSpecial,includeDigit>)
    • Example: password(5,10,true,false)

Credit Card

  • creditCardNumber(): provides random credit card number
  • creditCardExpiry(): provides random credit card expire date
  • creditCardType(): provides random credit card type

Products

  • productName(): provides random product name
  • material(): provides random material
  • price(): provides random price
  • promotionCode(): provides random promotion code

Companies

  • companyName(): provides random company name
  • suffix(): provides random company suffix
  • industry(): provides random industry

Currency

  • currency(): provides random currency
  • currencyCode(): provides random currency code

Random Numbers

  • integer: provides random integer number
    • Syntax: (<min,max>)
    • Example: integer(2,20)
  • decimal: provides random decimal number
    • Syntax: (<min,max,maxdecimals>)
    • Example: decimal(0,2,2)
  • uuid(): provides random unique identifier

Boolean

  • bool(): provides random boolean value

Collection/single Data

  • collection(<number_of_elements,”method”>):
    • provides a list of elements generated by “method”.
    • The single element is a simple string.
    • The size of the list is equal to the number_of_elements
  • collection(<number of elements,[“method1″,”method2”,…,”methodN2]>):
    • provides a list of elements generated by the list of methods provided.
    • The single element is a list.
    • The size of the list is equal to the number_of_elements
  • collection(<number of elements,[method1: ‘method1′,method2:’method2′,…,methodN:’methodN’>):
    • provides a list of elements generated by the list of methods provided.
    • The single element is a map.
    • The size of the list is equal to the number_of_elements
  • single(<“method”>):
    • provides an element generated by “method”.
    • The element is a simple string.
  • single(<[“method1″,”method2”,…,”methodN2]>):
    • provides an element generated by the list of methods provided.
    • The element is a list.
  • single(<[method1: ‘method1′,method2:’method2′,…,methodN:’methodN’>):
    • provides an element generated by the list of methods provided.
    • The single element is a map

Version Control

There are two primary mechanisms for version control in API Fortress. The first is the Publish Test feature, which allows for the pushing of updated test-code to a live version of the test.

The second mechanism for version control is the API Fortress-Git integration. The integration is powered by the API Fortress Post-Receive Git Hook, which can be found here. Documentation is located here.

Testing GraphQL

GraphQL is a fantastic tool for creating versatile, eminently flexible servers. With API Fortress, testing GraphQL queries is as easy as testing regular REST endpoints.

API Fortress provides a demonstration GraphQL environment at:

GraphServerlet

The query and mutation below are formatted for this environment.

Testing a Query:

If the server has GraphicQL enabled, creating your queries through that tool and then copying the generated URLs into an API Fortress GET component is an acceptable process. However, this process does not lend itself to either readability or replicability. The preferred method is passing the query as a POST body.

If we’re sending a query request to our GraphQL server, we would format our POST body as follows:

{
 "query": "query (\$id: Int!) { course(id: \$id) { id, title, author, description, topic, url }}", 
 "variables": { "id": 1} 
}

The above object says the following: we are querying for a specific course by ID, and wish our response body to contain the ID, Title, Author, Description, Topic, and URL of that entry. If we send this body as a POST to our test GraphQL environment, our response will look like this:

{
 "data": {
   "course": {
   "id": 1,
   "title": "The Complete Node.js Developer Course",
   "author": "Andrew Mead, Rob Percival",
   "description": "Learn Node.js by building real-world applications with     
    Node, Express, MongoDB, Mocha, and more!",
   "topic": "Node.js",
   "url": "https://codingthesmartway.com/courses/nodejs/"
    }
  }
}

Since our response is a JSON body, API Fortress is fully capable of automatically generating  a test to validate future responses from this query.

Testing a Mutation:

A mutation is a GraphQL operation that makes a change to the data being provided. Whereas a GraphQL Query that performs a READ, a Mutation performs a CREATE, UPDATE, or DELETE, rounding out our CRUD operations.

A Mutation is also passed as a POST body to the GraphQL endpoint in question:

{
 "query": "mutation (\$id: Int!, \$topic: String!) { updateCourseTopic(id: \$id, topic: \$topic) { title, topic }}", 
 "variables": { "id": 1, "topic" : "Ruby" } 
}

This Mutation is executing the ‘updateCourseTopic’ operation on the database entry with the ID of 1 and changing its ‘topic’ value to ‘Ruby’. Note the ‘mutation’ keyword in place of the ‘query’ keyword from the Query example. This Mutation would return the following response from our test GraphQL environment:

{
 "data": {
    "updateCourseTopic": {
    "title": "The Complete Node.js Developer Course",
    "topic": "Ruby"
    }
  }
}

Again, as this is a valid JSON response body, API Fortress is able to generate a test automatically to validate its schema in the future.

Import / Export Tests

API Fortress makes it very simple to import and export your tests. This is useful when moving tests to another project, making another API Fortress deployment, or sharing with our support team for help.

Export Tests

After you login to the platform, the flow is as such:

  1. Click Tests for a Project (folder) of your choice
  2. To download click the circles to the left of the test name
  3. Click Export Selected Tests

This will download a zip of the tests you exported. See below for a GIF of the process.

Export Tests
Export Tests

Import Tests

To import a test is as easy as clicking the +Import Tests button next to the +New Test button. See image below.

Import Tests
Import Tests

Using the Local Engine (APIF-Local)

apif-local-Local is the API Fortress local engine.

The objective of this program is to allow developers to run API Fortress tests on their computers, and to validate the tests being developed locally.

Requirements

  • A modern Linux/Mac/Windows computer
  • Java 8

Installation

  1. Make sure Java 8 is installed and is present in the command line path
  2. Unzip the file provided by our team in a location that is convenient to you

Configuration

The only essential key in the configuration is the license. Everything else can be provided on the command line. We do, however, suggest you configure the tool properly once you get accustomed to it and start using it regularly.

Example:

license: 'abcabcabc'
hooks:
- key: examples
  url: https://mastiff.apifortress.com/app/api/rest/v3/abcabc-123-123-123
  credentials:
    username: info@example.com
    password: password1

- key: local
  url: http://mydeployment.com:8080/app/api/rest/v3/abcabcabc-123-123-123
 credentials:
    username: john@doe.com
    password: password1

In this example, we configured two different hooks, related to two different API Fortress instances. The value of the “key” can be used to reference a profile without the need to explicitly introduce the hook URL and credentials every time in the command line.

The configuration file can be placed in multiple locations, based on your preferences.

The priority check is the following:

  1. A path provided in the command line
  2. The current working directory
  3. The directory where apif-local.jar resides
  4. A .apifortress sub-directory in the user’s home directory

apif-local – Download

java -jar apif-local.jar download [hook] <options>

This mode allows you to download full projects, or, selectively, tests, vault and environments, from an API Fortress platform instance. See apif-local.jar help for details about the possible switches.

Examples:

java -jar apif-local.jar download examples -l /tmp/stuff

Will download the full project represented by they key “examples” in the directory /tmp/stuff.

java -jar apif-local.jar download examples -l /tmp/stuff -v

Will download just the project’s vault.

apif-local – Run

java -jar apif-local.jar run [path] <options>

Runs an API Fortress test, located in the local file system. See apif-local.jar help for details about the possible switches.

The expected file system should look like the following:

\any_directory
  \api_fortress_tests
     \simple_test_1
         | unit.xml
         | input.xml
     \advanced_test_2
         | unit.xml
         | input.xml

Every test is represented by a directory, containing an input.xml and a unit.xml file. This exact format is also followed by apif-local – Download.

Examples:

java -jar apif-local.jar run any_directory/api_fortress_tests/simple_test_1

Will run the test simple_test_1.

java -jar apif-local.jar run any_directory/api_fortress_tests -r

Will run all the tests contained in the api_fortress_tests directory.

Different ways to compose a Request Body

In this post we will show you the different ways you can compose a Request Body: from the simplest to the most complex.

  1. Copy and paste the body from somewhere

    The first and easiest way is when we have a body from somewhere to copy and paste as is into the call. Let’s see how this is done:

    1. In the composer we add the POST component and type the url and all of the required fields.
      Url: https://mydomain.com/myPost (the url of the resource you want to test)
      Variable: payload (the name of the variable that contains the response)
      Mode: json (the type of the response)

      post_comp

    2. Now we add the Body component and after selecting the Content-Type we paste the body in Content field.
      Content-Type: application/json
      Content: {"method":"post","url":"http://www.testme.com/api/run/test"} (the body required in your call)

      paste_body

    3. Now we can execute the call and proceed with the test.
      final_call
  2. Using Variables in the Request Body

    Another way to compose a request is using variables in the body.

    1. In the composer we add the POST component typing the url and all the required fields.
      Url: https://mydomain.com/myPost (the url of the resource you want to test)
      Variable: payload (the name of the variable that contains the response)
      Mode: json (the type of the response)

      post_comp

    2. We add the Body component. In the Content-Type we choose the proper one, let’s say application/json. In this scenario we need to use a variable so in the Content field we enter the following:
       {
       "user": ${user},
       "password": ${password},
       "url": "http://www.testme.com/api/run/test"
       }

      In this scenario “user” and “password” are not directly passed in the body but they are variables defined as global parameters in the data set.
      var_body
      data_set

    3. The POST has been done and can be executed.
      final_call2
  3. Using a Variable from another call

    The next way to compose a Request Body is by using a variable from another call. Let’s see how this can be done.

    1. The first thing we need to do is add the call we will retrieve the variable from. Let’s consider, as example, the common scenario where we need to perform a login for authentication and retrieve the authentication token required for the following call.
      Url: http://www.mydomain.com/login (the url of the resource you want to test)
      Variable: payload (the name of the variable that contains the response)
      Mode: json (the type of the response)
      Header: 
         Name: Authorization
         Value: Basic YWRtaW46cGFzc3dvcmQ= (this value comes from encoding username:password in Base64)

      loginAuth

    2. Executing the login we will have as response the desired token. Let’s see it using our console.
      response_token
    3. Now we need to save the token as variable.
      Var: token (the name of the variable)
      Variable mode: String (the type of the variable)
      Value: ${payload.access_token} (we retrive the value from the previous 'payload')

      var_token

    4. Once the token has been saved as variable we can proceed adding the second call and use that token in the Request Body.
      Content-Type: application/json
      Content: {"token":"${token}"}

      bodyWToken

  4. Using an object from another call

    In the next example we will show you a more complex case. We will consider the scenario where we need to use an object retrieved from a previous call into the body of a subsequent call. Let’s take a look at an example:

    1. First, we perform the call we retrieve the object from.
      search
    2. Let’s execute the call in our console in order to see the response.
      {
       "id": 123,
       "items": [
       {
       "id": 11,
       "name": "stuff1"
       },
       {
       "id": 12,
       "name": "stuff2"
       },
       {
       "id": 13,
       "name": "stuff3"
       }
       ]
      }

      search_response

    3. Let’s say we need the object ‘items’ as the body in the subsequent call. So, as a second call, we will add a POST and we will type the following as body:
      ${searchPayload.items.asJSON()}

       

      objectInBody

    4. Now we can proceed with the test.

     

  5. Creating a new structure to add as a body

The last scenario is yet another more complex one. In this case, we consider the scenario where we need to create a new structure to add as a body, using data from a previous call. Let’s see how we can do this:

  1. The first thing we have to do is to perform the call which retrieves the data we’re using. Let’s consider a GET that returns an array of items.firstCall
  2. Let’s see the response using our console.
    {
     "items": [
     {
     "id": 11,
     "price": 5.99
     },
     {
     "id": 12,
     "price": 6.99
     },
     {
     "id": 13,
     "price": 10.99
     },
     {
     "id": 14,
     "price": 15.99
     }
     ]
    }

    response_get

  3. Now we need to create the new data structure. To do so, we add a SET component as follow: 
    payload.items.each { it -> it.currency='$'  }; return payload.asJSON(); (for each item in the array, we add the currency attribute with "$" as value)

    newData

  4. Now we can add the POST and add the new structure as the POST request body:postWithNewStructure
  5. That’s it. Now we can proceed with the test.allDone

Note: in this post we have used the POST method but all of the examples shown can be applied to the other REST methods. In the same way, we have demonstrated scenarios with Request Bodies, but all of the examples can be used for Header or Param cases.

 

 

Load Agent Deployment (On-Premises)

A Load Agent is a server instance that provides the simulated users in a load test. Load Testing cannot function without at least one Load Agent.

The provided files (contained in core-server.tgz) are all that you need in order to deploy a Load Agent. This tutorial will explain what changed need to be made to the files within in order to properly deploy the Load Agent.

Before starting the process, there is a step that needs to be taken for clients who received their API Fortress containers before the introduction of Load Testing.

Step 0 (Not for all users) – Activate the Node Container

Open the docker-compose.yml in the main API Fortress directory. It can be located at /core/bin/docker-compose.yml

  • Paste the following code snippet in after the #RABBITMQ section and before the #APIFORTRESS DASHBOARD section:
#NODE
apifortress-node:
   image: theirish81/uitools
   hostname: node.apifortress
   networks:
      - apifortress
   domainname: node.apifortress
   labels:
      io.rancher.container.pull_image: always
  • In the links section of the #APIFORTRESS DASHBOARD configuration, add the following line:
- apifortress-node:node.apifortress
  • Save and close the docker-compose.yml.
  • Open the start_all.sh file in a code editor. It is also located in /core/bin.
  • Copy and paste the following and overwrite the entire contents of the file:
#!/bin/bash
sudo docker-compose up -d apifortress-postgres
sleep 5s
sudo docker-compose up -d apifortress-mongo
sleep 5s
sudo docker-compose up -d apifortress-rabbit
sudo docker-compose up -d apifortress-node
sleep 30s
sudo docker-compose up -d apifortress
sleep 1m
sudo docker-compose up -d apifortress-mailer
sudo docker-compose up -d apifortress-scheduler
sudo docker-compose up -d apifortress-connector
  • Your API Fortress instance can now utilize the API Fortress Node Container which powers Load Testing.

Step 1 – Unzip the provided file (core-server.tgz)

First, unzip the provided file.

Screen Shot 2018-06-05 at 11.44.28 AM

Step 2 – Define the maximum users per Load Agent

Users per agent are the maximum number of virtual users that each Load Agent can provide.

It’s important to remember that large numbers of simulated users will require large amounts of hardware resources. Contact your DevOps team to develop a strategy for resource allocation. 

  • Locate and open the file named application.conf. It is located in core-server/etc.
  • Line 14 of this file (fixed-pool-size) should have it’s value adjusted to match the desired number of maximum users per agent.
  • Line 48 of this file (nr-of-instances) should have it’s value adjusted to match the desired number of maximum users per agent. These two values should match.

Step 3 – Configure Config.yaml

  • Locate and open config.yaml. It is located at core-server/etc.
  • First, we have to configure the baseURL
    • baseURL is located on line 3.
    • If the Load Agent and the API Fortress Dashboard are located on the same server, then you can replace the baseURL with the internal address and port of the Dashboard on the server.
    • If the Load Agent and the API Fortress Dashboard are located on different servers, you can replace the baseURL with the actual URL of the Dashboard. That is to say, the URL you would use to access it via web browser.
  • Next, we need to provide the API Key and Secret.
    • Open the main API Fortress dashboard and click the gear icon in the upper right corner to access the settings menu
    • Click the “API Keys” option in the left sidebar.
    • Click “+API Key” 

Create API Key

(Click image for GIF of procedure)

  • Copy the API Key to line 5 of config.yml.
  • Copy the Secret to line 6 of config.yml.

Step 4 – Adding the Engine

  • The next step is to add the new Engine to API Fortress itself.
  • Log into API Fortress as an administrator.
  • Click the user icon in the upper right corner, and then click “Admin Panel”
  • Click “Engines” on the left side of the screen.
  • Click “+Engine”
  • Enter the name and location of the Engine.
  • The CRN value defaults to a random string. You must change it to something human-readable. This is the internal name of the engine.
  • After modifying the CRN, copy the value to line 11 of config.yml
  • Copy the secret to line 12 of config.yml
  • Select the Owning Company of the Engine. An Engine must be owned by a single company. The default value (Public Engine) should not be chosen.
  • Select “Yes” for “Dedicated to Load Testing
  • Click the green check to save the Engine settings.

Add Engine

(Click image for GIF of procedure)

Step 5 – Deploy the Load Agent

At the desired server location, use the “docker-compose up -d” command to deploy the Load Agent container. After the operation is complete, the Load Agent will be visible to your API Fortress Load Tests.