You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2022/03/30 02:20:16 UTC

[skywalking-python] branch master updated: Add E2E coverage for Trace and Logging (#199)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-python.git


The following commit(s) were added to refs/heads/master by this push:
     new 95f4101  Add E2E coverage for Trace and Logging (#199)
95f4101 is described below

commit 95f4101dc89c20b9fe5bce44dcf3e08e772f1a00
Author: Superskyyy <Su...@outlook.com>
AuthorDate: Tue Mar 29 22:20:10 2022 -0400

    Add E2E coverage for Trace and Logging (#199)
---
 .github/workflows/CI.yaml                          | 213 ++++++++++++++++++---
 .github/workflows/dead-link-checker.yaml           |   8 +-
 Makefile                                           |   2 +-
 docker/Dockerfile                                  |   5 +-
 docker/Makefile                                    |  12 +-
 docs/en/setup/Container.md                         |   2 +-
 setup.py                                           |   2 +-
 skywalking/__init__.py                             |   2 +-
 skywalking/agent/__init__.py                       |   3 +-
 skywalking/client/grpc.py                          |   1 +
 skywalking/client/http.py                          |   2 +-
 skywalking/plugins/sw_fastapi.py                   |   2 +-
 Dockerfile => tests/e2e/base/Dockerfile.e2e        |  21 +-
 Dockerfile => tests/e2e/base/__init__.py           |  12 --
 Dockerfile => tests/e2e/base/consumer/__init__.py  |  12 --
 Dockerfile => tests/e2e/base/consumer/consumer.py  |  30 ++-
 tests/e2e/base/docker-compose.base.yml             |  76 ++++++++
 Dockerfile => tests/e2e/base/provider/__init__.py  |  12 --
 tests/e2e/base/provider/provider.py                |  93 +++++++++
 tests/e2e/case/expected/logs-list.yml              |  57 ++++++
 .../e2e/case/expected/metrics-has-value.yml        |  17 +-
 .../e2e/case/expected/service-endpoint.yml         |  15 +-
 tests/e2e/case/expected/service-instance.yml       |  36 ++++
 Dockerfile => tests/e2e/case/expected/service.yml  |  25 +--
 tests/e2e/case/expected/trace-artist-detail.yml    | 101 ++++++++++
 .../e2e/case/expected/traces-list.yml              |  25 +--
 .../e2e/case/grpc/docker-compose.yml               |  42 +++-
 tests/e2e/case/grpc/e2e.yaml                       |  92 +++++++++
 .../case/http/docker-compose.yml}                  |  58 +++---
 tests/e2e/case/http/e2e.yaml                       |  92 +++++++++
 tests/e2e/case/kafka/docker-compose.yml            | 122 ++++++++++++
 tests/e2e/case/kafka/e2e.yaml                      |  92 +++++++++
 Dockerfile => tests/e2e/script/env                 |  14 +-
 tests/e2e/script/prepare/install-swctl.sh          |  33 ++++
 tests/e2e/script/prepare/install-yq.sh             |  30 +++
 tests/e2e/script/prepare/install.sh                |  35 ++++
 Dockerfile => tests/plugin/Dockerfile.plugin       |   6 +-
 tests/plugin/docker-compose.base.yml               |   6 +-
 38 files changed, 1219 insertions(+), 189 deletions(-)

diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml
index 12a0de3..f022756 100644
--- a/.github/workflows/CI.yaml
+++ b/.github/workflows/CI.yaml
@@ -1,10 +1,10 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
 #
 #     http://www.apache.org/licenses/LICENSE-2.0
 #
@@ -13,79 +13,236 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-#
 
 name: CI
 
 on:
+  pull_request:
   push:
     branches:
       - master
-  pull_request:
-#  schedule: TODO: unpin minor lib versions and check weekly
-#    - 0 0 0 ? * FRI *
+  schedule:
+    - cron: '0 18 * * *'
+
 concurrency:
-  group: ci-it-${{ github.event.pull_request.number || github.ref }}
+  group: CI-plugin-e2e-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
 
 jobs:
   license-and-lint:
+    # Always check license-and-lint!
     name: License and Lint
     runs-on: ubuntu-latest
     steps:
       - name: Checkout source codes
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           submodules: true
       - name: Check License
-        uses: apache/skywalking-eyes@49d536241d6fe8f92400702b08710514dc298cd4
+        uses: apache/skywalking-eyes@main
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
       - name: Lint codes
         run: make lint
-  prep-plugin-and-unit-tests:
-    name: Prepare Plugin and Unit Tests
+
+  changes:
+    # Check if any file related to Agent/ CI behavior is changed
+    # set outputs for other jobs to access for if conditions
+    runs-on: ubuntu-latest
     needs: license-and-lint
+    timeout-minutes: 10
+    outputs:
+      agent: ${{ steps.filter.outputs.agent }}
+    steps:
+      - name: Check for file changes
+        uses: getsentry/paths-filter@v2
+        id: filter
+        with:
+          token: ${{ github.token }}
+          # The following filters indicate a category along with
+          # the files that should not be ignored by CI when modified.
+          filters: |
+            agent:
+              - '.github/**/*.yaml'
+              - '**/*.py'
+              - '**/Dockerfile*'
+              - '**/Makefile'
+              - 'protocol/**'
+              - 'tests/**'
+              - '**/*.bat'
+              - '**/*.sh'
+              - '**/*.ps1'
+              - '**/requirements*.text'
+              - '**/*.cfg'
+          list-files: json  # logs matched files
+
+  # Only run the Plugin and E2E jobs if there are essential changes as stated above
+  prep-plugin-and-unit-tests:
+    # prep step for plugin and unit test
+    name: Prepare Plugin and UT Matrix
+    needs: [ license-and-lint, changes ]
+    if: ${{ needs.changes.outputs.agent == 'true' }}
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - id: set-matrix
         run: |
           sudo apt-get install jq
           echo "::set-output name=matrix::$(bash tests/gather_test_paths.sh)"
     outputs:
       matrix: ${{ steps.set-matrix.outputs.matrix }}
+
+  docker-plugin:
+    # build docker image for plugin tests, with matrix of Python versions
+    name: Construct Agent Plugin Test Images
+    needs: [ license-and-lint, changes, prep-plugin-and-unit-tests ]
+    if: ${{ needs.changes.outputs.agent == 'true' }}
+    runs-on: ubuntu-latest
+    strategy:
+      matrix: # may support pypy in the future
+        python-version: [ "3.6", "3.7", "3.8", "3.9", "3.10" ]
+      fail-fast: false
+    env:
+      BASE_PYTHON_IMAGE: ${{ matrix.python-version }}
+    steps:
+      - name: Checkout source codes
+        uses: actions/checkout@v3
+        with:
+          submodules: true
+      - name: Build SkyWalking Python agent base plugin image
+        run: |
+          docker build --build-arg BASE_PYTHON_IMAGE -t apache/skywalking-python-agent:latest-plugin --no-cache . -f tests/plugin/Dockerfile.plugin
+          docker save -o docker-images-skywalking-python-plugin-${{ matrix.python-version }}.tar apache/skywalking-python-agent:latest-plugin
+      - name: Upload docker image with specific python version
+        uses: actions/upload-artifact@v3
+        with:
+          name: docker-images-skywalking-python-plugin-${{ matrix.python-version }}
+          path: docker-images-skywalking-python-plugin-${{ matrix.python-version }}.tar
+          retention-days: 1
+
   plugin-and-unit-tests:
-    name: Plugin and Unit Tests
-    needs: prep-plugin-and-unit-tests
+    # Execute plugin tests with matrix of Python versions and matrix of cases
+    # this step is only run after passing building images + prep matrix + changes
+    name: Execute Agent Plugin and Unit Tests
+    needs: [ license-and-lint, changes, docker-plugin, prep-plugin-and-unit-tests ]
+    if: ${{ needs.changes.outputs.agent == 'true' }}
     runs-on: ubuntu-latest
     timeout-minutes: 30
     strategy:
       matrix:
-        python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
+        python-version: [ "3.6", "3.7", "3.8", "3.9", "3.10" ]
         test-path: ${{fromJson(needs.prep-plugin-and-unit-tests.outputs.matrix)}}
       fail-fast: false
     env:
-      SW_PYTHON_VERSION: ${{ matrix.python-version }}
+      BASE_PYTHON_IMAGE: ${{ matrix.python-version }}
     steps:
       - name: Checkout source codes
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           submodules: true
+      - name: Pull SkyWalking Python agent base image
+        uses: actions/download-artifact@v3
+        with:
+          name: docker-images-skywalking-python-plugin-${{ matrix.python-version }}
+          path: docker-images
+      - name: Load docker images
+        run: find docker-images -name "*.tar" -exec docker load -i {} \;
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v2
+        # This step is crucial for correct plugin matrix in test orchestration
+        uses: actions/setup-python@v3
         with:
           python-version: ${{ matrix.python-version }}
-      - name: Set up dependencies
-        run: make setup install
       - name: Run unit tests
         run: |
           make test-parallel-setup
           python3 -m pytest -v ${{ matrix.test-path }}
+
+  docker-e2e:
+    # build docker image for E2E tests, single Python version for now.
+    name: Construct Agent E2E Test Images
+    needs: [ license-and-lint, changes ]
+    if: ${{ needs.changes.outputs.agent == 'true' }}
+    runs-on: ubuntu-latest
+    timeout-minutes: 10
+    steps:
+      - name: Checkout source codes
+        uses: actions/checkout@v3
+        with:
+          submodules: true
+      - name: Build SkyWalking Python agent base e2e image
+        run: |
+          docker build --build-arg BASE_PYTHON_IMAGE -t apache/skywalking-python-agent:latest-e2e --no-cache . -f tests/e2e/base/Dockerfile.e2e
+          docker save -o docker-images-skywalking-python-e2e.tar apache/skywalking-python-agent:latest-e2e
+        env: # may support pypy in the future
+          BASE_PYTHON_IMAGE: 3.7
+      - name: Upload docker image
+        uses: actions/upload-artifact@v3
+        with:
+          name: docker-images-skywalking-python-e2e
+          path: docker-images-skywalking-python-e2e.tar
+          retention-days: 1
+
+  e2e-tests:
+    # execute E2E tests with SkyWalking-infra-e2e with a matrix of agent protocols
+    name: Basic function + ${{ matrix.case.name }} Transport (Python3.7)
+    needs: [ license-and-lint, changes, docker-e2e ]
+    if: ${{ needs.changes.outputs.agent == 'true' }}
+    runs-on: ubuntu-latest
+    timeout-minutes: 20
+    strategy:
+      matrix:
+        case:
+          - name: gRPC
+            path: tests/e2e/case/grpc/e2e.yaml
+          - name: HTTP
+            path: tests/e2e/case/http/e2e.yaml
+          - name: Kafka
+            path: tests/e2e/case/kafka/e2e.yaml
+      fail-fast: false
+    steps:
+      - name: Checkout source codes
+        uses: actions/checkout@v3
+        with:
+          submodules: true
+      - name: Pull SkyWalking Python agent base image
+        uses: actions/download-artifact@v3
+        with:
+          name: docker-images-skywalking-python-e2e
+          path: docker-images
+      - name: Load docker images
+        run: find docker-images -name "*.tar" -exec docker load -i {} \;
+      - name: Setup go
+        uses: actions/setup-go@v2
+        with:
+          go-version: '1.16'
+      - name: Run E2E Tests
+        uses: apache/skywalking-infra-e2e@main
+        with:
+          log-dir: /tmp/e2e-logs
+          e2e-file: ${{ matrix.case.path }}
+      - name: Upload Logs
+        uses: actions/upload-artifact@v3
+        if: ${{ failure() }}
+        with:
+          name: e2e_logs
+          path: "${{ env.SW_INFRA_E2E_LOG_DIR }}"
+
   CheckStatus:
+    # a required check that must pass before merging a PR
     runs-on: ubuntu-latest
     timeout-minutes: 60
-    needs: [plugin-and-unit-tests]
+    # wait upon them regardless of success or skipped or failure
+    if: ${{ always() }}
+    needs: [ license-and-lint, changes, plugin-and-unit-tests, e2e-tests ]
     steps:
-      - name: Nothing
-        run: echo "Just to make the GitHub merge button green"
\ No newline at end of file
+      - name: Merge Requirement
+        # check license, lint, plugin and e2e tests, then naturally exits 0
+        run: |
+          execute=${{ needs.changes.outputs.agent }}
+          lintResults=${{ needs.license-and-lint.result }}
+          pluginResults=${{ needs.plugin-and-unit-tests.result }};
+          e2eResults=${{ needs.e2e-tests.result }};
+          [[ ${lintResults} == 'success' ]] || exit 2;
+          [[ ${pluginResults} == 'success' ]] || [[ ${execute} != 'true' && ${pluginResults} == 'skipped' ]] || exit 3;
+          [[ ${e2eResults} == 'success' ]] || [[ ${execute} != 'true' && ${e2eResults} == 'skipped' ]] || exit 4;
+          exit 0;
diff --git a/.github/workflows/dead-link-checker.yaml b/.github/workflows/dead-link-checker.yaml
index 1934585..4d3fd12 100644
--- a/.github/workflows/dead-link-checker.yaml
+++ b/.github/workflows/dead-link-checker.yaml
@@ -14,10 +14,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Dead link checker is always run on all files
 name: Dead Link Checker
 
 on:
   pull_request:
+  push:
+    branches:
+      - master
+  schedule:
+    - cron: '0 18 * * *'
 
 concurrency:
   group: dlc-${{ github.event.pull_request.number || github.ref }}
@@ -28,7 +34,7 @@ jobs:
     runs-on: ubuntu-latest
     timeout-minutes: 30
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
       - run: sudo npm install -g markdown-link-check
       - run: |
           for file in $(find . -name "*.md"); do
diff --git a/Makefile b/Makefile
index 71ab7a0..f90bdbb 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ setup:
 	python3 -m pip install --upgrade pip
 	python3 -m pip install grpcio --ignore-installed
 
-setup-test: setup
+setup-test: setup gen
 	pip3 install -e .[test]
 
 gen:
diff --git a/docker/Dockerfile b/docker/Dockerfile
index f610b38..68a99b6 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -14,13 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG BASE_IMAGE
+ARG BASE_PYTHON_IMAGE
 
-FROM ${BASE_IMAGE}
+FROM ${BASE_PYTHON_IMAGE}
 
 ARG SW_PYTHON_AGENT_PROTOCOL
 ARG SW_PYTHON_AGENT_VERSION
 
 RUN pip install --no-cache-dir "apache-skywalking[${SW_PYTHON_AGENT_PROTOCOL}]==${SW_PYTHON_AGENT_VERSION}"
 
+# So that the agent can be auto-started when container is started
 ENTRYPOINT ["sw-python", "run"]
diff --git a/docker/Makefile b/docker/Makefile
index eeba161..3fb5e2c 100644
--- a/docker/Makefile
+++ b/docker/Makefile
@@ -20,11 +20,11 @@ P := grpc http kafka
 
 TARGETS := py3.6 py3.7 py3.8 py3.9 py3.10
 
-py3.6: BASE_IMAGE = python:3.6
-py3.7: BASE_IMAGE = python:3.7
-py3.8: BASE_IMAGE = python:3.8
-py3.9: BASE_IMAGE = python:3.9
-py3.9: BASE_IMAGE = python:3.10
+py3.6: BASE_PYTHON_IMAGE = python:3.6
+py3.7: BASE_PYTHON_IMAGE = python:3.7
+py3.8: BASE_PYTHON_IMAGE = python:3.8
+py3.9: BASE_PYTHON_IMAGE = python:3.9
+py3.9: BASE_PYTHON_IMAGE = python:3.10
 
 PUSH_TARGETS := $(TARGETS:%=push-%)
 
@@ -36,7 +36,7 @@ push: $(PUSH_TARGETS)
 $(TARGETS):
 	for p in $(P); do \
 		$(D) build $(SW_BUILD_ARGS) \
-				--build-arg BASE_IMAGE=$(BASE_IMAGE) \
+				--build-arg BASE_PYTHON_IMAGE=$(BASE_PYTHON_IMAGE) \
 				--build-arg SW_PYTHON_AGENT_PROTOCOL=$$p \
 				--build-arg SW_PYTHON_AGENT_VERSION=${AGENT_VERSION} \
 				-t apache/skywalking-python:${AGENT_VERSION}-$$p-$@ \
diff --git a/docs/en/setup/Container.md b/docs/en/setup/Container.md
index a904321..1816a2d 100644
--- a/docs/en/setup/Container.md
+++ b/docs/en/setup/Container.md
@@ -35,7 +35,7 @@ it should be adopted and bootstrapped automatically through the `sw-python` CLI.
 Provide the following arguments to build your own image from the dockerfile.
 
 ```text
-BASE_IMAGE # the Python base image to build upon
+BASE_PYTHON_IMAGE # the Python base image to build upon
 SW_PYTHON_AGENT_VERSION # agent version to be pulled from PyPI
 SW_PYTHON_AGENT_PROTOCOL # agent protocol - grpc/ http/ kafka
 ```
diff --git a/setup.py b/setup.py
index 8132709..5683d3c 100644
--- a/setup.py
+++ b/setup.py
@@ -51,7 +51,7 @@ setup(
             'requests>=2.26.0',
         ],
         'kafka': [
-            'kafka',
+            'kafka-python',
         ],
     },
     classifiers=[
diff --git a/skywalking/__init__.py b/skywalking/__init__.py
index 221a643..31b218b 100644
--- a/skywalking/__init__.py
+++ b/skywalking/__init__.py
@@ -45,7 +45,7 @@ class Component(Enum):
     Celery = 7011
     Falcon = 7012
     MysqlClient = 7013
-    FastApi = 7014
+    FastAPI = 7014
 
 
 class Layer(Enum):
diff --git a/skywalking/agent/__init__.py b/skywalking/agent/__init__.py
index 580937d..f487e9e 100644
--- a/skywalking/agent/__init__.py
+++ b/skywalking/agent/__init__.py
@@ -21,8 +21,6 @@ from queue import Queue, Full
 from threading import Thread, Event
 from typing import TYPE_CHECKING
 
-from skywalking.protocol.logging.Logging_pb2 import LogData
-
 from skywalking import config, plugins
 from skywalking import loggings
 from skywalking import profile
@@ -31,6 +29,7 @@ from skywalking.command import command_service
 from skywalking.loggings import logger
 from skywalking.profile.profile_task import ProfileTask
 from skywalking.profile.snapshot import TracingThreadSnapshot
+from skywalking.protocol.logging.Logging_pb2 import LogData
 
 if TYPE_CHECKING:
     from skywalking.trace.context import Segment
diff --git a/skywalking/client/grpc.py b/skywalking/client/grpc.py
index b09c774..5c743c5 100644
--- a/skywalking/client/grpc.py
+++ b/skywalking/client/grpc.py
@@ -38,6 +38,7 @@ class GrpcServiceManagementClient(ServiceManagementClient):
         self.service_stub = ManagementServiceStub(channel)
 
     def send_instance_props(self):
+        # TODO: other properties periodically | matching behavior of java agent
         self.service_stub.reportInstanceProperties(InstanceProperties(
             service=config.service_name,
             serviceInstance=config.service_instance,
diff --git a/skywalking/client/http.py b/skywalking/client/http.py
index a3ae5d8..be60bd7 100644
--- a/skywalking/client/http.py
+++ b/skywalking/client/http.py
@@ -40,7 +40,7 @@ class HttpServiceManagementClient(ServiceManagementClient):
             'service': config.service_name,
             'serviceInstance': config.service_instance,
             'properties': [
-                {'key': 'language', 'value': 'Python'},
+                {'key': 'language', 'value': 'python'},
             ]
         })
         if logger_debug_enabled:
diff --git a/skywalking/plugins/sw_fastapi.py b/skywalking/plugins/sw_fastapi.py
index e0033ed..99a9550 100644
--- a/skywalking/plugins/sw_fastapi.py
+++ b/skywalking/plugins/sw_fastapi.py
@@ -55,7 +55,7 @@ def install():
 
         with span:
             span.layer = Layer.Http
-            span.component = Component.FastApi
+            span.component = Component.FastAPI
             span.peer = f'{req.client.host}:{req.client.port}'
             span.tag(TagHttpMethod(method))
             span.tag(TagHttpURL(req.url._url.split('?')[0]))
diff --git a/Dockerfile b/tests/e2e/base/Dockerfile.e2e
similarity index 61%
copy from Dockerfile
copy to tests/e2e/base/Dockerfile.e2e
index 5e03aa1..6289ce5 100644
--- a/Dockerfile
+++ b/tests/e2e/base/Dockerfile.e2e
@@ -13,14 +13,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG SW_PYTHON_VERSION
+# Builds -> skywalking-agent:latest-e2e
+ARG BASE_PYTHON_IMAGE
 
-FROM python:${SW_PYTHON_VERSION}
+FROM python:${BASE_PYTHON_IMAGE}
 
-ARG ROOT=.
+VOLUME /services
 
-WORKDIR /agent
+COPY tests/e2e/base/consumer/consumer.py /services/
+COPY tests/e2e/base/provider/provider.py /services/
 
-ADD $ROOT /agent
+# Copy the project and build
+COPY . /skywalking-python/
+RUN cd /skywalking-python && make install
 
-RUN make setup-test install
+RUN pip install requests kafka-python
+# Extra dependencies for e2e services
+RUN pip install fastapi uvicorn aiohttp
+
+# Entrypoint with agent attached
+Entrypoint ["sw-python", "run"]
diff --git a/Dockerfile b/tests/e2e/base/__init__.py
similarity index 85%
copy from Dockerfile
copy to tests/e2e/base/__init__.py
index 5e03aa1..ae1e83e 100644
--- a/Dockerfile
+++ b/tests/e2e/base/__init__.py
@@ -12,15 +12,3 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /agent
-
-ADD $ROOT /agent
-
-RUN make setup-test install
diff --git a/Dockerfile b/tests/e2e/base/consumer/__init__.py
similarity index 85%
copy from Dockerfile
copy to tests/e2e/base/consumer/__init__.py
index 5e03aa1..ae1e83e 100644
--- a/Dockerfile
+++ b/tests/e2e/base/consumer/__init__.py
@@ -12,15 +12,3 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /agent
-
-ADD $ROOT /agent
-
-RUN make setup-test install
diff --git a/Dockerfile b/tests/e2e/base/consumer/consumer.py
similarity index 50%
copy from Dockerfile
copy to tests/e2e/base/consumer/consumer.py
index 5e03aa1..68daa36 100644
--- a/Dockerfile
+++ b/tests/e2e/base/consumer/consumer.py
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.
@@ -12,15 +13,32 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+#
 
-ARG SW_PYTHON_VERSION
+"""
+This module contains the Consumer part of the e2e tests.
+consumer (FastAPI) -> consumer (AIOHTTP) -> provider (FastAPI + logging_with_exception)
+"""
+import aiohttp
+import uvicorn
+from fastapi import FastAPI
+from fastapi import Request
 
-FROM python:${SW_PYTHON_VERSION}
+app = FastAPI()
 
-ARG ROOT=.
 
-WORKDIR /agent
+@app.get('/artist')
+@app.post('/artist')
+async def application(request: Request):
+    try:
+        payload = await request.json()
+        async with aiohttp.ClientSession() as session:
+            async with session.post('http://provider:9090/artist', data=payload) as response:
+                return await response.json()
+    except Exception:  # noqa
+        return {'message': 'Error'}
 
-ADD $ROOT /agent
 
-RUN make setup-test install
+if __name__ == '__main__':
+    # noinspection PyTypeChecker
+    uvicorn.run(app, host='0.0.0.0', port=9090)
diff --git a/tests/e2e/base/docker-compose.base.yml b/tests/e2e/base/docker-compose.base.yml
new file mode 100644
index 0000000..65608ec
--- /dev/null
+++ b/tests/e2e/base/docker-compose.base.yml
@@ -0,0 +1,76 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version: '2.1'
+
+services:
+  # The following services are inherited by three protocols for testing
+  oap:
+    image: ghcr.io/apache/skywalking/oap:${SW_OAP_COMMIT}
+    # Python agent supports gRPC/ HTTP/ Kafka reporting
+    expose:
+      - 11800 # gRPC
+      - 12800 # HTTP
+    networks:
+      - e2e
+    healthcheck: # python base image has no nc command
+      test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/11800" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+
+  provider:
+    # Previously built in CI
+    image: apache/skywalking-python-agent:latest-e2e
+    expose:
+      - 9090
+    networks:
+      - e2e
+    environment:
+      SW_AGENT_NAME: e2e-service-provider
+      SW_AGENT_INSTANCE: provider1
+      SW_AGENT_LOGGING_LEVEL: DEBUG
+      SW_AGENT_LOG_REPORTER_ACTIVE: "True"
+      SW_AGENT_LOG_REPORTER_LEVEL: WARNING
+    healthcheck:
+      test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9090" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+    command: [ "python3", "/services/provider.py" ]
+
+
+  consumer:
+    image: apache/skywalking-python-agent:latest-e2e
+    expose:
+      - 9090
+    networks:
+      - e2e
+    environment:
+      SW_AGENT_NAME: e2e-service-consumer
+      SW_AGENT_INSTANCE: consumer1
+      SW_AGENT_LOGGING_LEVEL: DEBUG
+      SW_AGENT_LOG_REPORTER_ACTIVE: "True"
+      SW_AGENT_LOG_REPORTER_LEVEL: WARNING
+    healthcheck:
+      test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9090" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+    command: [ "python3", "/services/consumer.py" ]
+
+networks:
+  e2e:
diff --git a/Dockerfile b/tests/e2e/base/provider/__init__.py
similarity index 85%
copy from Dockerfile
copy to tests/e2e/base/provider/__init__.py
index 5e03aa1..ae1e83e 100644
--- a/Dockerfile
+++ b/tests/e2e/base/provider/__init__.py
@@ -12,15 +12,3 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /agent
-
-ADD $ROOT /agent
-
-RUN make setup-test install
diff --git a/tests/e2e/base/provider/provider.py b/tests/e2e/base/provider/provider.py
new file mode 100644
index 0000000..e3e4195
--- /dev/null
+++ b/tests/e2e/base/provider/provider.py
@@ -0,0 +1,93 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+This module contains the Provider part of the e2e tests.
+consumer (FastAPI) -> consumer (AIOHTTP) -> provider (FastAPI + logging_with_exception)
+We also cover the usage of logging interception in this module.
+"""
+import io
+import logging
+import random
+import time
+import traceback
+
+import uvicorn
+from fastapi import FastAPI
+
+
+class E2EProviderFormatter(logging.Formatter):
+    """
+    User defined formatter should in no way be
+    interfered by the log reporter formatter.
+    """
+
+    def format(self, record):
+        result = super().format(record)
+        return 'e2e_provider:=' + result
+
+    def formatException(self, ei):  # noqa
+        """
+        Mock user defined formatter which limits the traceback depth
+        to None -> meaning it will not involve trackback at all.
+        but the agent should still be able to capture the traceback
+        at default level of 5 by ignoring the cache.
+        """
+        sio = io.StringIO()
+        tb = ei[2]
+        traceback.print_exception(ei[0], ei[1], tb, None, sio)
+        s = sio.getvalue()
+        sio.close()
+        if s[-1:] == '\n':
+            s = s[:-1]
+        return s
+
+
+formatter = E2EProviderFormatter(logging.BASIC_FORMAT)
+stream_handler = logging.StreamHandler()
+stream_handler.setFormatter(formatter)
+
+e2e_provider_logger = logging.getLogger('__name__')
+e2e_provider_logger.setLevel(logging.INFO)
+e2e_provider_logger.addHandler(stream_handler)
+
+app = FastAPI()
+
+
+@app.get('/artist')
+@app.post('/artist')
+async def application():
+    time.sleep(random.random())
+    # Exception is reported with trackback depth of 5 (default)
+    try:
+        raise Exception('E2E Provider Exception Text!')
+    except Exception:  # noqa
+        e2e_provider_logger.exception('E2E Provider Exception, this is reported!')
+    # FIXME - a temp workaround of a flaky test related to issue #8752
+    # Later arrived logs are at top of list, thus q
+    time.sleep(0.5)
+    # Warning is reported
+    e2e_provider_logger.warning('E2E Provider Warning, this is reported!')
+    # Debug is not reported according to default agent setting
+    e2e_provider_logger.debug('E2E Provider Debug, this is not reported!')
+
+    return {'artist': 'Luis Fonsi'}
+
+
+if __name__ == '__main__':
+    # noinspection PyTypeChecker
+    uvicorn.run(app, host='0.0.0.0', port=9090)
diff --git a/tests/e2e/case/expected/logs-list.yml b/tests/e2e/case/expected/logs-list.yml
new file mode 100644
index 0000000..e853c7e
--- /dev/null
+++ b/tests/e2e/case/expected/logs-list.yml
@@ -0,0 +1,57 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+logs:
+  {{- contains .logs }}
+  - servicename: e2e-service-provider
+    serviceid: {{ b64enc "e2e-service-provider" }}.1
+    serviceinstancename: provider1
+    serviceinstanceid: {{ b64enc "e2e-service-provider" }}.1_{{ b64enc "provider1" }}
+    endpointname: null
+    endpointid: null
+    traceid: {{ notEmpty .traceid }}
+    timestamp: {{ gt .timestamp 0 }}
+    contenttype: TEXT
+    content: {{ regexp .content "(?s).+E2E Provider Warning.+"}}
+    tags:
+    {{- contains .tags }}
+    - key: level
+      value: WARNING
+    - key: logger
+      value: {{ notEmpty .value }}
+    - key: thread
+      value: {{ notEmpty .value }}
+    {{- end }}
+  - servicename: e2e-service-provider
+    serviceid: {{ b64enc "e2e-service-provider" }}.1
+    serviceinstancename: provider1
+    serviceinstanceid: {{ b64enc "e2e-service-provider" }}.1_{{ b64enc "provider1" }}
+    endpointname: null
+    endpointid: null
+    traceid: {{ notEmpty .traceid }}
+    timestamp: {{ gt .timestamp 0 }}
+    contenttype: TEXT
+    content: {{ regexp .content "(?s).+E2E Provider Exception.+Traceback(most recent call last).+" }}
+    tags:
+    {{- contains .tags }}
+    - key: level
+      value: ERROR
+    - key: logger
+      value: {{ notEmpty .value }}
+    - key: thread
+      value: {{ notEmpty .value }}
+    {{- end }}
+  {{- end }}
+total: 2
diff --git a/Dockerfile b/tests/e2e/case/expected/metrics-has-value.yml
similarity index 85%
copy from Dockerfile
copy to tests/e2e/case/expected/metrics-has-value.yml
index 5e03aa1..05696e2 100644
--- a/Dockerfile
+++ b/tests/e2e/case/expected/metrics-has-value.yml
@@ -13,14 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /agent
-
-ADD $ROOT /agent
-
-RUN make setup-test install
+{{- contains . }}
+- key: {{ notEmpty .key }}
+  value: {{ ge .value 0 }}
+- key: {{ notEmpty .key }}
+  value: {{ ge .value 1 }}
+{{- end }}
diff --git a/Dockerfile b/tests/e2e/case/expected/service-endpoint.yml
similarity index 85%
copy from Dockerfile
copy to tests/e2e/case/expected/service-endpoint.yml
index 5e03aa1..a8d8ab8 100644
--- a/Dockerfile
+++ b/tests/e2e/case/expected/service-endpoint.yml
@@ -13,14 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /agent
-
-ADD $ROOT /agent
-
-RUN make setup-test install
+  {{- contains . }}
+- id: {{ b64enc "e2e-service-provider" }}.1_{{ b64enc "/artist" }}
+  name: /artist
+  {{- end }}
diff --git a/tests/e2e/case/expected/service-instance.yml b/tests/e2e/case/expected/service-instance.yml
new file mode 100644
index 0000000..36aae48
--- /dev/null
+++ b/tests/e2e/case/expected/service-instance.yml
@@ -0,0 +1,36 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+{{- contains . }}
+- id: {{ b64enc "e2e-service-provider" }}.1_{{ b64enc "provider1" }}
+  name: {{ notEmpty .name }}
+  attributes:
+    {{- contains .attributes }}
+# TODO: The following attributes implementation is missing
+#    - name: OS Name
+#      value: linux
+#    - name: hostname
+#      value: {{ notEmpty .value }}
+#    - name: Process No.
+#      value: {{ notEmpty .value }}
+    - name: ipv4s
+      value: ""
+    {{- end}}
+  language: PYTHON
+  instanceuuid: {{ b64enc "e2e-service-provider" }}.1_{{ b64enc "provider1" }}
+  layer: GENERAL
+{{- end}}
diff --git a/Dockerfile b/tests/e2e/case/expected/service.yml
similarity index 71%
copy from Dockerfile
copy to tests/e2e/case/expected/service.yml
index 5e03aa1..7517f71 100644
--- a/Dockerfile
+++ b/tests/e2e/case/expected/service.yml
@@ -13,14 +13,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /agent
-
-ADD $ROOT /agent
-
-RUN make setup-test install
+- id: {{ b64enc "e2e-service-provider" }}.1
+  name: e2e-service-provider
+  shortname: e2e-service-provider
+  normal: true
+  layers:
+    - GENERAL
+  group: ""
+- id: {{ b64enc "e2e-service-consumer" }}.1
+  name: e2e-service-consumer
+  shortname: e2e-service-consumer
+  normal: true
+  layers:
+    - GENERAL
+  group: ""
diff --git a/tests/e2e/case/expected/trace-artist-detail.yml b/tests/e2e/case/expected/trace-artist-detail.yml
new file mode 100644
index 0000000..79c6a15
--- /dev/null
+++ b/tests/e2e/case/expected/trace-artist-detail.yml
@@ -0,0 +1,101 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+spans:
+{{- contains .spans }}
+- traceid: {{ notEmpty .traceid }}
+  segmentid: {{ notEmpty .segmentid }}
+  spanid: {{ .spanid }}
+  parentspanid: {{ .parentspanid }}
+  refs: []
+  servicecode: e2e-service-consumer
+  serviceinstancename: consumer1
+  starttime: {{ gt .starttime 0 }}
+  endtime: {{ gt .endtime 0 }}
+  endpointname: /artist
+  type: Entry
+  peer: {{ notEmpty .peer }}
+  component: FastAPI
+  iserror: false
+  layer: Http
+  tags:
+    {{- contains .tags }}
+    - key: http.method
+      value: POST
+    - key: http.url
+      value: {{ notEmpty .value }}
+    - key: http.status.code
+      value: "200"
+    {{- end }}
+  logs: []
+- traceid: {{ notEmpty .traceid }}
+  segmentid: {{ notEmpty .segmentid }}
+  spanid: {{ .spanid }}
+  parentspanid: {{ .parentspanid }}
+  refs: []
+  servicecode: e2e-service-consumer
+  serviceinstancename: consumer1
+  starttime: {{ gt .starttime 0 }}
+  endtime: {{ gt .endtime 0 }}
+  endpointname: /artist
+  type: Exit
+  peer: provider:9090
+  component: AioHttp
+  iserror: false
+  layer: Http
+  tags:
+    {{- contains .tags }}
+    - key: http.method
+      value: POST
+    - key: http.url
+      value: http://provider:9090/artist
+    - key: http.status.code
+      value: "200"
+    {{- end }}
+  logs: []
+- traceid: {{ notEmpty .traceid }}
+  segmentid: {{ notEmpty .segmentid }}
+  spanid: {{ .spanid }}
+  parentspanid: {{ .parentspanid }}
+  refs:
+    {{- contains .refs }}
+    - traceid: {{ notEmpty .traceid }}
+      parentsegmentid: {{ .parentsegmentid }}
+      parentspanid: {{ .parentspanid }}
+      type: CROSS_PROCESS
+    {{- end }}
+  servicecode: e2e-service-provider
+  serviceinstancename: provider1
+  starttime: {{ gt .starttime 0 }}
+  endtime: {{ gt .endtime 0 }}
+  endpointname: /artist
+  type: Entry
+  peer: {{ notEmpty .peer }}
+  component: FastAPI
+  iserror: false
+  layer: Http
+  tags:
+    {{- contains .tags }}
+    - key: http.method
+      value: POST
+    - key: http.url
+      # Change OAP side e2e from url -> http.url # why is oap e2e passing?? todo check with custom e2e build
+      value: http://provider:9090/artist
+    - key: http.status.code
+      # Change OAP side e2e from status.code -> http.status.code
+      value: "200"
+    {{- end }}
+  logs: []
+{{- end }}
diff --git a/Dockerfile b/tests/e2e/case/expected/traces-list.yml
similarity index 70%
copy from Dockerfile
copy to tests/e2e/case/expected/traces-list.yml
index 5e03aa1..ac3c1a3 100644
--- a/Dockerfile
+++ b/tests/e2e/case/expected/traces-list.yml
@@ -13,14 +13,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /agent
-
-ADD $ROOT /agent
-
-RUN make setup-test install
+traces:
+  {{- contains .traces }}
+  - segmentid: {{ notEmpty .segmentid }}
+    endpointnames:
+    {{- contains .endpointnames }}
+      - /artist
+    {{- end }}
+    duration: {{ ge .duration 0 }}
+    start: {{ notEmpty .start}}
+    iserror: false
+    traceids:
+      - {{ (index .traceids 0) }}
+  {{- end }}
+total: {{ gt .total 0 }}
diff --git a/Dockerfile b/tests/e2e/case/grpc/docker-compose.yml
similarity index 53%
copy from Dockerfile
copy to tests/e2e/case/grpc/docker-compose.yml
index 5e03aa1..5a124d3 100644
--- a/Dockerfile
+++ b/tests/e2e/case/grpc/docker-compose.yml
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.
@@ -12,15 +13,40 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+#
 
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
+version: '2.1'
 
-WORKDIR /agent
+services:
+  oap:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: oap
+    ports:
+      - "12800"
+  provider:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: provider
+    ports:
+      - "9090"
+    environment:
+      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:11800
+    depends_on:
+      oap:
+        condition: service_healthy
 
-ADD $ROOT /agent
+  consumer:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: consumer
+    environment:
+      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:11800
+    ports:
+      - "9090"
+    depends_on:
+      provider:
+        condition: service_healthy
 
-RUN make setup-test install
+networks:
+  e2e:
\ No newline at end of file
diff --git a/tests/e2e/case/grpc/e2e.yaml b/tests/e2e/case/grpc/e2e.yaml
new file mode 100644
index 0000000..4933b5b
--- /dev/null
+++ b/tests/e2e/case/grpc/e2e.yaml
@@ -0,0 +1,92 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file is used to show how to write configuration files and can be used to test.
+
+setup:
+  env: compose
+  file: docker-compose.yml
+  timeout: 20m
+  init-system-environment: ../../script/env
+  steps:
+    - name: install yq
+      command: bash tests/e2e/script/prepare/install.sh yq
+    - name: install swctl
+      command: bash tests/e2e/script/prepare/install.sh swctl
+
+trigger:
+  action: http      # The action of the trigger. support HTTP invoke.
+  interval: 3s      # Trigger the action every 3 seconds.
+  times: 5          # Don't omit this!
+  url: http://${consumer_host}:${consumer_9090}/artist
+  method: POST       # Http trigger method.
+  headers:
+    "Content-Type": "application/json"
+  body: '{"song": "Despacito"}'
+
+verify:
+  # verify with retry strategy
+  retry:
+    # max retry count
+    count: 20
+    # the interval between two retries
+    interval: 5s
+  cases:
+    # basic check: service list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service ls
+      expected: ../expected/service.yml
+    # basic check: service metrics
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name service_sla --service-name=e2e-service-provider |yq e 'to_entries' -
+      expected: ../expected/metrics-has-value.yml
+    # basic check: service endpoint
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql endpoint list --service-name=e2e-service-provider
+      expected: ../expected/service-endpoint.yml
+    # basic check: service endpoint metrics
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name endpoint_cpm --endpoint-name=/artist --service-name=e2e-service-provider |yq e 'to_entries' -
+      expected: ../expected/metrics-has-value.yml
+
+    # service instance list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance list --service-name=e2e-service-provider
+      expected: ../expected/service-instance.yml
+
+    # TODO: Metric Collection Implementation is not merged https://github.com/apache/skywalking/issues/7084
+    # service instance pvm metrics TODO: PVM Collection Implementation needed https://github.com/apache/skywalking/issues/5944
+    # swctl --display yaml --base-url=http://localhost:12800/graphql metrics linear --name instance_jvm_thread_live_count --instance-name=provider1 --service-name=e2e-service-provider |yq e 'to_entries' -
+    #    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name instance_jvm_thread_live_count --instance-name=provider1 --service-name=e2e-service-provider |yq e 'to_entries' -
+    #      expected: ../expected/metrics-has-value.yml
+
+    # trace segment list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls
+      expected: ../expected/traces-list.yml
+
+    # trace detail
+    - query: |
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace $( \
+          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls --service-name=e2e-service-consumer\
+            | yq e '.traces | select(.[].endpointnames[0]=="/artist") | .[0].traceids[0]' -
+        )
+      expected: ../expected/trace-artist-detail.yml
+
+    # event list TODO: Events Implementation needed - no tracking issues yet
+    #    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql event list --service-name=e2e-service-provider --instance-name=provider1
+    #      expected: ../expected/event-list.yml
+
+    # logs list
+    - query: |
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql logs list --service-name=e2e-service-provider --trace-id=$( \
+            swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls \
+              | yq e '.traces | select(.[].endpointnames[0]=="/artist") | .[0].traceids[0]' -
+        )
+      expected: ../expected/logs-list.yml
diff --git a/tests/plugin/docker-compose.base.yml b/tests/e2e/case/http/docker-compose.yml
similarity index 52%
copy from tests/plugin/docker-compose.base.yml
copy to tests/e2e/case/http/docker-compose.yml
index e101cd6..41d93c8 100644
--- a/tests/plugin/docker-compose.base.yml
+++ b/tests/e2e/case/http/docker-compose.yml
@@ -1,4 +1,4 @@
-
+#
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.
@@ -18,30 +18,38 @@
 version: '2.1'
 
 services:
-  collector:
-    image: ghcr.io/apache/skywalking-agent-test-tool/mock-collector:092c6a3c753684b5a301baf5bcb1965f2dfaf79d
+  oap:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: oap
+    ports:
+      - "12800"
+
+  provider:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: provider
     ports:
-      - 19876:19876
-      - 12800:12800
-    networks:
-      - beyond
-    healthcheck:
-      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/12800"]
-      interval: 5s
-      timeout: 60s
-      retries: 120
+      - "9090"
+    environment: # HTTP endpoint
+      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:12800
+      SW_AGENT_PROTOCOL: http
+    depends_on:
+      oap:
+        condition: service_healthy
 
-  agent:
-    build:
-      context: ../..
-      args:
-        - SW_PYTHON_VERSION=${SW_PYTHON_VERSION:-latest}
-    image: skywalking-agent:ci
+  consumer:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: consumer
     environment:
-      SW_AGENT_COLLECTOR_BACKEND_SERVICES: collector:19876
-      SW_AGENT_LOGGING_LEVEL: DEBUG
-      # Agent test tool does not support profiling, TODO: address in e2e ref: #155
-      SW_AGENT_PROFILE_ACTIVE: 'False'
-    networks:
-      - beyond
-    command: ['python3', '/entrypoint.py']
+      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:12800
+      SW_AGENT_PROTOCOL: http
+    ports:
+      - "9090"
+    depends_on:
+      provider:
+        condition: service_healthy
+
+networks:
+  e2e:
\ No newline at end of file
diff --git a/tests/e2e/case/http/e2e.yaml b/tests/e2e/case/http/e2e.yaml
new file mode 100644
index 0000000..4933b5b
--- /dev/null
+++ b/tests/e2e/case/http/e2e.yaml
@@ -0,0 +1,92 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file is used to show how to write configuration files and can be used to test.
+
+setup:
+  env: compose
+  file: docker-compose.yml
+  timeout: 20m
+  init-system-environment: ../../script/env
+  steps:
+    - name: install yq
+      command: bash tests/e2e/script/prepare/install.sh yq
+    - name: install swctl
+      command: bash tests/e2e/script/prepare/install.sh swctl
+
+trigger:
+  action: http      # The action of the trigger. support HTTP invoke.
+  interval: 3s      # Trigger the action every 3 seconds.
+  times: 5          # Don't omit this!
+  url: http://${consumer_host}:${consumer_9090}/artist
+  method: POST       # Http trigger method.
+  headers:
+    "Content-Type": "application/json"
+  body: '{"song": "Despacito"}'
+
+verify:
+  # verify with retry strategy
+  retry:
+    # max retry count
+    count: 20
+    # the interval between two retries
+    interval: 5s
+  cases:
+    # basic check: service list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service ls
+      expected: ../expected/service.yml
+    # basic check: service metrics
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name service_sla --service-name=e2e-service-provider |yq e 'to_entries' -
+      expected: ../expected/metrics-has-value.yml
+    # basic check: service endpoint
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql endpoint list --service-name=e2e-service-provider
+      expected: ../expected/service-endpoint.yml
+    # basic check: service endpoint metrics
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name endpoint_cpm --endpoint-name=/artist --service-name=e2e-service-provider |yq e 'to_entries' -
+      expected: ../expected/metrics-has-value.yml
+
+    # service instance list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance list --service-name=e2e-service-provider
+      expected: ../expected/service-instance.yml
+
+    # TODO: Metric Collection Implementation is not merged https://github.com/apache/skywalking/issues/7084
+    # service instance pvm metrics TODO: PVM Collection Implementation needed https://github.com/apache/skywalking/issues/5944
+    # swctl --display yaml --base-url=http://localhost:12800/graphql metrics linear --name instance_jvm_thread_live_count --instance-name=provider1 --service-name=e2e-service-provider |yq e 'to_entries' -
+    #    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name instance_jvm_thread_live_count --instance-name=provider1 --service-name=e2e-service-provider |yq e 'to_entries' -
+    #      expected: ../expected/metrics-has-value.yml
+
+    # trace segment list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls
+      expected: ../expected/traces-list.yml
+
+    # trace detail
+    - query: |
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace $( \
+          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls --service-name=e2e-service-consumer\
+            | yq e '.traces | select(.[].endpointnames[0]=="/artist") | .[0].traceids[0]' -
+        )
+      expected: ../expected/trace-artist-detail.yml
+
+    # event list TODO: Events Implementation needed - no tracking issues yet
+    #    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql event list --service-name=e2e-service-provider --instance-name=provider1
+    #      expected: ../expected/event-list.yml
+
+    # logs list
+    - query: |
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql logs list --service-name=e2e-service-provider --trace-id=$( \
+            swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls \
+              | yq e '.traces | select(.[].endpointnames[0]=="/artist") | .[0].traceids[0]' -
+        )
+      expected: ../expected/logs-list.yml
diff --git a/tests/e2e/case/kafka/docker-compose.yml b/tests/e2e/case/kafka/docker-compose.yml
new file mode 100644
index 0000000..4109262
--- /dev/null
+++ b/tests/e2e/case/kafka/docker-compose.yml
@@ -0,0 +1,122 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+version: '2.1'
+
+services:
+  zookeeper:
+    image: zookeeper:3.4
+    hostname: zookeeper
+    expose:
+      - 2181
+    networks:
+      - e2e
+    environment:
+      - ALLOW_ANONYMOUS_LOGIN=yes
+    healthcheck:
+      test: [ "CMD", "sh", "-c", "nc -nz 127.0.0.1 2181" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+  broker-a:
+    image: bitnami/kafka:2.4.1
+    hostname: broker-a
+    expose:
+      - 9092
+    networks:
+      - e2e
+    environment:
+      - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
+      - KAFKA_BROKER_ID=10
+      - ALLOW_PLAINTEXT_LISTENER=yes
+    depends_on:
+      zookeeper:
+        condition: service_healthy
+    healthcheck:
+      test: [ "CMD", "kafka-topics.sh", "--list", "--zookeeper", "zookeeper:2181" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+  broker-b:
+    image: bitnami/kafka:2.4.1
+    hostname: broker-b
+    expose:
+      - 9092
+    networks:
+      - e2e
+    environment:
+      - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
+      - KAFKA_BROKER_ID=24
+      - ALLOW_PLAINTEXT_LISTENER=yes
+    depends_on:
+      zookeeper:
+        condition: service_healthy
+    healthcheck:
+      test: [ "CMD", "kafka-topics.sh", "--list", "--zookeeper", "zookeeper:2181" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+  oap:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: oap
+    environment:
+      SW_KAFKA_FETCHER: default
+      SW_KAFKA_FETCHER_SERVERS: broker-a:9092,broker-b:9092
+      SW_KAFKA_FETCHER_PARTITIONS: 2
+      SW_KAFKA_FETCHER_PARTITIONS_FACTOR: 1
+    depends_on:
+      broker-a:
+        condition: service_healthy
+      broker-b:
+        condition: service_healthy
+    ports:
+      - "12800"
+
+  provider:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: provider
+    ports:
+      - "9090"
+    environment:
+      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:11800
+      SW_AGENT_PROTOCOL: kafka
+      SW_KAFKA_REPORTER_BOOTSTRAP_SERVERS: broker-a:9092,broker-b:9092
+
+    depends_on:
+      oap:
+        condition: service_healthy
+
+  consumer:
+    extends:
+      file: ../../base/docker-compose.base.yml
+      service: consumer
+    environment:
+      SW_AGENT_COLLECTOR_BACKEND_SERVICES: oap:11800
+      SW_AGENT_PROTOCOL: kafka
+      SW_KAFKA_REPORTER_BOOTSTRAP_SERVERS: broker-a:9092,broker-b:9092
+    ports:
+      - "9090"
+    depends_on:
+      provider:
+        condition: service_healthy
+
+networks:
+  e2e:
\ No newline at end of file
diff --git a/tests/e2e/case/kafka/e2e.yaml b/tests/e2e/case/kafka/e2e.yaml
new file mode 100644
index 0000000..4933b5b
--- /dev/null
+++ b/tests/e2e/case/kafka/e2e.yaml
@@ -0,0 +1,92 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file is used to show how to write configuration files and can be used to test.
+
+setup:
+  env: compose
+  file: docker-compose.yml
+  timeout: 20m
+  init-system-environment: ../../script/env
+  steps:
+    - name: install yq
+      command: bash tests/e2e/script/prepare/install.sh yq
+    - name: install swctl
+      command: bash tests/e2e/script/prepare/install.sh swctl
+
+trigger:
+  action: http      # The action of the trigger. support HTTP invoke.
+  interval: 3s      # Trigger the action every 3 seconds.
+  times: 5          # Don't omit this!
+  url: http://${consumer_host}:${consumer_9090}/artist
+  method: POST       # Http trigger method.
+  headers:
+    "Content-Type": "application/json"
+  body: '{"song": "Despacito"}'
+
+verify:
+  # verify with retry strategy
+  retry:
+    # max retry count
+    count: 20
+    # the interval between two retries
+    interval: 5s
+  cases:
+    # basic check: service list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service ls
+      expected: ../expected/service.yml
+    # basic check: service metrics
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name service_sla --service-name=e2e-service-provider |yq e 'to_entries' -
+      expected: ../expected/metrics-has-value.yml
+    # basic check: service endpoint
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql endpoint list --service-name=e2e-service-provider
+      expected: ../expected/service-endpoint.yml
+    # basic check: service endpoint metrics
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name endpoint_cpm --endpoint-name=/artist --service-name=e2e-service-provider |yq e 'to_entries' -
+      expected: ../expected/metrics-has-value.yml
+
+    # service instance list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance list --service-name=e2e-service-provider
+      expected: ../expected/service-instance.yml
+
+    # TODO: Metric Collection Implementation is not merged https://github.com/apache/skywalking/issues/7084
+    # service instance pvm metrics TODO: PVM Collection Implementation needed https://github.com/apache/skywalking/issues/5944
+    # swctl --display yaml --base-url=http://localhost:12800/graphql metrics linear --name instance_jvm_thread_live_count --instance-name=provider1 --service-name=e2e-service-provider |yq e 'to_entries' -
+    #    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name instance_jvm_thread_live_count --instance-name=provider1 --service-name=e2e-service-provider |yq e 'to_entries' -
+    #      expected: ../expected/metrics-has-value.yml
+
+    # trace segment list
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls
+      expected: ../expected/traces-list.yml
+
+    # trace detail
+    - query: |
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace $( \
+          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls --service-name=e2e-service-consumer\
+            | yq e '.traces | select(.[].endpointnames[0]=="/artist") | .[0].traceids[0]' -
+        )
+      expected: ../expected/trace-artist-detail.yml
+
+    # event list TODO: Events Implementation needed - no tracking issues yet
+    #    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql event list --service-name=e2e-service-provider --instance-name=provider1
+    #      expected: ../expected/event-list.yml
+
+    # logs list
+    - query: |
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql logs list --service-name=e2e-service-provider --trace-id=$( \
+            swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls \
+              | yq e '.traces | select(.[].endpointnames[0]=="/artist") | .[0].traceids[0]' -
+        )
+      expected: ../expected/logs-list.yml
diff --git a/Dockerfile b/tests/e2e/script/env
similarity index 85%
copy from Dockerfile
copy to tests/e2e/script/env
index 5e03aa1..ae86a22 100644
--- a/Dockerfile
+++ b/tests/e2e/script/env
@@ -13,14 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG SW_PYTHON_VERSION
-
-FROM python:${SW_PYTHON_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /agent
-
-ADD $ROOT /agent
-
-RUN make setup-test install
+# 2022-03-25 commit
+SW_CTL_COMMIT=60cee4a926a867a7bd934b7f94c9a8517e141608
+SW_OAP_COMMIT=547f1ede2d1665601cb9d9a3853ed205620d6c83
diff --git a/tests/e2e/script/prepare/install-swctl.sh b/tests/e2e/script/prepare/install-swctl.sh
new file mode 100644
index 0000000..c0c2bc9
--- /dev/null
+++ b/tests/e2e/script/prepare/install-swctl.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+BASE_DIR=$1
+BIN_DIR=$2
+
+set -ex
+
+if ! command -v swctl &> /dev/null; then
+  mkdir -p $BASE_DIR/swctl && cd $BASE_DIR/swctl
+  curl -kLo skywalking-cli.tar.gz https://github.com/apache/skywalking-cli/archive/${SW_CTL_COMMIT}.tar.gz
+  tar -zxf skywalking-cli.tar.gz --strip=1
+  utype=$(uname | awk '{print tolower($0)}')
+  make $utype-amd64 && mv bin/swctl-*-$utype-amd64 $BIN_DIR/swctl
+fi
diff --git a/tests/e2e/script/prepare/install-yq.sh b/tests/e2e/script/prepare/install-yq.sh
new file mode 100644
index 0000000..dcc01c1
--- /dev/null
+++ b/tests/e2e/script/prepare/install-yq.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+BASE_DIR=$1
+BIN_DIR=$2
+
+if ! command -v yq &> /dev/null; then
+  mkdir -p $BASE_DIR/yq && cd $BASE_DIR/yq
+  curl -kLo yq.tar.gz https://github.com/mikefarah/yq/archive/v4.11.1.tar.gz
+  tar -zxf yq.tar.gz --strip=1
+  go install && go build -ldflags -s && cp yq $BIN_DIR/
+fi
diff --git a/tests/e2e/script/prepare/install.sh b/tests/e2e/script/prepare/install.sh
new file mode 100644
index 0000000..8ac8ed2
--- /dev/null
+++ b/tests/e2e/script/prepare/install.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+set -ex
+
+NAME=$1
+CURRENT_DIR="$(cd "$(dirname $0)"; pwd)"
+
+# prepare base dir
+TMP_DIR=/tmp/skywalking-infra-e2e
+BIN_DIR=/usr/local/bin
+mkdir -p $TMP_DIR && cd $TMP_DIR
+
+# execute install
+bash $CURRENT_DIR/install-$NAME.sh $TMP_DIR $BIN_DIR
+
+echo "success to install $NAME"
diff --git a/Dockerfile b/tests/plugin/Dockerfile.plugin
similarity index 90%
rename from Dockerfile
rename to tests/plugin/Dockerfile.plugin
index 5e03aa1..876cd8a 100644
--- a/Dockerfile
+++ b/tests/plugin/Dockerfile.plugin
@@ -13,9 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ARG SW_PYTHON_VERSION
+ARG BASE_PYTHON_IMAGE
 
-FROM python:${SW_PYTHON_VERSION}
+FROM python:${BASE_PYTHON_IMAGE}
 
 ARG ROOT=.
 
@@ -23,4 +23,4 @@ WORKDIR /agent
 
 ADD $ROOT /agent
 
-RUN make setup-test install
+RUN cd /agent && make setup-test
diff --git a/tests/plugin/docker-compose.base.yml b/tests/plugin/docker-compose.base.yml
index e101cd6..3af3d57 100644
--- a/tests/plugin/docker-compose.base.yml
+++ b/tests/plugin/docker-compose.base.yml
@@ -32,11 +32,7 @@ services:
       retries: 120
 
   agent:
-    build:
-      context: ../..
-      args:
-        - SW_PYTHON_VERSION=${SW_PYTHON_VERSION:-latest}
-    image: skywalking-agent:ci
+    image: apache/skywalking-python-agent:latest-plugin
     environment:
       SW_AGENT_COLLECTOR_BACKEND_SERVICES: collector:19876
       SW_AGENT_LOGGING_LEVEL: DEBUG