diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index af22a0ee65..9420a2092d 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -90,7 +90,7 @@ jobs: should_build: ${{ steps.filter.outputs.react_native }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: dorny/paths-filter@v4 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 id: filter with: filters: | @@ -103,6 +103,9 @@ jobs: if: needs.check-react-native-changes.outputs.should_build == 'true' uses: ./.github/workflows/react-native-build.yml + integration-tests: + uses: ./.github/workflows/run-integration-tests.yml + build-test: needs: [ build_images, @@ -112,7 +115,8 @@ jobs: checklinks, sanity, checklicense, - react-native-android + react-native-android, + integration-tests ] if: always() && !cancelled() runs-on: ubuntu-latest diff --git a/.github/workflows/run-integration-tests.yml b/.github/workflows/run-integration-tests.yml index 71fae0704e..ca104a6895 100644 --- a/.github/workflows/run-integration-tests.yml +++ b/.github/workflows/run-integration-tests.yml @@ -3,9 +3,7 @@ name: Integration Tests on: - pull_request_review: - types: - - submitted + workflow_call: permissions: contents: read @@ -14,7 +12,6 @@ jobs: run_tests: runs-on: ubuntu-latest name: "Run CI" - if: github.event.review.state == 'APPROVED' steps: - name: check out code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 diff --git a/docker-compose-tests.yml b/docker-compose-tests.yml index 984d666db2..d846399058 100644 --- a/docker-compose-tests.yml +++ b/docker-compose-tests.yml @@ -61,36 +61,68 @@ services: accounting: condition: service_started ad: - condition: service_started + condition: service_healthy cart: - condition: service_started + condition: service_healthy checkout: condition: service_started currency: - condition: service_started + condition: service_healthy email: - condition: service_started + condition: service_healthy fraud-detection: condition: service_started frontend: - condition: service_started + condition: service_healthy llm: - condition: service_started + condition: service_healthy payment: - condition: service_started + condition: service_healthy product-catalog: condition: service_started product-reviews: - condition: service_started + condition: service_healthy quote: - condition: service_started + condition: service_healthy recommendation: - condition: service_started + condition: service_healthy shipping: condition: service_started flagd: condition: service_started kafka: + condition: service_healthy + checkout-ready: + condition: service_completed_successfully + product-catalog-ready: + condition: service_completed_successfully + shipping-ready: + condition: service_completed_successfully + + # Wait-for sidecar: polls gRPC health for checkout (distroless image, no tools) + checkout-ready: + image: ghcr.io/grpc-ecosystem/grpc-health-probe:v0.4.39 + command: ["-addr=checkout:5050", "-connect-timeout=5s", "-rpc-timeout=5s"] + restart: on-failure + depends_on: + checkout: + condition: service_started + + # Wait-for sidecar: polls gRPC health for product-catalog (distroless image, no tools) + product-catalog-ready: + image: ghcr.io/grpc-ecosystem/grpc-health-probe:v0.4.39 + command: ["-addr=product-catalog:3550", "-connect-timeout=5s", "-rpc-timeout=5s"] + restart: on-failure + depends_on: + product-catalog: + condition: service_started + + # Wait-for sidecar: polls TCP for shipping (distroless image, no tools) + shipping-ready: + image: busybox:1.37 + command: ["/bin/sh", "-c", "until nc -z shipping 50050; do sleep 2; done"] + depends_on: + shipping: condition: service_started tracetest-server: diff --git a/docker-compose-tests_include-override.yml b/docker-compose-tests_include-override.yml index b9c3c837e0..ddef07932b 100644 --- a/docker-compose-tests_include-override.yml +++ b/docker-compose-tests_include-override.yml @@ -3,6 +3,111 @@ services: + ad: + healthcheck: + test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/9555'"] + start_period: 20s + interval: 5s + timeout: 5s + retries: 20 + + cart: + healthcheck: + test: ["CMD-SHELL", "nc -z localhost 7070"] + start_period: 10s + interval: 5s + timeout: 5s + retries: 20 + + currency: + healthcheck: + test: ["CMD-SHELL", "nc -z localhost 7001"] + start_period: 10s + interval: 5s + timeout: 5s + retries: 20 + + email: + healthcheck: + test: ["CMD", "ruby", "-e", "require 'socket'; TCPSocket.new('localhost', 6060).close"] + start_period: 10s + interval: 5s + timeout: 5s + retries: 20 + + frontend: + healthcheck: + test: ["CMD", "/nodejs/bin/node", "-e", "require('http').get('http://frontend:8080/',(r)=>{process.exit(0)}).on('error',()=>process.exit(1))"] + start_period: 15s + interval: 5s + timeout: 5s + retries: 20 + + llm: + healthcheck: + test: ["CMD", "python3", "-c", "import socket; s=socket.create_connection(('localhost',8000),2); s.close()"] + start_period: 10s + interval: 5s + timeout: 5s + retries: 20 + + payment: + healthcheck: + test: + - "CMD" + - "/nodejs/bin/node" + - "-e" + - >- + const net=require('net');const c=new net.Socket(); + c.setTimeout(2000); + c.connect(50051,'127.0.0.1',()=>{c.destroy();process.exit(0)}); + c.on('error',()=>process.exit(1)); + c.on('timeout',()=>process.exit(1)) + start_period: 10s + interval: 5s + timeout: 5s + retries: 20 + + product-reviews: + healthcheck: + test: ["CMD-SHELL", "nc -z localhost 3551"] + start_period: 10s + interval: 5s + timeout: 5s + retries: 20 + + quote: + healthcheck: + test: ["CMD", "php", "-r", "fsockopen('localhost', 8090) or die('fail');"] + start_period: 10s + interval: 5s + timeout: 5s + retries: 20 + + recommendation: + healthcheck: + test: ["CMD-SHELL", "nc -z localhost 9001"] + start_period: 10s + interval: 5s + timeout: 5s + retries: 20 + + postgresql: + healthcheck: + test: ["CMD-SHELL", "pg_isready -U root"] + start_period: 10s + interval: 5s + timeout: 5s + retries: 10 + + valkey-cart: + healthcheck: + test: ["CMD-SHELL", "valkey-cli ping"] + start_period: 5s + interval: 5s + timeout: 3s + retries: 10 + otel-collector: command: [ "--config=/etc/otelcol-config.yml", "--config=/etc/otelcol-config-tracetest.yml" ] environment: diff --git a/test/tracetesting/checkout/place-order.yaml b/test/tracetesting/checkout/place-order.yaml index ce642e2f38..31ae5199aa 100644 --- a/test/tracetesting/checkout/place-order.yaml +++ b/test/tracetesting/checkout/place-order.yaml @@ -41,9 +41,9 @@ spec: - attr:tracetest.response.body | json_path '$.order.shippingCost.currencyCode' = "USD" - name: It calls the PlaceOrder method successfuly selector: span[tracetest.span.type="rpc" name="oteldemo.CheckoutService/PlaceOrder" - rpc.system="grpc" rpc.method="PlaceOrder" rpc.service="oteldemo.CheckoutService"] + rpc.system.name="grpc" rpc.method="oteldemo.CheckoutService/PlaceOrder"] assertions: - - attr:rpc.grpc.status_code = 0 + - attr:rpc.response.status_code = "OK" - name: It sends an order to be processed asyncronously selector: span[tracetest.span.type="messaging" name="orders publish" kind="producer" messaging.system="kafka" messaging.destination.name="orders" messaging.operation="publish"] assertions: diff --git a/test/tracetesting/frontend/03-browse-product.yaml b/test/tracetesting/frontend/03-browse-product.yaml index 2d13fdfa4a..02d732ccf3 100644 --- a/test/tracetesting/frontend/03-browse-product.yaml +++ b/test/tracetesting/frontend/03-browse-product.yaml @@ -25,7 +25,7 @@ spec: - attr:tracetest.response.body | json_path '$.priceUsd' != "{}" - attr:tracetest.response.body | json_path '$.categories' != "[]" - name: It queried the product catalog correctly for a specific product - selector: span[tracetest.span.type="rpc" name="oteldemo.ProductCatalogService/GetProduct" rpc.system="grpc" rpc.method="GetProduct" rpc.service="oteldemo.ProductCatalogService"] + selector: span[tracetest.span.type="rpc" name="oteldemo.ProductCatalogService/GetProduct" rpc.system.name="grpc" rpc.method="oteldemo.ProductCatalogService/GetProduct"] assertions: - - attr:rpc.grpc.status_code = 0 + - attr:rpc.response.status_code = "OK" - attr:app.product.id = "0PUK6V6EV0" diff --git a/test/tracetesting/frontend/06-checking-out-cart.yaml b/test/tracetesting/frontend/06-checking-out-cart.yaml index a72d5a1474..a6b0ee80ed 100644 --- a/test/tracetesting/frontend/06-checking-out-cart.yaml +++ b/test/tracetesting/frontend/06-checking-out-cart.yaml @@ -39,23 +39,23 @@ spec: assertions: - attr:tracetest.response.status = 200 - name: "The order was placed" - selector: span[tracetest.span.type="rpc" name="oteldemo.CheckoutService/PlaceOrder" rpc.system="grpc" rpc.method="PlaceOrder" rpc.service="oteldemo.CheckoutService"] + selector: span[tracetest.span.type="rpc" name="oteldemo.CheckoutService/PlaceOrder" rpc.system.name="grpc" rpc.method="oteldemo.CheckoutService/PlaceOrder"] assertions: - attr:app.user.id = "2491f868-88f1-4345-8836-d5d8511a9f83" - attr:app.order.items.count = 1 - name: "The user was charged" - selector: span[tracetest.span.type="rpc" name="oteldemo.PaymentService/Charge" rpc.system="grpc" rpc.method="Charge" rpc.service="oteldemo.PaymentService"] + selector: span[tracetest.span.type="rpc" name="oteldemo.PaymentService/Charge" rpc.system.name="grpc" rpc.method="oteldemo.PaymentService/Charge"] assertions: - - attr:rpc.grpc.status_code = 0 + - attr:rpc.response.status_code = "OK" - attr:tracetest.selected_spans.count >= 1 - name: "The product was shipped" - selector: span[tracetest.span.type="http" name="/ship-order"] + selector: span[name="/ship-order"] assertions: - attr:http.response.status_code = 200 - name: "The cart was emptied" - selector: span[tracetest.span.type="rpc" name="oteldemo.CartService/EmptyCart" rpc.system="grpc" rpc.method="EmptyCart" rpc.service="oteldemo.CartService"] + selector: span[tracetest.span.type="rpc" name="oteldemo.CartService/EmptyCart" rpc.system.name="grpc" rpc.method="oteldemo.CartService/EmptyCart"] assertions: - - attr:rpc.grpc.status_code = 0 + - attr:rpc.response.status_code = "OK" - attr:tracetest.selected_spans.count >= 1 - name: The order was sent to be processed asyncronously selector: span[tracetest.span.type="messaging" name="orders publish" messaging.system="kafka" messaging.destination.name="orders" messaging.operation="publish"] diff --git a/test/tracetesting/product-catalog/get.yaml b/test/tracetesting/product-catalog/get.yaml index a1e26c4c3a..75e51c67ff 100644 --- a/test/tracetesting/product-catalog/get.yaml +++ b/test/tracetesting/product-catalog/get.yaml @@ -18,9 +18,9 @@ spec: } specs: - name: It queried the product catalog correctly for a specific product - selector: span[tracetest.span.type="rpc" name="oteldemo.ProductCatalogService/GetProduct" rpc.system="grpc" rpc.method="GetProduct" rpc.service="oteldemo.ProductCatalogService"] + selector: span[tracetest.span.type="rpc" name="oteldemo.ProductCatalogService/GetProduct" rpc.system.name="grpc" rpc.method="oteldemo.ProductCatalogService/GetProduct"] assertions: - - attr:rpc.grpc.status_code = 0 + - attr:rpc.response.status_code = "OK" - attr:app.product.id = "OLJCESPC7Z" - name: It returned a product with valid attributes selector: span[tracetest.span.type="general" name="Tracetest trigger"] diff --git a/test/tracetesting/product-catalog/list.yaml b/test/tracetesting/product-catalog/list.yaml index 92adadb78e..7027d5107f 100644 --- a/test/tracetesting/product-catalog/list.yaml +++ b/test/tracetesting/product-catalog/list.yaml @@ -16,9 +16,9 @@ spec: specs: - name: It queried the product catalog correctly selector: span[tracetest.span.type="rpc" name="oteldemo.ProductCatalogService/ListProducts" - rpc.system="grpc" rpc.method="ListProducts" rpc.service="oteldemo.ProductCatalogService"] + rpc.system.name="grpc" rpc.method="oteldemo.ProductCatalogService/ListProducts"] assertions: - - attr:rpc.grpc.status_code = 0 + - attr:rpc.response.status_code = "OK" - attr:app.products.count = 10 - name: It returned products with IDs selector: span[tracetest.span.type="general" name="Tracetest trigger"] diff --git a/test/tracetesting/product-catalog/search.yaml b/test/tracetesting/product-catalog/search.yaml index fe211b8e7c..26f2df05e9 100644 --- a/test/tracetesting/product-catalog/search.yaml +++ b/test/tracetesting/product-catalog/search.yaml @@ -18,10 +18,10 @@ spec: } specs: - name: It called SearchProducts correctly and it returned 1 item - selector: span[tracetest.span.type="rpc" name="oteldemo.ProductCatalogService/SearchProducts" rpc.system="grpc" rpc.method="SearchProducts" rpc.service="oteldemo.ProductCatalogService"] + selector: span[tracetest.span.type="rpc" name="oteldemo.ProductCatalogService/SearchProducts" rpc.system.name="grpc" rpc.method="oteldemo.ProductCatalogService/SearchProducts"] assertions: - attr:app.products_search.count = 1 - - attr:rpc.grpc.status_code = 0 + - attr:rpc.response.status_code = "OK" - name: It returned the desired product selector: span[tracetest.span.type="general" name="Tracetest trigger"] assertions: diff --git a/test/tracetesting/run.bash b/test/tracetesting/run.bash index ef4e15a343..8f1e7901cd 100755 --- a/test/tracetesting/run.bash +++ b/test/tracetesting/run.bash @@ -65,7 +65,7 @@ run_tracetest() { service_name=$1 testsuite_file=./$service_name/all.yaml - tracetest --config ./cli-config.yml run testsuite --file $testsuite_file --vars ./tracetesting-vars.yaml & + tracetest --config ./cli-config.yml run testsuite --file $testsuite_file --vars ./tracetesting-vars.yaml --output json & pids+=($!) } diff --git a/test/tracetesting/shipping/empty-quote.yaml b/test/tracetesting/shipping/empty-quote.yaml index ea7e141646..fcc3818d8e 100644 --- a/test/tracetesting/shipping/empty-quote.yaml +++ b/test/tracetesting/shipping/empty-quote.yaml @@ -26,8 +26,12 @@ spec: "items": [] } specs: - - name: It called GetQuote successfully - selector: span[tracetest.span.type="http" name="/get-quote" http.request.method="POST"] + - name: It called GetQuote successfully 1 + selector: span[name="/get-quote" http.request.method="POST"] + assertions: + - attr:http.response.status_code = 200 + - name: It called GetQuote successfully 2 + selector: span[tracetest.span.type="http" name="POST /getquote" http.request.method="POST"] assertions: - attr:http.response.status_code = 200 - name: It returned a valid empty quote diff --git a/test/tracetesting/shipping/order.yaml b/test/tracetesting/shipping/order.yaml index c3d04751e2..5f344ab16b 100644 --- a/test/tracetesting/shipping/order.yaml +++ b/test/tracetesting/shipping/order.yaml @@ -32,7 +32,7 @@ spec: } specs: - name: It called ShipOrder successfully - selector: span[tracetest.span.type="http" name="/ship-order" http.request.method="POST"] + selector: span[name="/ship-order" http.request.method="POST"] assertions: - attr:http.response.status_code = 200 - name: It returned a tracking ID diff --git a/test/tracetesting/shipping/quote.yaml b/test/tracetesting/shipping/quote.yaml index d9f3412803..0a0c10044e 100644 --- a/test/tracetesting/shipping/quote.yaml +++ b/test/tracetesting/shipping/quote.yaml @@ -31,10 +31,14 @@ spec: ] } specs: - - name: It called GetQuote successfully + - name: It called GetQuote successfully 1 selector: span[tracetest.span.type="http" name="/get-quote" http.request.method="POST"] assertions: - attr:http.response.status_code = 200 + - name: It called GetQuote successfully 2 + selector: span[tracetest.span.type="http" name="POST /getquote" http.request.method="POST"] + assertions: + - attr:http.response.status_code = 200 - name: It returned a valid quote selector: span[tracetest.span.type="general" name="Tracetest trigger"] assertions: