Skip to content

Testing A Connector Locally

If you want to validate the code of a connector locally, you need to have a data object and at least one Cache Writer or one Action Processor implemented and know the API you are building the connector for.

At this point

  • You understand what a connector is.
  • You have implemented the API Client and related files.
  • You have a data object and at least one Cache Writer or Action Processor implemented

To test the connector locally, the CLI and connector project offers some useful functionality. You can verify if the connector works by: 1. Initializing a test-settings.json file 2. Configuring test-settings.json in your root "Connector" folder 3. Configuring launchSettings.json in the "Properties" folder 4. Using your development environment or command line to run

Instructions

Run Test Init Command

Always build your project before running xchange test init to keep the file up to date. This creates a file named test-settings.json and populates it scaffolding based on your current connecter setup. Like most commands, make sure to execute it in the "Connector" directory where Connector.csproj is located.

Command

xchange test init

Warning

Always build the project before the command is run. Must execute the command in the directory where the csproj file of the connector is. If you don’t you will get an error message like the following:

xchange test init
Error Time: 11:42:29.299 Could not find a CSPROJ file in the directory: /Users/builder/Documents/svc/trimble/connector-product

Expected Results on Success

xchange test init
Information Time: 11:44:41.110 /Users/builder/Documents/svc/trimble/connector-product/Connector/test-settings.json could not be found. Creating a new file.
Information Time: 11:44:41.191 Test data generated in /Users/builder/Documents/svc/trimble/connector-product/Connector/test-settings.json

Enter Configuration In the Test Settings file

Test-settings.json contains several different sections which will need to be configured, including connectorRegistration, activeConnection, connections, serviceConfiguration, and data. By default it is listed in gitignore and you will need to enter credentials here to test your api such as username, password, bearer token, etc. as appropriate for your authorization setup.

{
  "testSettings": {
    "connectorRegistration": {  }, // api configuration
    "activeConnection": "apiKeyAuth", // definition key of connection to use
    "connections": [ // predefined connections to test against
      {  },
      {  },
    ],
    "app-1": { // module to test
      "serviceConfiguration": {  } // configuration of the module
      "data": {  } // test data objects
    }
  }
}

connectorRegistrations

The connectorRegistration section coordinates with what you have under the Connector/ConnectorRegistrationConfig.cs - This is where you enter test data - on the App Xchange platform these fields would be completed by the user. It might include a Username, Password, Company or Account ID, or a wide variety of things depending on the specific API and product the Connector is for.

{
  "connectorRegistration": {
    "companyId": 123,
    "startDate": "08-04-1989",
    "userName": "myTestUserNameHere",
    "password": "myTestPasswordHere",
    "accountId": "myTestAccountIdHere"
  },
}

activeConnection

Define the connection you want to use for your test. Enter the definitionKey of the connection you want to test with.

{
   "activeConnection": "apiKeyAuth",
}

connections - currently only applies if using --auth-type

An array of credentials that you want to test against. Only one will be used per test run.

{
  "connections": [
    {
      "definitionKey": "apiKeyAuth",
      "configuration": {
        "apiKey": "super-user",
        "connectionEnvironment": 1
      }
    },
    {
      "definitionKey": "basicAuth",
      "configuration": {
        "username": "normal-user",
        "password": "123456",
        "connectionEnvironment": 1
      }
    },
    ,
  ],
  
}

Module ID section (app-1 default example)

Contains the serviceConfiguration and data keys for each module to test. The serviceConfiguration section contains information about what Action Processors and Cache Writers exist for the connector, and which ones to test. Set "UploadObject" to "true" to run and "false" to ignore/skip. The data section contains information on the data objects broken down by event and type.

