Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add local build/dev tests for examples #21

Merged
merged 45 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c94c23d
feat: add examples/ci
CahidArda Nov 8, 2024
51477fc
ci: add local build/dev tests for examples
CahidArda Nov 8, 2024
8c7c5be
ci: fix tests
CahidArda Nov 8, 2024
d871c0e
fix: add start workflow tests for next and cf
CahidArda Nov 8, 2024
8e44711
ci: add ci.mjs for node 18
CahidArda Nov 8, 2024
c7280bb
fix: add crypto import
CahidArda Nov 8, 2024
93c62f3
fix: change expected error message
CahidArda Nov 8, 2024
bce7041
fix: use node:crypto
CahidArda Nov 8, 2024
d98aa50
Merge branch 'examples/ci' into local-example-ci
CahidArda Nov 8, 2024
1b21594
feat: add integration test logic
CahidArda Nov 8, 2024
0edba8a
feat: add routes and add vercel deployment
CahidArda Nov 8, 2024
8dd774d
ci: add mock release and integration tests
CahidArda Nov 8, 2024
84da3d9
ci: add redis env to test step
CahidArda Nov 8, 2024
12c0ce1
ci: use UPSTASH_WORKFLOW_URL
CahidArda Nov 8, 2024
924d19b
fix: checkWorkflowStart
CahidArda Nov 8, 2024
255591d
fix: add path duration
CahidArda Nov 8, 2024
3d38eff
fix: add auth and call routes
CahidArda Nov 9, 2024
51ed0be
fix: add fail routes to ci
CahidArda Nov 9, 2024
47ccd29
fix: add retry and user headers to failure
CahidArda Nov 9, 2024
1990a64
fix: add wait-for-event endpoint
CahidArda Nov 9, 2024
da6569d
ci: add ci release and use it in integration tests
CahidArda Nov 9, 2024
dba3e2e
fix: ci build error
CahidArda Nov 9, 2024
cdaa4fe
fix: rm nano from routes
CahidArda Nov 9, 2024
ad276d0
fix: rm Keep-Alive checks and extend wait duration in tests
CahidArda Nov 9, 2024
d6d1b8e
feat: add nextjs-12 example
CahidArda Nov 9, 2024
d047b56
fix: use redis to count the step executions
CahidArda Nov 9, 2024
0509131
fix: increate wait times
CahidArda Nov 9, 2024
2431376
ci: add deployed cf and nextjs-12 tests
CahidArda Nov 10, 2024
3d14cc0
fix: sleep longer before checking
CahidArda Nov 10, 2024
8f8f684
ci: fix project id and extend timeout
CahidArda Nov 10, 2024
2bd2938
ci: enable all ci
CahidArda Nov 10, 2024
b730a1d
ci: fix name
CahidArda Nov 10, 2024
3b4e2d7
fix: rm toString and extend sleep
CahidArda Nov 10, 2024
8bf4737
fix: expire secrets in ci
CahidArda Nov 11, 2024
fc9d22a
ci: skip solidjs test
CahidArda Nov 11, 2024
6a9498e
fix: add nextjs-pages example to CI
CahidArda Nov 11, 2024
403668f
Merge branch 'main' into local-example-ci
CahidArda Nov 11, 2024
d352690
fix: handle todo
CahidArda Nov 11, 2024
11f0cca
fix: rm changes in path.ts
CahidArda Nov 11, 2024
2d42381
ci: ignore solidjs in release
CahidArda Nov 11, 2024
adba2e9
ci: use ci release in nextjs-pages deployed
CahidArda Nov 11, 2024
72525ed
ci: extend wait
CahidArda Nov 11, 2024
501134e
fix: expected call and duration in call/workflow test
CahidArda Nov 11, 2024
189c704
fix: extend test durations
CahidArda Nov 11, 2024
b6eb97b
fix: use publish in triggerFirstInvocation
CahidArda Nov 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
669 changes: 669 additions & 0 deletions .github/workflows/test.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/vercel": "^7.8.2",
"@upstash/workflow": "0.1.2-canary-astro",
"@upstash/workflow": "latest",
"astro": "^4.16.7",
"typescript": "^5.6.3"
},
Expand Down
10 changes: 6 additions & 4 deletions examples/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ project_arg="$1"


# create dist
# cd ..
# bun install
# bun run build
# cd examples
cd ..
bun install
bun run build
cd examples/$project_arg
pnpm i @upstash/workflow@file:../../dist
cd ..

# install dependencies
cd "$project_arg"
Expand Down
11 changes: 11 additions & 0 deletions examples/ci/.env.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
QSTASH_URL=""
QSTASH_TOKEN=""

