Skip to content
Merged
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
10 changes: 8 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,14 @@ jobs:
uv python install
uv pip install modal

- run: modal deploy test-support/libmodal_test_support.py
- run: test-support/setup.sh
env:
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
MODAL_ENVIRONMENT: libmodal
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1

- run: npm test
working-directory: ./modal-js
Expand All @@ -75,11 +78,14 @@ jobs:
uv python install
uv pip install modal

- run: modal deploy test-support/libmodal_test_support.py
- run: test-support/setup.sh
env:
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
MODAL_ENVIRONMENT: libmodal
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1

- name: Set up Go
uses: actions/setup-go@v5
Expand Down
9 changes: 5 additions & 4 deletions modal-go/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,14 @@ func (app *App) CreateSandbox(image *Image, options *SandboxOptions) (*Sandbox,

// ImageFromRegistry creates an Image from a registry tag.
func (app *App) ImageFromRegistry(tag string) (*Image, error) {
return fromRegistryInternal(app, tag, &pb.ImageRegistryConfig{})
return fromRegistryInternal(app, tag, nil)
}

// ImageFromAwsEcr creates an Image from an AWS ECR tag, and secret for auth.
func (app *App) ImageFromAwsEcr(tag string, secret *Secret) (*Image, error) {
imageRegistryConfig := &pb.ImageRegistryConfig{}
imageRegistryConfig.SetRegistryAuthType(pb.RegistryAuthType_REGISTRY_AUTH_TYPE_AWS)
imageRegistryConfig.SetSecretId(secret.SecretId)
imageRegistryConfig := pb.ImageRegistryConfig_builder{
RegistryAuthType: pb.RegistryAuthType_REGISTRY_AUTH_TYPE_AWS,
SecretId: secret.SecretId,
}.Build()
return fromRegistryInternal(app, tag, imageRegistryConfig)
}
2 changes: 1 addition & 1 deletion modal-go/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,5 @@ func environmentName(environment string) string {
}

func imageBuilderVersion(version string) string {
return firstNonEmpty(version, defaultProfile.ImageBuilderVersion)
return firstNonEmpty(version, defaultProfile.ImageBuilderVersion, "2024.10")
}
2 changes: 1 addition & 1 deletion modal-go/examples/sandbox-private-image/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
log.Fatalf("Failed to lookup or create app: %v", err)
}