{
 "app-1": {
  "serviceConfiguration": {
     "actionProcessor": {
        "AddHealthCheckConfig": {
           "ProcessQueuedEvent": true,
            "TestAPIFailure": false,
             "TestCacheSyncFailure": false
          },
         },
      "cacheWriter": {
         "HealthCheckConfig": {
            "UploadObject": true,
            "ValidateCacheInsert": false,
            "ValidateCacheUpdate": false,
            "ValidateCacheDelete": false
          }
        }
      }
  },
  "data": {
     "health-check": {
        "add": [
           {
            "Timestamp": "2024-06-25T22:50:19.9781118Z"
           }
          ]
      }
  }
}
Full Example of a test-settings.json
  1. Non connection configuration needed for interacting with the external system API.
  2. Which connection to use
  3. List of available connections
  4. Flag to enable the CreateEmployees action when the Action Processor Local Development profile runs.
  5. Flag to enable the cache writer of the Employees data object when the Cache Writer Local Development profile runs.
  6. All the CreateEmployeesActionInput properties that are used to test the CreateEmployees action.
  7. All the UpdateEmployeesActionInput properties that are used to test the UpdateEmployees action.
{
  "testSettings": {
    "connectorRegistration": {
      "apiDetails": { // (1)
        "cuisine": "",
        "type": "",
        "diet": "",
      }
    },
  "activeConnection": "basicAuth", // (2)
  "connections": [ // (3)
    {
      "definitionKey": "apiKeyAuth",
      "configuration": {
        "apiKey": "",
        "connectionEnvironment": 1
      }
    },
    {
      "definitionKey": "basicAuth",
      "configuration": {
        "username": "",
        "password": "",
        "connectionEnvironment": 1
      }
    }
  ],
    "app-1": {
      "serviceConfiguration": {
        "actionProcessor": {
          "AddHealthCheckConfig": {
            "ProcessQueuedEvent": true,
            "TestAPIFailure": false,
            "TestCacheSyncFailure": false
          },
          "CreateEmployeesConfig": {
            "ProcessQueuedEvent": true // (4)
          },
          "UpdateEmployeesConfig": {
            "ProcessQueuedEvent": true
          },
          "DeleteEmployeesConfig": {
            "ProcessQueuedEvent": true
          }
        },
        "cacheWriter": {
          "HealthCheckConfig": {
            "UploadObject": true,
            "ValidateCacheInsert": false,
            "ValidateCacheUpdate": false,
            "ValidateCacheDelete": false
          },
          "EmployeesConfig": {
            "UploadObject": true // (5)
          }
        }
      },
      "data": {
        "health-check": {
          "add": [
            {
              "Timestamp": "2024-06-25T22:50:19.9781118Z"
            }
          ]
        },
        "employees": {
          "create": [ // (6)
            {
              "firstName": "",
              "lastName": "",
              "phone": "",
              "email": "",
              "address": "",
              "city": "",
              "state": "",
              "zip": ""
            }
          ],
          "update": [ // (7)
            {
              "employeeId": 0,
              "firstName": "",
              "lastName": "",
              "phone": "",
              "email": "",
              "address": "",
              "city": "",
              "state": "",
              "zip": ""
            }
          ],
          "delete": [
            {
              "employeeId": 0
            }
          ]
        }
      }
    }
  }
}

Run Test Locally

Now that you've configured test-settings.jon, locate Connector/Properties/launchSettings.json. This file contains information about the launch profile, such as the application URL and the environment variables.

What does the launchSettings File Contain and what is its purpose:

The launchSettings.json is a configuration file used in C# projects. It defines various settings related to the application's launch, such as environment variables, command-line arguments, and debugging settings. This file is located within the "Properties" folder of your project and is used by the development environment to determine how the application should run.

In the launchSettings file locate the sections

Action Processor Local Development 
Cache Writer Local Development
These are the sections we care about.

Testing Cache Writer

Command

dotnet run --launch-profile "Cache Writer Local Development"

This or any profile can be run via the IDE of your choosing as well. Feel free to use which one you are comfortable with.

Example Expected Results on Success

$ dotnet run --launch-profile "Cache Writer Local Development"
Local development is currently configured. You'll need to use the Xchange.Connector.SDK.Test.Local library
<6>ESR.Hosting.RunService[0] ESR (1.0.6.0) Host started in 0.646475 seconds
<6>ESR.Hosting.RunService[0] Running job 60ab563e-06be-491b-ac91-78b0d668288e for Subscriber Id 0
Time to Retrieve Service Run Message and Signal Started: 966
Time to initialize context: 68
Time to validate context: 94
[12:17:28 INF] Writing <fieldwire/app/1/project> (Asynchronous) data objects to cache
[12:17:29 INF] Change detection system determined that there were 10 new records, 0 updated records, 0 unchanged records, and 0 deleted records for object of type <fieldwire/app/1/project>.
[12:17:29 INF] App Network sync summary for fieldwire/app/1/project
Inserts: 10 successful, 0 no change, 0 failed
Updates: 0 successful, 0 no change, 0 failed
Deletes: 0 successful, 0 no change, 0 failed
Time to Finish Service: 752
<6>ESR.Hosting.RunService[0] Service runner shutting down…