UPSTASH_REDIS_REST_URL=""
UPSTASH_REDIS_REST_TOKEN=""

QSTASH_CURRENT_SIGNING_KEY=""
QSTASH_NEXT_SIGNING_KEY=""

# for local development
UPSTASH_WORKFLOW_URL=""
3 changes: 3 additions & 0 deletions examples/ci/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
37 changes: 37 additions & 0 deletions examples/ci/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
ngrok.log
54 changes: 54 additions & 0 deletions examples/ci/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"arrowParens": "always",
"bracketSameLine": false,
"bracketSpacing": true,
"semi": false,
"singleQuote": true,
"jsxSingleQuote": false,
"quoteProps": "as-needed",
"trailingComma": "all",
"singleAttributePerLine": false,
"htmlWhitespaceSensitivity": "css",
"vueIndentScriptAndStyle": false,
"proseWrap": "preserve",
"insertPragma": false,
"printWidth": 80,
"requirePragma": false,
"tabWidth": 2,
"useTabs": false,
"embeddedLanguageFormatting": "auto",
"jsxBracketSameLine": false,
"fluid": false,
"importOrder": [
"^(react/(.*)$)|^(react$)",
"^(next/(.*)$)|^(next$)",
"",
"<THIRD_PARTY_MODULES>",
"",
"^@/config/(.*)$",
"^@/lib/(.*)$",
"^@/hooks/(.*)$",
"",
"^@/components/ui/(.*)$",
"^@/components/(.*)$",
"",
"^@/styles/(.*)$",
"",
"^types$",
"^@/types/(.*)$",
"",
"^[./]"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true,
"importOrderBuiltinModulesToTop": true,
"importOrderParserPlugins": [
"typescript",
"jsx"
],
"importOrderMergeDuplicateImports": true,
"importOrderCombineTypeAndValueImports": true,
"plugins": [
"prettier-plugin-tailwindcss"
]
}
39 changes: 39 additions & 0 deletions examples/ci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fupstash%2Fqstash-js%2Ftree%2Fmain%2Fexamples%2Fworkflow%2Fnextjs&env=QSTASH_TOKEN&envDescription=You%20can%20access%20this%20variable%20from%20Upstash%20Console%2C%20under%20QStash%20page.%20&project-name=qstash-workflow-nextjs&repository-name=qstash-workflow-nextjs&demo-title=Upstash%20QStash%20Workflow%20Example&demo-description=A%20Next.js%20application%20utilizing%20QStash%20Workflows)

# Upstash Workflow Nextjs Example

