Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@ jobs:
images: samples/demo
directories: samples/demo/

- name: demo-redis
os: ubuntu-24.04
runOnPullRequest: true
app: demo-default
env: default
path: ./samples/demo/app-redis.bicep
deployArgs: -p image=sampleregistry:5000/samples/demo
exposeArgs: --application demo-default
# Use the preview (Radius.*) resource types for expose/delete.
previewFlag: true
uiTestFile: tests/demo/demo.app.spec.ts
expectRedisConnection: true
port: 3000
container: demo-default
enableDapr: false
images: samples/demo
directories: samples/demo/

- name: dapr
os: ubuntu-24.04
runOnPullRequest: true
Expand Down Expand Up @@ -290,6 +308,8 @@ jobs:
- name: Run Playwright Test
if: steps.gen-id.outputs.RUN_TEST == 'true' && matrix.uiTestFile != ''
id: run-playwright-test
env:
EXPECT_REDIS_CONNECTION: ${{ matrix.expectRedisConnection }}
run: |
if [[ "${{ matrix.container }}" != "" ]]; then
if [[ "${{ matrix.previewFlag }}" == "true" ]]; then
Expand Down
30 changes: 26 additions & 4 deletions playwright/tests/demo/demo.app.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,28 @@ test("To-Do App Basic UI Checks", async ({ page }) => {
await page.getByRole("link", { name: "Radius Demo" }).click();
});

test("Redis connection injects resource and secret values", async ({
request
}) => {
test.skip(
process.env.EXPECT_REDIS_CONNECTION !== "true",
"Redis connection assertions are only enabled for the Redis demo"
);

const endpoint = process.env.ENDPOINT;
expect(endpoint).toBeDefined();

const response = await request.get(
new URL("/api/container-info", endpoint as string).toString()
);
expect(response.ok()).toBeTruthy();

const containerInfo = await response.json();
expect(containerInfo.env.CONNECTION_REDIS_HOST).toBeTruthy();
expect(containerInfo.env.CONNECTION_REDIS_PORT).toBeTruthy();
expect(containerInfo.env.CONNECTION_REDIS_URL).toBeTruthy();
});

test("Add an item and check basic functionality", async ({ page }) => {
// Listen for all console events and handle errors
page.on("console", (msg) => {
Expand Down Expand Up @@ -81,15 +103,15 @@ test("Add an item and check basic functionality", async ({ page }) => {
await expect(
page
.getByRole("row", {
name: `${todoItem} lightbulb Complete done Delete delete`,
name: `${todoItem} lightbulb Complete done Delete delete`
})
.getByRole("button", { name: "Complete done" })
).toBeVisible();

// We click the Complete button
await page
.getByRole("row", {
name: `${todoItem} lightbulb Complete done Delete delete`,
name: `${todoItem} lightbulb Complete done Delete delete`
})
.getByRole("button", { name: "Complete done" })
.click();
Expand All @@ -98,15 +120,15 @@ test("Add an item and check basic functionality", async ({ page }) => {
await expect(
page
.getByRole("row", {
name: `${todoItem} done Complete done Delete delete`,
name: `${todoItem} done Complete done Delete delete`
})
.getByRole("button", { name: "Complete done" })
).toBeVisible();

// Delete a todo item
await page
.getByRole("row", {
name: `${todoItem} done Complete done Delete delete`,
name: `${todoItem} done Complete done Delete delete`
})
.getByRole("button", { name: "Delete delete" })
.click();
Expand Down
17 changes: 17 additions & 0 deletions samples/demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,20 @@ docker build \
--tag radius-demo:local \
samples/demo
```

## Deploy the Redis demo

`app-redis.bicep` deploys the demo application with a Redis cache and uses the
published demo image by default:

```sh
rad deploy samples/demo/app-redis.bicep
```

The `redis` connection provides both the Redis resource's non-secret values and
its secret outputs. Radius injects `CONNECTION_REDIS_HOST` and
`CONNECTION_REDIS_PORT` as normal environment variables, and injects the
generated Secret's `url` key as `CONNECTION_REDIS_URL` through a Kubernetes
`secretKeyRef`.

The demo uses `CONNECTION_REDIS_URL` for its Todo storage.
6 changes: 4 additions & 2 deletions samples/demo/app-redis.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ extension radius
@description('The Radius Environment ID. Injected automatically by the rad CLI.')
param environment string

// Defaults to the published image; CI overrides this to test the freshly built image.
param image string = 'ghcr.io/radius-project/samples/demo:latest'

// Environment name derived from the Environment ID, used to keep resource names
// unique per environment (e.g. dev/test/prod) within the same resource group.
var environmentName = last(split(environment, '/'))
Expand All @@ -21,7 +24,7 @@ resource demoContainer 'Radius.Compute/containers@2025-08-01-preview' = {
application: demoApp.id
containers: {
web: {
image: 'ghcr.io/radius-project/samples/demo:latest'
image: image
ports: {
web: {
containerPort: 3000
Expand All @@ -45,4 +48,3 @@ resource redis 'Radius.Data/redisCaches@2025-08-01-preview' = {
size: 'S'
}
}

23 changes: 0 additions & 23 deletions samples/demo/src/db/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,6 @@ export function createFactory(): RepositoryFactory {
return new RedisFactory(process.env.CONNECTION_REDIS_URL);
}

if (process.env.CONNECTION_REDIS_HOST) {
console.log("Using Redis: found hostname in environment variable CONNECTION_REDIS_HOST");
const connection = {
host: process.env.CONNECTION_REDIS_HOST!,
port: process.env.CONNECTION_REDIS_PORT!,
username: process.env.CONNECTION_REDIS_USERNAME || '',
password: process.env.CONNECTION_REDIS_PASSWORD || '',
}

let scheme = "redis"
if (connection.port === "6380") {
scheme = "rediss"
}

let usernamePass = "";
if (connection.username !== "" || connection.password !== "") {
usernamePass = `${connection.username}:${connection.password}@`
}

const url = `${scheme}://${usernamePass}${connection.host}:${connection.port}`
return new RedisFactory(url);
}

if (process.env.CONNECTION_POSTGRESQL_HOST) {
console.log("Using PostgreSQL: found hostname in environment variable CONNECTION_POSTGRESQL_HOST");
const connection = {
Expand Down
Loading