Giter VIP home page Giter VIP logo

airbyte-e2e-testing-tool's Introduction

Airbyte E2E testing tool

This stand-alone testing configurable application will help us execute different end-to-end tests and improve the Airbyte final product quality. You can find the development state and future roadmap in this epic issue.

Ways to use it:

  • Automatic run before publishing a new connector version to the could - prevent versions without backward compatibility or braking change for one of the possible integrations between source and destination.
  • Run scenario for a dev version in the PR.
  • Run scenario locally during development.

Main flow

The central concept of the tool is a universal testing platform that you can easily configure by providing scenario config and required credentials. The solution helps us run different test scenarios from the CI referring to already defined config files and cover all possible e2e test cases with minimal effort.

image

Credentials

All credentials are independent of the selected scenario and can be used in different runs. In addition, we store credentials in the secrets storage as we do for the integration tests.

As the credential file is input data, you can find structure in the CredentialConfig.yaml file.

Source credential file example:

{
  "credentialName": "test_source_creds",
  "credentialType": "source_creds",
  "instanceType": "Postgres",
  "credentialJson": {
    "database": "test_source_database",
    "host": "put.your.host.here",
    "password": "yourPassword",
    "port": 5432,
    "replication_method": {
      "method": "Standard"
    },
    "schemas": [
      "public"
    ],
    "ssl": false,
    "ssl_mode": {
      "mode": "disable"
    },
    "tunnel_method": {
      "tunnel_method": "NO_TUNNEL"
    },
    "username": "sourceuser"
  }
}

Airbyte credential file example:

{
  "credentialName": "airbyte_local_creds",
  "credentialType": "airbyte_creds",
  "credentialJson": {
    "apiHost": "your.airbyte.host",
    "apiPort": "80",
    "apiScheme": "https"
  }
}

Scenarios

The scenario config describes a list of actions, their sequence, and used instances. It doesn't contain any credentials for used instances. So, we can reuse the same scenario for different Airbyte instances, sources, and destinations. As there is no sensitive data, we can store it as part of the application.

You can find scenario config file structure in the ScenarioConfig.yaml file. (Sub files: ScenarioConfigAction.yaml , ScenarioConfigInstance.yaml)

Note! The instance name is a way to use the same instance in different actions

Scenario config example:

{
  "scenarioName": "Simple sync scenario",
  "usedInstances": [
    {
      "instanceName": "airbyte_1",
      "instanceType": "AIRBYTE"
    },
    {
      "instanceName": "source_1",
      "instanceType": "SOURCE"
    },
    {
      "instanceName": "destination_1",
      "instanceType": "DESTINATION"
    },
    {
      "instanceName": "connection_1",
      "instanceType": "CONNECTION"
    }
  ],
  "preparationActions": [
    {
      "action": "CONNECT_AIRBYTE_API",
      "resultInstance": "airbyte_1"
    },
    {
      "action": "CREATE_SOURCE",
      "requiredInstances": [
        "airbyte_1"
      ],
      "resultInstance": "source_1"
    },
    {
      "action": "CREATE_DESTINATION",
      "requiredInstances": [
        "airbyte_1"
      ],
      "resultInstance": "destination_1"
    },
    {
      "action": "CREATE_CONNECTION",
      "requiredInstances": [
        "airbyte_1",
        "source_1",
        "destination_1"
      ],
      "resultInstance": "connection_1"
    }
  ],
  "scenarioActions": [
    {
      "action": "SYNC_CONNECTION",
      "requiredInstances": [
        "airbyte_1",
        "connection_1"
      ]
    }
  ]
}

How to run in the GitHub

You can put your comment with one of the testing tool commands to any PR in the repository to trigger the GitHub action. The action will run the testing tool using your comment message as input parameters for the main method. The GA publish the execution result in your original comment.