This project has some routes showcasing how Upstash Workflow can be used in a nextjs project. You can learn more in [Workflow documentation for Nextjs](https://upstash.com/docs/qstash/workflow/quickstarts/vercel-nextjs).

Under the app directory, you will find 7 folders, each corresponding to a workflow API except the `-call-qstash`. In each of these folders, you will find the `route.ts` file which defines the endpoint.

The user calls `-call-qstash` with information about which endpoint is to be called in the body. `-call-qstash` publishes a message to QStash. QStash then calls the specified endpoint.

![flow-diagram](../imgs/flow-diagram.png)

## Deploying the Project at Vercel

To deploy the project, you can simply use the `Deploy with Vercel` button at the top of this README. If you want to edit the project and deploy it, you can read the rest of this section.

To deploy the project at vercel and try the endpoints, you should start with setting up the project by running:

```
vercel
```

Next, you shoud go to vercel.com, find your project and add `QSTASH_TOKEN`, to the project as environment variables. You can find this env variables from the [Upstash Console](https://console.upstash.com/qstash). To learn more about other env variables and their use in the context of Upstash Workflow, you can read [the Secure your Endpoint in our documentation](https://upstash.com/docs/qstash/workflow/howto/security#using-qstashs-built-in-request-verification-recommended).

Once you add the env variables, you can deploy the project with:

```
vercel --prod
```

Note that the project won't work in preview. It should be deployed to production like above. This is because preview requires authentication.

Once you have the app deployed, you can go to the deployment and call the endpoints using the form on the page.

You can observe the logs at [Upstash console under the Worfklow tab](https://console.upstash.com/qstash?tab=workflow) or vercel.com to see your workflow operate.

## Local Development

For local development setup, refer to the [Local Development section in our documentation](https://upstash.com/docs/qstash/workflow/howto/local-development).
17 changes: 17 additions & 0 deletions examples/ci/app/ci/ci.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { test, describe } from "bun:test"
import { TEST_ROUTES } from "./constants";
import { initiateTest } from "./utils";

describe("workflow integration tests", () => {
TEST_ROUTES.forEach(testConfig => {
test(
testConfig.route,
async () => {
await initiateTest(testConfig.route, testConfig.waitForSeconds)
},
{
timeout: (testConfig.waitForSeconds + 8) * 1000
}
)
});
})
71 changes: 71 additions & 0 deletions examples/ci/app/ci/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { TestConfig } from "./types"

export const CI_RANDOM_ID_HEADER = "Ci-Test-Id"
export const CI_ROUTE_HEADER = `Ci-Test-Route`

export const BASE_URL = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: process.env.UPSTASH_WORKFLOW_URL
? process.env.UPSTASH_WORKFLOW_URL
: "http://localhost:3001"

export const TEST_ROUTE_PREFIX = `${BASE_URL}/test-routes`

export const TEST_ROUTES: Pick<TestConfig, "route" | "waitForSeconds">[] = [
{
// tests a very basic endpoint with 2 context run statements
// payload has unicode chars
route: "path",
waitForSeconds: 1
},
{
// runs sleep and sleepUntil. checks if sufficient time passed between
// steps
route: "sleep",
waitForSeconds: 8
},
{
// runs sleep parallel with other steps
route: "sleepWithoutAwait",
waitForSeconds: 18
},
{
// checks auth
route: "auth",
waitForSeconds: 1
},
{
// checks auth failing
route: "auth-fail",
waitForSeconds: 0
},
{
// checks context.call (sucess and fail case)
route: "call/workflow",
waitForSeconds: 24
},
{
// checks context.run with async and sync route methods
route: "async-sync-run",
waitForSeconds: 1
},
{
// checks failureFunction
route: "failureFunction",
waitForSeconds: 1
},
{
// checks failureFunction with retries: 1
route: "failureFunction-retry",
waitForSeconds: 14
},
{
// checks failureUrl
route: "failureUrl/workflow",
waitForSeconds: 1
},
{
route: "wait-for-event/workflow",
waitForSeconds: 20
}
]
44 changes: 44 additions & 0 deletions examples/ci/app/ci/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export type TestConfig<TPayload = unknown> = {
/**
* path of the workflow endpoint
*
* will also be part of the redis key
*/
route: string,
/**
* payload to send in the initial request
*/
payload: TPayload,
/**
* headers of the request
*/
headers?: Record<string, string>,
/**
* duration the test between initiating the workflow and checking the result
*/
waitForSeconds: number
/**
* number of times the endpoint is to be called in this test
*/
expectedCallCount: number
/**
* expected result in the Redis
*/
expectedResult: string
}

export type RedisResult = {
/**
* observed call count
*/
callCount: number
/**
* result written to redis
*/
result: string
/**
* a randomly generated string which is generated
* in each test and sent as a header.
*/
randomTestId: string
}
51 changes: 51 additions & 0 deletions examples/ci/app/ci/upstash/qstash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Client, QstashError } from "@upstash/qstash"
import { TEST_ROUTE_PREFIX, CI_RANDOM_ID_HEADER, CI_ROUTE_HEADER } from "../constants"
import { TestConfig } from "../types"

const client = new Client({ baseUrl: process.env.QSTASH_URL, token: process.env.QSTASH_TOKEN! })

/**
* starts a workflow run given the config
*
* @param testConfig
* @param randomTestId
* @returns
*/
export const startWorkflow = async (
testConfig: Pick<TestConfig, "route" | "headers" | "payload">,
randomTestId: string
): Promise<{ messageId: string }> => {
const result = await client.publishJSON({
url: `${TEST_ROUTE_PREFIX}/${testConfig.route}`,
headers: {
[ CI_RANDOM_ID_HEADER ]: randomTestId,
[ CI_ROUTE_HEADER ]: testConfig.route,
...testConfig.headers
},
body: testConfig.payload
})
return result
}

/**
* throws error if workflow hasn't started
*
* @param messageId
* @returns
*/
export const checkWorkflowStart = async (messageId: string) => {

try {
const { events } = await client.events({ filter: { messageId }})
const startMessageDelivered = Boolean(events.find(event => event.state === "DELIVERED"))
if (!startMessageDelivered) {
await client.messages.delete(messageId)
throw new Error(`Couldn't verify that workflow has begun. Number of events: ${events.length}`)
}
} catch (error) {
if (error instanceof QstashError && error.message.includes(`message ${messageId} not found`)) {
return
}
throw error
}
}
Loading
Loading