Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
673284b
Switch to fauxqs
kibertoad Feb 19, 2026
f35c7fd
Bump dependency
kibertoad Feb 19, 2026
881082c
Bump version
kibertoad Feb 19, 2026
e4d4a33
Remove localstack
kibertoad Feb 19, 2026
177a765
remove logs
kibertoad Feb 19, 2026
c476457
Update fauxqs
kibertoad Feb 19, 2026
f7f754d
Merge branch 'main' of https://github.com/kibertoad/message-queue-too…
kibertoad Feb 19, 2026
de7431b
Version bump
kibertoad Feb 20, 2026
562b2bf
Merge branch 'main' of https://github.com/kibertoad/message-queue-too…
kibertoad Feb 20, 2026
d2a4013
version bump
kibertoad Feb 20, 2026
1ca432f
bump dependencies
kibertoad Feb 20, 2026
69ea7dd
Version bump
kibertoad Feb 20, 2026
9669996
Bump version
kibertoad Feb 21, 2026
7c6a8fd
Execute both localstack and fauxqs
kibertoad Feb 21, 2026
f80bbb3
Migrate to helpers
kibertoad Feb 21, 2026
9d241f4
Add logs
kibertoad Feb 21, 2026
af11f19
more logs
kibertoad Feb 21, 2026
7b0198f
fix formatting
kibertoad Feb 21, 2026
12b486e
Enable global env param
kibertoad Feb 21, 2026
b4bff42
Avoid cascading test run
kibertoad Feb 21, 2026
ed43dbc
Test not using helpers
kibertoad Feb 21, 2026
f5fa071
Improve helpers
kibertoad Feb 21, 2026
3e91292
Fix region handling
kibertoad Feb 21, 2026
dfe884a
Adjust helpers
kibertoad Feb 21, 2026
d0b34bd
Cleanup
kibertoad Feb 21, 2026
808073e
add missing file
kibertoad Feb 21, 2026
0c787f9
Update deps
kibertoad Feb 22, 2026
03126bc
Merge branch 'main' of https://github.com/kibertoad/message-queue-too…
kibertoad Feb 22, 2026
9eb8fe9
Bump version
kibertoad Feb 22, 2026
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
14 changes: 13 additions & 1 deletion .github/workflows/ci.common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ on:
node_version:
required: true
type: string
queue_backend:
required: false
type: string
default: 'fauxqs'

jobs:
build:
Expand All @@ -32,9 +36,17 @@ jobs:

- name: Docker start
run: npm run docker:start:ci -- --filter=${{ inputs.package_name }}
env:
QUEUE_BACKEND: ${{ inputs.queue_backend }}

- name: Run Tests
run: npm run test:ci -- --filter=${{ inputs.package_name }}
run: |
echo "::notice::Running ${{ inputs.package_name }} with QUEUE_BACKEND=${{ inputs.queue_backend }}"
npm run test:ci -- --filter=${{ inputs.package_name }}
env:
QUEUE_BACKEND: ${{ inputs.queue_backend }}

- name: Docker stop
run: npm run docker:stop:ci -- --filter=${{ inputs.package_name }}
env:
QUEUE_BACKEND: ${{ inputs.queue_backend }}
46 changes: 42 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.detect.outputs.packages }}
aws_packages: ${{ steps.detect.outputs.aws_packages }}
steps:
- name: Get changed files
id: changed-files
Expand Down Expand Up @@ -39,22 +40,45 @@ jobs:
["packages/sqs"]="@message-queue-toolkit/sqs"
)

AWS_PACKAGE_PATHS=("packages/sqs" "packages/sns")

PACKAGES=()
AWS_PACKAGES=()
for path in "${!PATH_TO_NAME[@]}"; do
if echo "$ALL_CHANGED_FILES" | grep -q "$path/"; then
PACKAGES+=("\"${PATH_TO_NAME[$path]}\"")
is_aws=false
for aws_path in "${AWS_PACKAGE_PATHS[@]}"; do
if [ "$path" = "$aws_path" ]; then
is_aws=true
break
fi
done
if [ "$is_aws" = true ]; then
AWS_PACKAGES+=("\"${PATH_TO_NAME[$path]}\"")
else
PACKAGES+=("\"${PATH_TO_NAME[$path]}\"")
fi
fi
done