Example

  1. Open some PR
  2. Put the comment /run-scenario name="Simple sync scenario" airbyte_1=tt_airbyte_dev2 source_1=tt_postgres_source_aws_1 destination_1=tt_postgres_destination_aws_1
  3. Wait till GA updates your comment with the execution results. Screenshot from 2022-09-29 13-23-46

How to run locally

The tool provides the possibility to run all scenarios locally. If your command requires credentials, you should provide them locally or request them from the secret service. You have two ways how to provide the required credentials to the tool. The main flow is to get credentials from the secret service, but also you can use your local files as a source for credentials. (See more about credentials below)

Example: Run scenario with credentials from Secret service

  1. Clone the repository
  2. Build the project
  3. Put the secret service credential file in the secrets/service_account_credentials.json folder in the project root (You can find the file structure in the ServiceAccountConfig.yaml)
  4. Run the scenario by passing the required arguments to the method TestingTool::main with the command /run-scenario Screenshot from 2022-08-30 12-54-42

The result you can find in the execution log. Screenshot from 2022-09-29 13-41-04 Note! The help text is formatted for GitHub. You can put it there to get a more readable view. Screenshot from 2022-09-29 13-41-25

How to get the list of scenarios

The tool has help command /list-scenarios. The command provides the full list of available scenarios and hints on how to get more details about a specific scenario.

Note! The command also runs logical validation for all scenarios. If some scenario is unfinished or invalid, you will see โŒ sing after its name. Screenshot from 2022-09-29 13-46-12

How to prepare a scenario command line