secret, err := modal.SecretFromName(ctx, "aws-ecr-private-registry-test-secret", &modal.SecretFromNameOptions{
secret, err := modal.SecretFromName(ctx, "libmodal-aws-ecr-test", &modal.SecretFromNameOptions{
RequiredKeys: []string{"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"},
})
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions modal-go/test/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ func TestImageFromAwsEcr(t *testing.T) {
app, err := modal.AppLookup(context.Background(), "libmodal-test", &modal.LookupOptions{CreateIfMissing: true})
g.Expect(err).ShouldNot(gomega.HaveOccurred())

secret, err := modal.SecretFromName(context.Background(), "aws-ecr-private-registry-test-secret", &modal.SecretFromNameOptions{
Environment: "libmodal",
secret, err := modal.SecretFromName(context.Background(), "libmodal-aws-ecr-test", &modal.SecretFromNameOptions{
RequiredKeys: []string{"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"},
})
g.Expect(err).ShouldNot(gomega.HaveOccurred())
Expand Down
16 changes: 3 additions & 13 deletions modal-go/test/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,24 @@ import (
func TestSecretFromName(t *testing.T) {
t.Parallel()
g := gomega.NewWithT(t)
secret, err := modal.SecretFromName(context.Background(), "test-secret", nil)
secret, err := modal.SecretFromName(context.Background(), "libmodal-test-secret", nil)
g.Expect(err).ShouldNot(gomega.HaveOccurred())
g.Expect(secret.SecretId).Should(gomega.HavePrefix("st-"))

_, err = modal.SecretFromName(context.Background(), "missing-secret", nil)
g.Expect(err).Should(gomega.MatchError(gomega.ContainSubstring("Secret 'missing-secret' not found")))
}

func TestSecretFromNameWithEnvironment(t *testing.T) {
t.Parallel()
g := gomega.NewWithT(t)
secret, err := modal.SecretFromName(context.Background(), "test-secret", &modal.SecretFromNameOptions{
Environment: "libmodal",
})
g.Expect(err).ShouldNot(gomega.HaveOccurred())
g.Expect(secret.SecretId).Should(gomega.HavePrefix("st-"))
}

func TestSecretFromNameWithRequiredKeys(t *testing.T) {
t.Parallel()
g := gomega.NewWithT(t)
secret, err := modal.SecretFromName(context.Background(), "test-secret", &modal.SecretFromNameOptions{
secret, err := modal.SecretFromName(context.Background(), "libmodal-test-secret", &modal.SecretFromNameOptions{
RequiredKeys: []string{"a", "b", "c"},
})
g.Expect(err).ShouldNot(gomega.HaveOccurred())
g.Expect(secret.SecretId).Should(gomega.HavePrefix("st-"))

_, err = modal.SecretFromName(context.Background(), "test-secret", &modal.SecretFromNameOptions{
_, err = modal.SecretFromName(context.Background(), "libmodal-test-secret", &modal.SecretFromNameOptions{
RequiredKeys: []string{"a", "b", "c", "missing-key"},
})
g.Expect(err).Should(gomega.MatchError(gomega.ContainSubstring("Secret is missing key(s): missing-key")))
Expand Down
2 changes: 1 addition & 1 deletion modal-js/examples/sandbox-private-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { App, Secret } from "modal";
const app = await App.lookup("libmodal-example", { createIfMissing: true });
const image = await app.imageFromAwsEcr(
"459781239556.dkr.ecr.us-east-1.amazonaws.com/ecr-private-registry-test-7522615:python",
await Secret.fromName("aws-ecr-private-registry-test-secret", {
await Secret.fromName("libmodal-aws-ecr-test", {
requiredKeys: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"],
}),
);
Expand Down
7 changes: 3 additions & 4 deletions modal-js/test/image.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { App, Secret } from "modal";
import { expect, test } from "vitest";

test("ImageFromRegistry", { timeout: 30_000 }, async () => {
test("ImageFromRegistry", async () => {
const app = await App.lookup("libmodal-test", { createIfMissing: true });
expect(app.appId).toBeTruthy();

Expand All @@ -10,14 +10,13 @@ test("ImageFromRegistry", { timeout: 30_000 }, async () => {
expect(image.imageId).toMatch(/^im-/);
});

test("ImageFromAwsEcr", { timeout: 30_000 }, async () => {
test("ImageFromAwsEcr", async () => {
const app = await App.lookup("libmodal-test", { createIfMissing: true });
expect(app.appId).toBeTruthy();

const image = await app.imageFromAwsEcr(
"459781239556.dkr.ecr.us-east-1.amazonaws.com/ecr-private-registry-test-7522615:python",
await Secret.fromName("aws-ecr-private-registry-test-secret", {
environment: "libmodal",
await Secret.fromName("libmodal-aws-ecr-test", {
requiredKeys: ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"],
}),
);
Expand Down
13 changes: 3 additions & 10 deletions modal-js/test/secret.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Secret } from "modal";
import { expect, test } from "vitest";

test("SecretFromName", async () => {
const secret = await Secret.fromName("test-secret");
const secret = await Secret.fromName("libmodal-test-secret");
expect(secret).toBeDefined();
expect(secret.secretId).toBeDefined();
expect(secret.secretId).toMatch(/^st-/);
Expand All @@ -13,20 +13,13 @@ test("SecretFromName", async () => {
);
});

test("SecretFromNameWithEnvironment", async () => {
const secret = await Secret.fromName("test-secret", {
environment: "libmodal",
});
expect(secret).toBeDefined();
});

test("SecretFromNameWithRequiredKeys", async () => {
const secret = await Secret.fromName("test-secret", {
const secret = await Secret.fromName("libmodal-test-secret", {
requiredKeys: ["a", "b", "c"],
});
expect(secret).toBeDefined();

const promise = Secret.fromName("test-secret", {
const promise = Secret.fromName("libmodal-test-secret", {
requiredKeys: ["a", "b", "c", "missing-key"],
});
await expect(promise).rejects.toThrowError(
Expand Down
11 changes: 6 additions & 5 deletions test-support/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# Test support for libmodal

Sign in to a Modal account, which you'll use for running the test programs.
Sign in to Modal, which you'll use for running the test programs.

Then deploy the apps in this folder using the Python client:
Then deploy the apps and secrets in this folder using the Python client. This
requires being signed in to AWS (Modal Labs account):

```bash
modal deploy libmodal_test_support.py
test-support/setup.sh
```

This deployed app will be called from tests in each language.
Now you can run tests in each language.

```bash
# JavaScript
cd modal-js && npm test
cd modal-js && npm run build && npm test

# Go
cd modal-go && go test -v -count=1 -parallel=10 ./test
Expand Down
21 changes: 21 additions & 0 deletions test-support/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

set -euo pipefail

cd "$(dirname "$0")"

modal deploy libmodal_test_support.py

echo "Deploying libmodal-test-secret..."
modal secret create --force libmodal-test-secret \
a=1 b=2 c="hello world" >/dev/null

# Must be signed into AWS CLI for Modal Labs
echo "Deploying libmodal-aws-ecr-test..."
ecr_test_secret=$(aws secretsmanager get-secret-value \
--secret-id test/libmodal/AwsEcrTest --query 'SecretString' --output text)
modal secret create --force libmodal-aws-ecr-test \
AWS_ACCESS_KEY_ID="$(echo "$ecr_test_secret" | jq -r '.AWS_ACCESS_KEY_ID')" \
AWS_SECRET_ACCESS_KEY="$(echo "$ecr_test_secret" | jq -r '.AWS_SECRET_ACCESS_KEY')" \
AWS_REGION=us-east-1 \
>/dev/null