Note

When you run the cache writer or action processor a directory named ‘databases’ gets created as well as a file under that directory named local-test-what-goes-here.db. The path of that file is here Connector/databases/local-test-what-goes-here.db.

On a local test cache write, the connector talks to the API pulls down the information, and stores it on a local database file.

Testing Action Processor

  1. Go to Properties/launchSettings.json
  2. Locate the section Action Processor Local Development
  3. Under the field/property commandLineArgs
  4. Fill out the --dataObjectUrl XXXX --actionUrl XXXX part of the command line for data object and action - note it is case sensitive based on the CLI command.

Example

--dataObject project --action create

Command

dotnet run --launch-profile "Action Processor Local Development"

Expected Results on Success

Local development is currently configured. You'll need to use the Xchange.Connector.SDK.Test.Local library
<6>ESR.Hosting.RunService[0] ESR (1.0.6.0) Host started in 0.42326 seconds
<6>ESR.Hosting.RunService[0] Running job 35b583fe-ffb8-4090-bfd9-98a335313a19 for Subscriber Id 0
Time to Retrieve Service Run Message and Signal Started: 928
Time to initialize context: 76
Time to validate context: 89
[12:24:53 INF] Starting action processor for any queued actions
[12:24:54 INF] Action with ID ffd85a7f-335a-4c38-8cfb-d182c974e0c2 closed as Failed
[12:24:54 INF] Processing actions complete. 1 were handled. 0 queued actions were skipped
Time to Finish Service: 424
<6>ESR.Hosting.RunService[0] Service runner shutting down...

Expected Error If Data Object or Action Command Line Argument Are Wrong

dotnet run --launch-profile "Action Processor Local Development"
Local development is currently configured. You'll need to use the Xchange.Connector.SDK.Test.Local library
<6>ESR.Hosting.RunService[0] ESR (1.0.6.0) Host started in 0.503598 seconds
<6>ESR.Hosting.RunService[0] Running job fc746eda-9a10-49a4-b3ac-9e565be8ecf3 for Subscriber Id 0
Time to Retrieve Service Run Message and Signal Started: 1016
Time to initialize context: 76
Time to validate context: 84
[12:24:38 INF] Starting action processor for any queued actions
[12:24:38 ERR] An error occurred during action processing
System.Exception: Unable to resolve an IAction<> type for the module 'app-1' and the DataObject 'project' and its action 'Create'
  at Xchange.Connector.SDK.Test.Local.TestDataSource.GetIActionInterface()
  at Xchange.Connector.SDK.Test.Local.TestDataSource.GetTestQueuedData()
  at Xchange.Connector.SDK.Test.Local.Client.LocalAppNetworkClient.GetQueuedActions(String urlPart, String actionPath, CancellationToken cancellationToken)
  at ESR.Hosting.Action.ActionHandlerService.HandleActionsInActionQueueAsync()
<3>ESR.Hosting.RunService[0] Exception while running service System.Exception: Unable to resolve an IAction<> type for the module 'app-1' and the DataObject 'project' and its action 'Create'    at Xchange.Connector.SDK.Test.Local.TestDataSource.GetIActionInterface()    at Xchange.Connector.SDK.Test.Local.TestDataSource.GetTestQueuedData()    at Xchange.Connector.SDK.Test.Local.Client.LocalAppNetworkClient.GetQueuedActions(String urlPart, String actionPath, CancellationToken cancellationToken)    at ESR.Hosting.Action.ActionHandlerService.HandleActionsInActionQueueAsync()    at Xchange.Connector.SDK.Hosting.ServiceRunner.RunServiceAsync(IConnectorServiceDefinition serviceDefinition, CancellationToken cancellationToken)    at Xchange.Connector.SDK.Hosting.ServiceRunner.RunAsync(CancellationToken cancellationToken)    at ESR.Hosting.RunService.StartAsync(CancellationToken cancellationToken)
<6>ESR.Hosting.RunService[0] Service runner shutting down...

Resetting Local Cache

If you need to reset the local databases (Change detection and cache) this command will do so:

Command

xchange test reset

Summary

At this point, you should have used the test init command to prepopulate a test-settings.json file and configured it for testing, and run the test according to launchSettings.json with your IDE or command line. You can repeat the build->test init->configure->launch process as you complete your connector.