From c57a99b681c05be6fa1a8a6ca98f87f7b50bb926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adnan=20Rahi=C4=87?= Date: Tue, 23 Jan 2024 13:32:53 +0100 Subject: [PATCH] docs(recipe): add vercel (#3549) * docs(recipe): add vercel * Update docs/docs/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest.mdx Co-authored-by: Julianne Fermi * Update docs/docs/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest.mdx Co-authored-by: Julianne Fermi --------- Co-authored-by: Julianne Fermi --- docs/docs/examples-tutorials/recipes.mdx | 12 +- ...functions-with-opentelemetry-tracetest.mdx | 316 ++++++++++++++++++ docs/docs/examples-tutorials/tutorials.mdx | 7 + docs/sidebars.js | 11 + 4 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 docs/docs/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest.mdx diff --git a/docs/docs/examples-tutorials/recipes.mdx b/docs/docs/examples-tutorials/recipes.mdx index 95a1c91f21..9686ac01bb 100644 --- a/docs/docs/examples-tutorials/recipes.mdx +++ b/docs/docs/examples-tutorials/recipes.mdx @@ -19,8 +19,10 @@ If you're already building something with Tracetest, explore these Recipes. They These guides show integrations with other tools and vendors. +- [Trace-Based End to End Testing with Cypress and Tracetest](/tools-and-integrations/cypress) +- [Trace-Based End to End Testing with Playwright and Tracetest](/tools-and-integrations/playwright) - [Running Tracetest with Testkube](/tools-and-integrations/testkube) -- [Running Tracetest with k6](/tools-and-integrations/k6) +- [Performance and Trace-Based Tests with Tracetest and k6](/tools-and-integrations/k6) - [Running Tracetest Core with k6](/tools-and-integrations/k6-core) - [Running Tracetest with Keptn](/tools-and-integrations/keptn) @@ -30,6 +32,12 @@ These recipes show how to trigger Tracetest test runs with message queues like K - [Testing Kafka in a Go API with OpenTelemetry](/examples-tutorials/recipes/testing-kafka-go-api-with-opentelemetry-tracetest) +## Serverless Functions (FaaS) + +These recipes show how to run tests against Serverless Functions with Tracetest. + +- [Testing Vercel Functions with OpenTelemetry](/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest) + ## Trace Data Stores These recipes show integrations with trace data stores and tracing vendors/providers. @@ -87,6 +95,8 @@ This integration point uses the OpenTelemetry Collector as a router to send trac - [Sending traces to Sumo Logic from a Node.js app and fetching them from Sumo Logic with Tracetest](/examples-tutorials/recipes/running-tracetest-with-sumologic) + + ## CI/CD Automation These guides show integrations with CI/CD tools. diff --git a/docs/docs/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest.mdx b/docs/docs/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest.mdx new file mode 100644 index 0000000000..d367c25acf --- /dev/null +++ b/docs/docs/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest.mdx @@ -0,0 +1,316 @@ +--- +id: testing-vercel-functions-with-opentelemetry-tracetest +title: Testing Vercel Functions (Next.js) with OpenTelemetry and Tracetest +description: Quick start on how to configure Vercel functions with OpenTelemetry and Tracetest for enhancing your integration tests with trace-based testing. +hide_table_of_contents: false +keywords: + - tracetest + - trace-based testing + - observability + - distributed tracing + - testing + - cypress + - end to end testing + - end-to-end testing + - integration testing +image: https://res.cloudinary.com/djwdcmwdz/image/upload/v1698686403/docs/Blog_Thumbnail_14_rsvkmo.jpg +--- + +:::note +[Check out the source code on GitHub here.](https://github.com/kubeshop/tracetest/tree/main/examples/integration-testing-vercel-functions) +::: + +[Tracetest](https://tracetest.io/) is a testing tool based on [OpenTelemetry](https://opentelemetry.io/) that allows you to test your distributed application. It allows you to use data from distributed traces generated by OpenTelemetry to validate and assert if your application has the desired behavior defined by your test definitions. + +[Vercel](https://vercel.com/) is a platform that hosts serverless functions and front-end code offering developers scalability and flexibility with no infrastructure overhead. + +## Why is this important? + +Testing Serverless Functions has been a pain point for years. Not having visibility into the infrastructure and not knowing where a test fails causes the MTTR to be higher than for other tools. Including OpenTelemetry in Vercel functions exposes telemetry that you can use for both production visibility and trace-based testing. + +This sample shows how to run integration tests against Vercel Functions using [OpenTelemetry](https://opentelemetry.io/) and Tracetest. + +The Vercel function will fetch data from an external API, transform the data and insert it into a Vercel Postgres database. This particular flow has two failure points that are difficult to test. + +1. Validating that an external API request from a Vercel function is successful. +2. Validating that a Postgres insert request is successful. + +## Prerequisites + +**Tracetest Account**: + +- Sign up to [`app.tracetest.io`](https://app.tracetest.io) or follow the [get started](/getting-started/installation) docs. +- Create an [environment](/concepts/environments). +- Create an [environment token](/concepts/environment-tokens). +- Have access to the environment's [agent API key](/configuration/agent). +- [Vercel Account](https://vercel.com/) +- [Vercel Postgres Database](https://vercel.com/docs/storage/vercel-postgres) + +**Vercel Functions Example:** + +Clone the official [Tracetest Pokeshop Demo App Repo](https://github.com/kubeshop/pokeshop) to your local machine. + +```bash +git clone https://github.com/kubeshop/tracetest.git +cd tracetest/examples/integration-testing-vercel-functions +``` + +Before moving forward, run `npm i` in the root folder to install the dependencies. + +```bash +npm i +``` + +**Docker**: + +- Have [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) installed on your machine. + +## Project Structure + +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +It's using Vercel Functions via `/pages/api`, with [OpenTelemetry configured as explained in the Vercel docs](https://nextjs.org/docs/pages/building-your-application/optimizing/open-telemetry#manual-opentelemetry-configuration). + +### 1. Vercel (Next.js) Function + +The `docker-compose.yaml` file reference the Next.js app with `next-app`. + +### 2. Tracetest + +The `docker-compose.yaml` file also has a Tracetest Agent service and an integration tests service. + +### Docker Compose Network + +All `services` in the `docker-compose.yaml` are on the same network and will be reachable by hostname from within other services. E.g. `next-app:3000` in the `test/api.pokemon.spec.docker.yaml` will map to the `next-app` service. + +## Vercel (Next.js) Function + +The Vercel Function is a simple API, [contained in the `pages/api/pokemon.ts` file](https://github.com/kubeshop/tracetest/blob/main/examples/integration-testing-vercel-functions/pages/api/pokemon.ts). + +```typescript +import { trace, SpanStatusCode } from '@opentelemetry/api' +import type { NextApiRequest, NextApiResponse } from 'next' +import { sql } from '@vercel/postgres' + +export async function addPokemon(pokemon: any) { + return await sql` + INSERT INTO pokemon (name) + VALUES (${pokemon.name}) + RETURNING *; + ` +} + +export async function getPokemon(pokemon: any) { + return await sql` + SELECT * FROM pokemon where id=${pokemon.id}; + ` +} + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + const activeSpan = trace.getActiveSpan() + const tracer = await trace.getTracer('integration-testing-vercel-functions') + + try { + + const externalPokemon = await tracer.startActiveSpan('GET Pokemon from pokeapi.co', async (externalPokemonSpan) => { + const requestUrl = `https://pokeapi.co/api/v2/pokemon/${req.body.id || '6'}` + const response = await fetch(requestUrl) + const { id, name } = await response.json() + + externalPokemonSpan.setStatus({ code: SpanStatusCode.OK, message: String("Pokemon fetched successfully!") }) + externalPokemonSpan.setAttribute('pokemon.name', name) + externalPokemonSpan.setAttribute('pokemon.id', id) + externalPokemonSpan.end() + + return { id, name } + }) + + const addedPokemon = await tracer.startActiveSpan('Add Pokemon to Vercel Postgres', async (addedPokemonSpan) => { + const { rowCount, rows: [addedPokemon, ...rest] } = await addPokemon(externalPokemon) + addedPokemonSpan.setAttribute('pokemon.isAdded', rowCount === 1) + addedPokemonSpan.setAttribute('pokemon.added.name', addedPokemon.name) + addedPokemonSpan.end() + return addedPokemon + }) + + res.status(200).json(addedPokemon) + + } catch (err) { + activeSpan?.setAttribute('error', String(err)) + activeSpan?.recordException(String(err)) + activeSpan?.setStatus({ code: SpanStatusCode.ERROR, message: String(err) }) + res.status(500).json({ error: 'failed to load data' }) + } finally { + activeSpan?.end() + } +} +``` + +The OpenTelemetry tracing is [contained in the `instrumentation.node.ts` file](https://github.com/kubeshop/tracetest/blob/main/examples/integration-testing-vercel-functions/instrumentation.node.ts). Traces will be sent to the Tracetest Agent. + +```typescript +import { NodeSDK } from '@opentelemetry/sdk-node' +import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http' +import { Resource } from '@opentelemetry/resources' +import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' +import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node' +import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch' + +const sdk = new NodeSDK({ + // The OTEL_EXPORTER_OTLP_ENDPOINT env var is passed into "new OTLPTraceExporter" automatically. + // If the OTEL_EXPORTER_OTLP_ENDPOINT env var is not set the "new OTLPTraceExporter" will + // default to use "http://localhost:4317" for gRPC and "http://localhost:4318" for HTTP. + // This sample is using HTTP. + traceExporter: new OTLPTraceExporter(), + instrumentations: [ + getNodeAutoInstrumentations(), + new FetchInstrumentation(), + ], + resource: new Resource({ + [SemanticResourceAttributes.SERVICE_NAME]: 'integration-testing-vercel-functions', + }), +}) +sdk.start() +``` + +### Set up Environment Variables + +Edit the `.env.development` file. Add your Vercel Postgres env vars. + +```bash title=.env.development.local +# OTLP HTTP +OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318" + +# Vercel Postgres +POSTGRES_DATABASE="**********" +POSTGRES_HOST="**********" +POSTGRES_PASSWORD="**********" +POSTGRES_PRISMA_URL="**********" +POSTGRES_URL="**********" +POSTGRES_URL_NON_POOLING="**********" +POSTGRES_USER="**********" +``` + +### Start the Next.js Vercel Function + +Spin up your Next.js app. + +```bash +npm run dev +``` + +This starts the function on `http://localhost:3000/api/pokemon`. + +## Testing the Vercel Function Locally + +[Download the CLI](/getting-started/installation#install-the-tracetest-cli) for your operating system. + +The CLI is bundled with [Tracetest Agent](/concepts/agent/) that runs in your infrastructure to collect responses and traces for tests. + +To start Tracetest Agent add the `--api-key` from your environment. + +```bash title=Terminal +tracetest start --api-key YOUR_AGENT_API_KEY +``` + +Run a test with the test definition `test/api.pokemon.spec.development.yaml`. + +```yaml title=test/api.pokemon.spec.development.yaml +type: Test +spec: + id: kv8C-hOSR + name: Test API + trigger: + type: http + httpRequest: + method: POST + url: http://localhost:3000/api/pokemon + body: "{\n \"id\": \"6\"\n}" + headers: + - key: Content-Type + value: application/json + specs: + - selector: span[tracetest.span.type="http"] + name: "All HTTP Spans: Status code is 200" + assertions: + - attr:http.status_code = 200 +``` + +```bash title=Terminal +tracetest run test -f ./test/api.pokemon.spec.development.yaml --required-gates test-specs --output pretty + +[Output] +✔ Test API (https://app.tracetest.io/organizations/ttorg_e66318ba6544b856/environments/ttenv_0e807879e2e38d28/test/-gjd4idIR/run/22/test) - trace id: f2250362ff2f70f8f5be7b2fba74e4b2 + ✔ All HTTP Spans: Status code is 200 +``` + +## Integration Testing the Vercel Function + +Edit the `.env.docker` file to use your Vercel Postgres env vars. + +```bash title=.env.docker +# OTLP HTTP +OTEL_EXPORTER_OTLP_ENDPOINT="http://tracetest-agent:4318" + +# Vercel Postgres +POSTGRES_DATABASE="**********" +POSTGRES_HOST="**********" +POSTGRES_PASSWORD="**********" +POSTGRES_PRISMA_URL="**********" +POSTGRES_URL="**********" +POSTGRES_URL_NON_POOLING="**********" +POSTGRES_USER="**********" +``` + +This configures the `OTEL_EXPORTER_OTLP_ENDPOINT` to send traces to Tracetest Agent. + +Edit the `docker-compose.yaml` in the root directory. Add your `TRACETEST_API_KEY`. + +```yaml title=docker-compose.yaml + # [...] + tracetest-agent: + image: kubeshop/tracetest-agent:latest + environment: + - TRACETEST_API_KEY=YOUR_TRACETEST_API_KEY # Find the Agent API Key here: https://docs.tracetest.io/configuration/agent + ports: + - 4317:4317 + - 4318:4318 + networks: + - tracetest +``` + +Edit the `run.bash`. Add your `TRACETEST_API_TOKEN`. + +```bash +#/bin/bash + +# Find the API Token here: https://docs.tracetest.io/concepts/environment-tokens +tracetest configure -t YOUR_TRACETEST_API_TOKEN +tracetest run test -f ./api.pokemon.spec.docker.yaml --required-gates test-specs --output pretty +``` + +Now you can run the Vercel function and Tracetest Agent! + +```bash +docker compose up -d --build +``` + +And, trigger the integration tests. + +```bash +docker compose run integration-tests + +[Ouput] +[+] Creating 1/0 + ✔ Container integration-testing-vercel-functions-tracetest-agent-1 Running 0.0s + SUCCESS Successfully configured Tracetest CLI +✔ Test API (https://app.tracetest.io/organizations/ttorg_e66318ba6544b856/environments/ttenv_82af376d61da80a0/test/p00W82OIR/run/8/test) - trace id: d64ab3a6f52a98141d26679fff3373b6 + ✔ All HTTP Spans: Status code is 200 +``` + +## Learn More + +Feel free to check out our [examples in GitHub](https://github.com/kubeshop/tracetest/tree/main/examples) and join our [Slack Community](https://dub.sh/tracetest-community) for more info! diff --git a/docs/docs/examples-tutorials/tutorials.mdx b/docs/docs/examples-tutorials/tutorials.mdx index 9eea42bfc2..027191833c 100644 --- a/docs/docs/examples-tutorials/tutorials.mdx +++ b/docs/docs/examples-tutorials/tutorials.mdx @@ -19,6 +19,7 @@ Check out the following blog posts with Tracetest-related content. ### Distributed Tracing Vendors +- [Sumo Logic and Tracetest: AI-Driven Observability Meets Testing](https://tracetest.io/blog/sumo-logic-and-tracetest-ai-driven-observability-meets-testing) - [Tracetest + Dynatrace: Unified Observability for Testing](https://tracetest.io/blog/tracetest-dynatrace-unified-observability-for-testing) - [Honeycomb + Tracetest: Observability-driven Development](https://tracetest.io/blog/honeycomb-tracetest-observability-driven-development) - [Tracetest + Elastic: Trace-based testing meets APM](https://tracetest.io/blog/tracetest-integration-elastic-trace-based-testing-application-performance-monitoring) @@ -34,6 +35,8 @@ Check out the following blog posts with Tracetest-related content. ### Tools +- [Cloud Native Observability and Cypress: An Unlikely Marriage](https://tracetest.io/blog/cloud-native-observability-and-cypress-an-unlikely-marriage) +- [Load Testing with k6 and Tracetest](https://tracetest.io/blog/load-testing-with-k6-and-tracetest) - [Synthetic Monitoring with the Tracetest GitHub Action](https://tracetest.io/blog/synthetic-monitoring-with-the-tracetest-github-action) - [Event-driven Kubernetes testing with Testkube and Tracetest](https://tracetest.io/blog/event-driven-kubernetes-testing-with-testkube-and-tracetest) - [Announcing the Tracetest integration with Keptn](https://tracetest.io/blog/announcing-the-tracetest-integration-with-keptn-the-control-plane-for-cloud-native-application-life-cycle-orchestration) @@ -61,6 +64,10 @@ Check out the following blog posts with Tracetest-related content. - [Testing Event-driven Systems with OpenTelemetry](https://tracetest.io/blog/testing-event-driven-systems-with-opentelemetry) +### Testing Serverless Functions (Faas) + +- [Integration Testing Vercel Serverless Functions with OpenTelemetry](https://tracetest.io/blog/integration-testing-vercel-serverless-functions-with-opentelemetry) + ### Observability-driven development - [Observability-driven development with Go and Tracetest](https://tracetest.io/blog/observability-driven-development-with-go-and-tracetest) diff --git a/docs/sidebars.js b/docs/sidebars.js index 3c763d8ee7..e5be5021de 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -137,6 +137,17 @@ const sidebars = { }, ], }, + { + type: "category", + label: "Serverless Functions", + items: [ + { + type: "doc", + id: "examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest", + label: "Testing Vercel Functions", + }, + ], + }, { type: "category", label: "OpenTelemetry",