Each scenario has its list of required credentials and their number. In addition, some scenarios might require parameter values in the command line. To make this step easier, the tool has command /help name="<scenario name>"(How to get name see `How to get the list of scenarios). This command returns a prepared command line and a list of all credentials you should put into this line. In the result, you can find such parts:

  • Call examples - different command lines which can be useful for you. Note that you need to replace texts like <put_credential_name> in this line before running.

Screenshot from 2022-09-29 13-53-41

  • Instances in the scenario - List required instance credentials with their types. Use it to put the proper credential name into the command line.

Screenshot from 2022-09-29 13-53-47

  • Parameters in the scenario - parameter is a simple text value required inside a scenario. The name and type of the parameter should be enough to understand which value is expected from you.

Screenshot from 2022-09-29 13-53-52

In the end, you should have a command line ready for execution. For example, in this case we can get a line like this : /run-scenario name="Update destination version scenario" airbyte_1=tt_airbyte_docker source_1=tt_postgres_source_aws_1 destination_1=tt_postgres_destination_aws_1 old_version="0.3.22" new_version="0.3.23"

How to choose a credential

TBD

CHANGELOG

Version Description
0.4.4 Add common local instances for destinations + Postgres impl
0.4.3 Make normalization on by default
0.4.2 Add autonomous instances
0.4.1 Action structure improvement + add delete actions for conn/src/dest instances
0.4.0 Phase 4 and 5 complete
0.3.0 Add possibility to provide params by actions + new action ReadSourceVersion
0.2.3 Scenario validation result is now available in help and list commands
0.2.2 Scenario description
0.2.1 Add additional settings to CredentialConfig
0.2.0 Run scenario using secret service. !No default test run anymore!
0.1.3 Run scenario using local files
0.1.2 Action parameters.
0.1.1 Implement HelpService. Now you can get short description with examples for a scenario.
0.1.0 Stage 1. POC

airbyte-e2e-testing-tool's People

Contributors

andriikorotkov avatar donotpanicua avatar etsybaev avatar grishick avatar kimerinn avatar mkhokh-33 avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

ghas-results

airbyte-e2e-testing-tool's Issues

Clearly show failed steps and error message when a scenario fails

I ran an upgrade scenario upgrading MySQL Source from 1.0.2 to 1.0.5. This scenario fails, because there is a backwards incompatible spec change between MySQL Source versions 1.0.2 and 1.0.5

/run-scenario-local name="Update source version scenario" airbyte_1=airbyte_creds.json source_1=source_creds.json destination_1=destination_creds.json old_version="1.0.2" new_version="1.0.5"

The output from the tool looks like this:

2:48:45 PM: Executing ':TestingTool.main()'...

> Task :generateEffectiveLombokConfig UP-TO-DATE
> Task :processResources UP-TO-DATE

> Task :generateJsonSchema2Pojo
Execution optimizations have been disabled for task ':generateJsonSchema2Pojo' to ensure correctness due to the following reasons:
  - Gradle detected a problem with the following location: '/Users/gregsolovyev/git/airbyte-e2e-testing-tool/build/generated/src/gen/java'. Reason: Task ':generateEffectiveLombokConfig' uses this output of task ':generateJsonSchema2Pojo' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. Please refer to https://docs.gradle.org/7.2/userguide/validation_problems.html#implicit_dependency for more details about this problem.

> Task :compileJava UP-TO-DATE
> Task :classes UP-TO-DATE

> Task :TestingTool.main()
2022-08-29 21:48:48 INFO i.a.t.TestingTool(main):16 - Testing tool started!
2022-08-29 21:48:48 INFO i.a.t.a.ArgumentParser(argumentParser):19 - Parsed arguments:
2022-08-29 21:48:48 INFO i.a.t.a.ArgumentParser(lambda$argumentParser$0):21 - run-command : /run-scenario-local
2022-08-29 21:48:48 INFO i.a.t.a.ArgumentParser(lambda$argumentParser$0):21 - destination_1 : destination_creds.json
2022-08-29 21:48:48 INFO i.a.t.a.ArgumentParser(lambda$argumentParser$0):21 - old_version : 1.0.2
2022-08-29 21:48:48 INFO i.a.t.a.ArgumentParser(lambda$argumentParser$0):21 - name : Update source version scenario
2022-08-29 21:48:48 INFO i.a.t.a.ArgumentParser(lambda$argumentParser$0):21 - source_1 : source_creds.json
2022-08-29 21:48:48 INFO i.a.t.a.ArgumentParser(lambda$argumentParser$0):21 - new_version : 1.0.5
2022-08-29 21:48:48 INFO i.a.t.a.ArgumentParser(lambda$argumentParser$0):21 - airbyte_1 : airbyte_creds.json
2022-08-29 21:48:48 INFO i.a.t.TestingTool(main):19 - Run arguments : 
Run arguments:
  Run command          : RUN_SCENARIO_LOCAL
  Scenario config name : Update source version scenario
  Credentials          : {destination_1=test_dest_creds, source_1=test_source_creds, airbyte_1=airbyte_local_creds}
  Parameters           : {old_version=1.0.2, new_version=1.0.5}

2022-08-29 21:48:48 INFO i.a.t.s.v.ValidationService(printResults):28 - Scenario `Update source version scenario` validation result : 
  [Check that all action instances listed in the `UsedInstances` section]  : Ok      
  [Check that all instances have initialization action]                    : Ok      
  [Validate `UsedInstances` section]                                       : Ok      
  [Action should have all mandatory attributes]                            : Ok      
2022-08-29 21:48:48 INFO i.a.t.TestingTool(runScenario):33 - Scenario [Update source version scenario] is selected for execution.
2022-08-29 21:48:48 INFO i.a.t.s.a.ActionConnectToAirbyteAPI(connectToApi):50 - Creating Airbyte Config Api Client...
2022-08-29 21:48:49 INFO i.a.t.s.a.ActionCreateSource(createSource):50 - New source "MySQL" successfully created.
2022-08-29 21:48:49 INFO i.a.t.s.a.ActionCreateDestination(createDestination):48 - New destination "Postgres" successfully created.
2022-08-29 21:48:49 INFO i.a.t.s.a.ActionUpdateSourceVersion(updateSourceVersion):48 - Start updating Source version to  "1.0.2"
2022-08-29 21:48:51 ERROR i.a.t.s.TestScenario(executeActions):36 - Scenario execution stops due to action [Update Source version] failure.
2022-08-29 21:48:51 INFO i.a.t.TestingTool(runScenario):36 - Scenario preparation finished.
2022-08-29 21:48:51 INFO i.a.t.TestingTool(runScenario):38 - Scenario execution finished.
2022-08-29 21:48:51 INFO i.a.t.s.TestScenario(printSummary):45 - Scenario `Update source version scenario` execution is finished  with errors!.
Preparation actions :
  [Connect to Airbyte API]     : OK
  [Create Source]              : OK
  [Create Destination]         : OK
  [Update Source version]      : FAILED - Execution failed with exception : updateSourceDefinition call failed with: 500 - {"message":"Internal Server Error: Get Spec job failed.","exceptionClassName":"java.lang.IllegalStateException","exceptionStack":["java.lang.IllegalStateException: Get Spec job failed.","\tat com.google.common.base.Preconditions.checkState(Preconditions.java:502)","\tat io.airbyte.server.converters.SpecFetcher.getSpecFromJob(SpecFetcher.java:14)","\tat io.airbyte.server.handlers.SourceDefinitionsHandler.getSpecForImage(SourceDefinitionsHandler.java:293)","\tat io.airbyte.server.handlers.SourceDefinitionsHandler.updateSourceDefinition(SourceDefinitionsHandler.java:228)","\tat io.airbyte.server.apis.ConfigurationApi.lambda$updateSourceDefinition$14(ConfigurationApi.java:364)","\tat io.airbyte.server.apis.ConfigurationApi.execute(ConfigurationApi.java:886)","\tat io.airbyte.server.apis.ConfigurationApi.updateSourceDefinition(ConfigurationApi.java:364)","\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)","\tat java.base/java.lang.reflect.Method.invoke(Method.java:578)","\tat org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:52)","\tat org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:124)","\tat org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:167)","\tat org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:219)","\tat org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:79)","\tat org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:469)","\tat org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:391)","\tat org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:80)","\tat org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:253)","\tat org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)","\tat org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)","\tat org.glassfish.jersey.internal.Errors.process(Errors.java:292)","\tat org.glassfish.jersey.internal.Errors.process(Errors.java:274)","\tat org.glassfish.jersey.internal.Errors.process(Errors.java:244)","\tat org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)","\tat org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:232)","\tat org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:680)","\tat org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:394)","\tat org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346)","\tat org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:366)","\tat org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:319)","\tat org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205)","\tat org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:763)","\tat org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:569)","\tat org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)","\tat org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1377)","\tat org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)","\tat org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:507)","\tat org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)","\tat org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1292)","\tat org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)","\tat org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)","\tat org.eclipse.jetty.server.Server.handle(Server.java:501)","\tat org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383)","\tat org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:556)","\tat org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375)","\tat org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273)","\tat org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)","\tat org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)","\tat org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)","\tat org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)","\tat org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)","\tat org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)","\tat org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)","\tat org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375)","\tat org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)","\tat org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)","\tat java.base/java.lang.Thread.run(Thread.java:1589)"]}
  [Create Connection]          : NOT_EXECUTED

Scenario actions    :
  [Sync Connection]            : NOT_EXECUTED
  [Update Source version]      : NOT_EXECUTED
  [Sync Connection]            : NOT_EXECUTED


2022-08-29 21:48:51 INFO i.a.t.TestingTool(main):28 - Testing tool execution finished!

Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

See https://docs.gradle.org/7.2/userguide/command_line_interface.html#sec:command_line_warnings

Execution optimizations have been disabled for 1 invalid unit(s) of work during this build to ensure correctness.
Please consult deprecation warnings for more details.

BUILD SUCCESSFUL in 6s
5 actionable tasks: 2 executed, 3 up-to-date
2:48:51 PM: Execution finished ':TestingTool.main()'.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.