if [ ${#PACKAGES[@]} -eq 0 ]; then
echo 'packages=[]' >> $GITHUB_OUTPUT
echo "No packages changed"
echo "No non-AWS packages changed"
else
JSON="[$(IFS=,; echo "${PACKAGES[*]}")]"
echo "packages=$JSON" >> $GITHUB_OUTPUT
echo "Changed packages: $JSON"
fi

if [ ${#AWS_PACKAGES[@]} -eq 0 ]; then
echo 'aws_packages=[]' >> $GITHUB_OUTPUT
echo "No AWS packages changed"
else
AWS_JSON="[$(IFS=,; echo "${AWS_PACKAGES[*]}")]"
echo "aws_packages=$AWS_JSON" >> $GITHUB_OUTPUT
echo "Changed AWS packages: $AWS_JSON"
fi

general:
needs: [changed-files-job]
if: needs.changed-files-job.outputs.packages != '[]'
Expand All @@ -67,9 +91,23 @@ jobs:
node_version: ${{ matrix.node-version }}
package_name: ${{ matrix.package-name }}

aws-packages:
needs: [changed-files-job]
if: needs.changed-files-job.outputs.aws_packages != '[]'
strategy:
matrix:
node-version: [22.x, 24.x]
package-name: ${{ fromJson(needs.changed-files-job.outputs.aws_packages) }}
queue-backend: [fauxqs, localstack]
uses: ./.github/workflows/ci.common.yml
with:
node_version: ${{ matrix.node-version }}
package_name: ${{ matrix.package-name }}
queue_backend: ${{ matrix.queue-backend }}

automerge:
needs: [general]
if: always() && (needs.general.result == 'success' || needs.general.result == 'skipped')
needs: [general, aws-packages]
if: always() && (needs.general.result == 'success' || needs.general.result == 'skipped') && (needs.aws-packages.result == 'success' || needs.aws-packages.result == 'skipped')
runs-on: ubuntu-latest
permissions:
pull-requests: write
Expand Down
35 changes: 16 additions & 19 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,6 @@ services:
- rabbit_data:/var/lib/rabbitmq
restart: on-failure

localstack:
image: localstack/localstack:4.13.1
network_mode: bridge
hostname: localstack
ports:
- '127.0.0.1:4566:4566' # LocalStack Gateway
- '127.0.0.1:4510-4559:4510-4559' # external services port range
environment:
- SERVICES=sns,sqs,s3,sts
- DEBUG=0
- DATA_DIR=${DATA_DIR-}
- DOCKER_HOST=unix:///var/run/docker.sock
- LOCALSTACK_HOST=localstack
# - LOCALSTACK_API_KEY=someDummyKey
volumes:
- '${TMPDIR:-/tmp}/localstack:/var/log/localstack'
- '/var/run/docker.sock:/var/run/docker.sock'
restart: on-failure

redis:
image: redis:6.2.7-alpine
command: redis-server --requirepass sOmE_sEcUrE_pAsS
Expand Down Expand Up @@ -95,6 +76,22 @@ services:
retries: 10
start_period: 10s

localstack:
image: localstack/localstack:4.13.1
network_mode: bridge
hostname: localstack
ports:
- '127.0.0.1:4566:4566'
- '127.0.0.1:4510-4559:4510-4559'
environment:
- SERVICES=sns,sqs,s3,sts
- DEBUG=0
- LOCALSTACK_HOST=localstack
volumes:
- '${TMPDIR:-/tmp}/localstack:/var/log/localstack'
- '/var/run/docker.sock:/var/run/docker.sock'
restart: on-failure

volumes:
rabbit_data:
driver: local
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"dependencies": {},
"devDependencies": {
"turbo": "^2.6.2"
"turbo": "^2.8.10"
},
"packageManager": "npm@10.7.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { PUBSUB_MESSAGE_MAX_SIZE } from '../../lib/pubsub/AbstractPubSubService.
import { OFFLOADED_PAYLOAD_SIZE_ATTRIBUTE } from '../../lib/utils/messageUtils.ts'
import { PubSubPermissionPublisher } from '../publishers/PubSubPermissionPublisher.ts'
import { deletePubSubTopicAndSubscription } from '../utils/cleanupPubSub.ts'
import { assertBucket, emptyBucket } from '../utils/gcsUtils.ts'
import { assertBucket, emptyBuckets } from '../utils/gcsUtils.ts'
import type { Dependencies } from '../utils/testContext.ts'
import { registerDependencies } from '../utils/testContext.ts'
import { PubSubPermissionConsumer } from './PubSubPermissionConsumer.ts'
Expand Down Expand Up @@ -75,7 +75,7 @@ describe('PubSubPermissionConsumer - Payload Offloading', () => {
})

afterAll(async () => {
await emptyBucket(gcsStorage, gcsBucketName)
await emptyBuckets(gcsStorage, gcsBucketName)

const { awilixManager } = diContainer.cradle
await awilixManager.executeDispose()
Expand Down Expand Up @@ -259,7 +259,7 @@ describe('PubSubPermissionConsumer - Payload Offloading', () => {
})

afterAll(async () => {
await emptyBucket(gcsStorage, gcsBucketName)
await emptyBuckets(gcsStorage, gcsBucketName)

const { awilixManager } = diContainer.cradle
await awilixManager.executeDispose()
Expand Down
18 changes: 10 additions & 8 deletions packages/gcp-pubsub/test/utils/gcsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ export async function assertBucket(storage: Storage, bucketName: string) {
return bucket
}

export async function emptyBucket(storage: Storage, bucketName: string) {
const bucket = storage.bucket(bucketName)
const [exists] = await bucket.exists()
export async function emptyBuckets(storage: Storage, ...bucketNames: string[]) {
for (const bucketName of bucketNames) {
const bucket = storage.bucket(bucketName)
const [exists] = await bucket.exists()

if (!exists) {
return
}
if (!exists) {
continue
}

const [files] = await bucket.getFiles()
await Promise.all(files.map((file) => file.delete({ ignoreNotFound: true })))
const [files] = await bucket.getFiles()
await Promise.all(files.map((file) => file.delete({ ignoreNotFound: true })))
}
}
5 changes: 2 additions & 3 deletions packages/s3-payload-store/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
"test:coverage": "npm run test -- --coverage",
"lint": "biome check . && tsc",
"lint:fix": "biome check --write .",
"docker:start": "docker compose up -d --quiet-pull localstack",
"docker:stop": "docker compose down",
"prepublishOnly": "npm run lint && npm run build"
},
"dependencies": {},
Expand All @@ -43,8 +41,9 @@
"@lokalise/tsconfig": "^3.0.0",
"@types/node": "^25.0.2",
"@vitest/coverage-v8": "^4.0.15",
"fauxqs": "^1.10.0",
"rimraf": "^6.0.1",
"typescript": "^5.9.2",
"typescript": "^5.9.3",
"vitest": "^4.0.15"
},
"homepage": "https://github.com/kibertoad/message-queue-toolkit",
Expand Down
4 changes: 2 additions & 2 deletions packages/s3-payload-store/test/store/S3PayloadStore.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { beforeAll, beforeEach, describe, expect, it } from 'vitest'
import { resolvePayloadStoreConfig, S3PayloadStore } from '../../lib/S3PayloadStore.ts'
import { assertEmptyBucket, getObjectContent, objectExists } from '../utils/s3Utils.ts'
import { streamToString } from '../utils/streamUtils.ts'
import { TEST_AWS_CONFIG } from '../utils/testS3Config.ts'
import { getTestS3Config } from '../utils/testS3Config.ts'

const TEST_BUCKET = 'test-bucket'

Expand All @@ -15,7 +15,7 @@ describe('S3PayloadStore', () => {
let store: S3PayloadStore

beforeAll(() => {
s3 = new S3(TEST_AWS_CONFIG)
s3 = new S3(getTestS3Config())
store = new S3PayloadStore({ s3 }, { bucketName: TEST_BUCKET })
})
beforeEach(async () => {
Expand Down
19 changes: 19 additions & 0 deletions packages/s3-payload-store/test/utils/fauxqsInstance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** biome-ignore-all lint/suspicious/noConsole: test **/
import { type FauxqsServer, startFauxqs } from 'fauxqs'

let server: FauxqsServer | undefined

export async function ensureFauxqsServer(): Promise<void> {
if (server) return
server = await startFauxqs({ port: 0, logger: false, host: 'localstack' })
console.log(`[fauxqs] server started on port ${server.port}`)
}

export function getFauxqsServer(): FauxqsServer | undefined {
return server
}

export function getFauxqsPort(): number {
if (!server) throw new Error('fauxqs server not started — call ensureFauxqsServer() first')
return server.port
}
21 changes: 14 additions & 7 deletions packages/s3-payload-store/test/utils/testS3Config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { S3ClientConfig } from '@aws-sdk/client-s3'
import { createLocalhostHandler } from 'fauxqs'

export const TEST_AWS_CONFIG: S3ClientConfig = {
endpoint: 'http://s3.localhost.localstack.cloud:4566',
region: 'eu-west-1',
credentials: {
accessKeyId: 'access',
secretAccessKey: 'secret',
},
import { getFauxqsPort } from './fauxqsInstance.ts'

export function getTestS3Config(): S3ClientConfig {
const port = getFauxqsPort()
return {
endpoint: `http://s3.localhost:${port}`,
region: 'eu-west-1',
credentials: {
accessKeyId: 'access',
secretAccessKey: 'secret',
},
requestHandler: createLocalhostHandler(),
}
}
3 changes: 3 additions & 0 deletions packages/s3-payload-store/test/utils/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ensureFauxqsServer } from './fauxqsInstance.ts'

await ensureFauxqsServer()
2 changes: 2 additions & 0 deletions packages/s3-payload-store/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export default defineConfig({
watch: false,
mockReset: true,
pool: 'threads',
maxWorkers: 1,
setupFiles: ['test/utils/vitest.setup.ts'],
coverage: {
provider: 'v8',
include: ['lib/**/*.ts'],
Expand Down
5 changes: 3 additions & 2 deletions packages/sns/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"test:coverage": "npm run test -- --coverage",
"lint": "biome check . && tsc",
"lint:fix": "biome check --write .",
"docker:start": "docker compose up -d localstack redis",
"docker:start": "docker compose up -d redis && if [ \"$QUEUE_BACKEND\" = \"localstack\" ]; then docker compose up -d --quiet-pull --wait localstack; fi",
"docker:stop": "docker compose down",
"prepublishOnly": "npm run lint && npm run build"
},
Expand Down Expand Up @@ -53,8 +53,9 @@
"@message-queue-toolkit/sqs": "*",
"@types/node": "^25.0.2",
"@vitest/coverage-v8": "^4.0.15",
"awilix": "^12.0.5",
"awilix": "^12.1.1",
"awilix-manager": "^6.1.0",
"fauxqs": "^1.10.0",
"ioredis": "^5.7.0",
"rimraf": "^6.0.1",
"typescript": "^5.9.3",
Expand Down
22 changes: 6 additions & 16 deletions packages/sns/test/consumers/CreateLocateConfigMixConsumer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,25 @@
import type { SNSClient } from '@aws-sdk/client-sns'
import type { SQSClient } from '@aws-sdk/client-sqs'
import type { STSClient } from '@aws-sdk/client-sts'
import { deleteQueue } from '@message-queue-toolkit/sqs'
import type { AwilixContainer } from 'awilix'
import { beforeAll, beforeEach, describe, it } from 'vitest'
import { assertTopic, deleteTopic } from '../../lib/utils/snsUtils.ts'
import type { TestAwsResourceAdmin } from '../utils/testAdmin.ts'
import { type Dependencies, registerDependencies } from '../utils/testContext.ts'
import { CreateLocateConfigMixConsumer } from './CreateLocateConfigMixConsumer.ts'

describe('CreateLocateConfigMixConsumer', () => {
let diContainer: AwilixContainer<Dependencies>
let sqsClient: SQSClient
let snsClient: SNSClient
let stsClient: STSClient
let testAdmin: TestAwsResourceAdmin

beforeAll(async () => {
diContainer = await registerDependencies({}, false)
sqsClient = diContainer.cradle.sqsClient
snsClient = diContainer.cradle.snsClient
stsClient = diContainer.cradle.stsClient
testAdmin = diContainer.cradle.testAdmin
})

beforeEach(async () => {
await deleteQueue(sqsClient, CreateLocateConfigMixConsumer.CONSUMED_QUEUE_NAME)
await deleteTopic(snsClient, stsClient, CreateLocateConfigMixConsumer.SUBSCRIBED_TOPIC_NAME)
await testAdmin.deleteQueues(CreateLocateConfigMixConsumer.CONSUMED_QUEUE_NAME)
await testAdmin.deleteTopics(CreateLocateConfigMixConsumer.SUBSCRIBED_TOPIC_NAME)
})

it('accepts mixed config of create and locate', async () => {
await assertTopic(snsClient, stsClient, {
Name: CreateLocateConfigMixConsumer.SUBSCRIBED_TOPIC_NAME,
})
await testAdmin.createTopic(CreateLocateConfigMixConsumer.SUBSCRIBED_TOPIC_NAME)
const consumer = new CreateLocateConfigMixConsumer(diContainer.cradle)
await consumer.init()
})
Expand Down
Loading