-
Notifications
You must be signed in to change notification settings - Fork 19
feat: add integration tests for Java, NestJS, and React generators #221
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
|
|
||
| "dagger.io/dagger" | ||
| "github.com/open-feature/cli/test/integration" | ||
| ) | ||
|
|
||
| // Test implements the integration test for the Java generator | ||
| type Test struct { | ||
| // ProjectDir is the absolute path to the root of the project | ||
| ProjectDir string | ||
| // TestDir is the absolute path to the test directory | ||
| TestDir string | ||
| } | ||
|
|
||
| // New creates a new Test | ||
| func New(projectDir, testDir string) *Test { | ||
| return &Test{ | ||
| ProjectDir: projectDir, | ||
| TestDir: testDir, | ||
| } | ||
| } | ||
|
|
||
| // Run executes the Java integration test using Dagger | ||
| func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Container, error) { | ||
| // Source code container | ||
| source := client.Host().Directory(t.ProjectDir) | ||
| testFiles := client.Host().Directory(t.TestDir, dagger.HostDirectoryOpts{ | ||
| Include: []string{"pom.xml", "src/**/*.java"}, | ||
| }) | ||
|
|
||
| // Build the CLI | ||
| cli := client.Container(). | ||
| From("golang:1.24-alpine"). | ||
| WithExec([]string{"apk", "add", "--no-cache", "git"}). | ||
| WithDirectory("/src", source). | ||
| WithWorkdir("/src"). | ||
| WithExec([]string{"go", "mod", "tidy"}). | ||
| WithExec([]string{"go", "mod", "download"}). | ||
| WithExec([]string{"go", "build", "-o", "cli", "./cmd/openfeature"}) | ||
|
|
||
| // Generate Java client | ||
| generated := cli.WithExec([]string{ | ||
| "./cli", "generate", "java", | ||
| "--manifest=/src/sample/sample_manifest.json", | ||
| "--output=/tmp/generated", | ||
| "--package-name=dev.openfeature.generated", | ||
| }) | ||
|
|
||
| // Get generated files | ||
| generatedFiles := generated.Directory("/tmp/generated") | ||
|
|
||
| // Test Java compilation with the generated files | ||
| javaContainer := client.Container(). | ||
| From("maven:3.9-eclipse-temurin-21-alpine"). | ||
| WithWorkdir("/app"). | ||
| WithDirectory("/app", testFiles). | ||
| WithDirectory("/app/src/main/java/dev/openfeature/generated", generatedFiles). | ||
| WithExec([]string{"mvn", "clean", "compile", "-B", "-q"}). | ||
| WithExec([]string{"mvn", "exec:java", "-Dexec.mainClass=dev.openfeature.Main", "-q"}) | ||
|
|
||
| return javaContainer, nil | ||
| } | ||
|
|
||
| // Name returns the name of the integration test | ||
| func (t *Test) Name() string { | ||
| return "java" | ||
| } | ||
|
|
||
| func main() { | ||
| ctx := context.Background() | ||
|
|
||
| // Get project root | ||
| projectDir, err := filepath.Abs(os.Getenv("PWD")) | ||
| if err != nil { | ||
| fmt.Fprintf(os.Stderr, "Failed to get project dir: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Get test directory | ||
| testDir, err := filepath.Abs(filepath.Join(projectDir, "test/java-integration")) | ||
| if err != nil { | ||
| fmt.Fprintf(os.Stderr, "Failed to get test dir: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Create and run the Java integration test | ||
| test := New(projectDir, testDir) | ||
|
|
||
| if err := integration.RunTest(ctx, test); err != nil { | ||
| fmt.Fprintf(os.Stderr, "Error: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
|
|
||
| "dagger.io/dagger" | ||
| "github.com/open-feature/cli/test/integration" | ||
| ) | ||
|
|
||
| // Test implements the integration test for the NestJS generator | ||
| type Test struct { | ||
| // ProjectDir is the absolute path to the root of the project | ||
| ProjectDir string | ||
| // TestDir is the absolute path to the test directory | ||
| TestDir string | ||
| } | ||
|
|
||
| // New creates a new Test | ||
| func New(projectDir, testDir string) *Test { | ||
| return &Test{ | ||
| ProjectDir: projectDir, | ||
| TestDir: testDir, | ||
| } | ||
| } | ||
|
|
||
| // Run executes the NestJS integration test using Dagger | ||
| func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Container, error) { | ||
| // Source code container | ||
| source := client.Host().Directory(t.ProjectDir) | ||
| testFiles := client.Host().Directory(t.TestDir, dagger.HostDirectoryOpts{ | ||
| Include: []string{"package.json", "tsconfig.json", "src/**/*.ts"}, | ||
| }) | ||
|
|
||
| // Build the CLI | ||
| cli := client.Container(). | ||
| From("golang:1.24-alpine"). | ||
| WithExec([]string{"apk", "add", "--no-cache", "git"}). | ||
| WithDirectory("/src", source). | ||
| WithWorkdir("/src"). | ||
| WithExec([]string{"go", "mod", "tidy"}). | ||
| WithExec([]string{"go", "mod", "download"}). | ||
| WithExec([]string{"go", "build", "-o", "cli", "./cmd/openfeature"}) | ||
|
|
||
| // Generate NestJS client | ||
| generated := cli.WithExec([]string{ | ||
| "./cli", "generate", "nestjs", | ||
| "--manifest=/src/sample/sample_manifest.json", | ||
| "--output=/tmp/generated", | ||
| }) | ||
|
|
||
| // Get generated files | ||
| generatedFiles := generated.Directory("/tmp/generated") | ||
|
|
||
| // Test NestJS compilation with the generated files | ||
| nestjsContainer := client.Container(). | ||
| From("node:20-alpine"). | ||
| WithWorkdir("/app"). | ||
| WithDirectory("/app", testFiles). | ||
| WithDirectory("/app/src/generated", generatedFiles). | ||
| WithExec([]string{"npm", "install"}). | ||
| WithExec([]string{"npm", "run", "build"}). | ||
| WithExec([]string{"node", "dist/main.js"}) | ||
|
|
||
| return nestjsContainer, nil | ||
| } | ||
|
|
||
| // Name returns the name of the integration test | ||
| func (t *Test) Name() string { | ||
| return "nestjs" | ||
| } | ||
|
|
||
| func main() { | ||
| ctx := context.Background() | ||
|
|
||
| // Get project root | ||
| projectDir, err := filepath.Abs(os.Getenv("PWD")) | ||
| if err != nil { | ||
| fmt.Fprintf(os.Stderr, "Failed to get project dir: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Get test directory | ||
| testDir, err := filepath.Abs(filepath.Join(projectDir, "test/nestjs-integration")) | ||
| if err != nil { | ||
| fmt.Fprintf(os.Stderr, "Failed to get test dir: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Create and run the NestJS integration test | ||
| test := New(projectDir, testDir) | ||
|
|
||
| if err := integration.RunTest(ctx, test); err != nil { | ||
| fmt.Fprintf(os.Stderr, "Error: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
|
|
||
| "dagger.io/dagger" | ||
| "github.com/open-feature/cli/test/integration" | ||
| ) | ||
|
|
||
| // Test implements the integration test for the React generator | ||
| type Test struct { | ||
| // ProjectDir is the absolute path to the root of the project | ||
| ProjectDir string | ||
| // TestDir is the absolute path to the test directory | ||
| TestDir string | ||
| } | ||
|
|
||
| // New creates a new Test | ||
| func New(projectDir, testDir string) *Test { | ||
| return &Test{ | ||
| ProjectDir: projectDir, | ||
| TestDir: testDir, | ||
| } | ||
| } | ||
|
|
||
| // Run executes the React integration test using Dagger | ||
| func (t *Test) Run(ctx context.Context, client *dagger.Client) (*dagger.Container, error) { | ||
| // Source code container | ||
| source := client.Host().Directory(t.ProjectDir) | ||
| testFiles := client.Host().Directory(t.TestDir, dagger.HostDirectoryOpts{ | ||
| Include: []string{"package.json", "tsconfig.json", "src/**/*.ts", "src/**/*.tsx"}, | ||
| }) | ||
|
|
||
| // Build the CLI | ||
| cli := client.Container(). | ||
| From("golang:1.24-alpine"). | ||
| WithExec([]string{"apk", "add", "--no-cache", "git"}). | ||
| WithDirectory("/src", source). | ||
| WithWorkdir("/src"). | ||
| WithExec([]string{"go", "mod", "tidy"}). | ||
| WithExec([]string{"go", "mod", "download"}). | ||
| WithExec([]string{"go", "build", "-o", "cli", "./cmd/openfeature"}) | ||
|
|
||
| // Generate React client | ||
| generated := cli.WithExec([]string{ | ||
| "./cli", "generate", "react", | ||
| "--manifest=/src/sample/sample_manifest.json", | ||
| "--output=/tmp/generated", | ||
| }) | ||
|
|
||
| // Get generated files | ||
| generatedFiles := generated.Directory("/tmp/generated") | ||
|
|
||
| // Test React compilation with the generated files | ||
| reactContainer := client.Container(). | ||
| From("node:20-alpine"). | ||
| WithWorkdir("/app"). | ||
| WithDirectory("/app", testFiles). | ||
| WithDirectory("/app/src/generated", generatedFiles). | ||
| WithExec([]string{"npm", "install"}). | ||
| WithExec([]string{"npm", "run", "build"}). | ||
| WithExec([]string{"node", "dist/test.js"}) | ||
|
|
||
| return reactContainer, nil | ||
| } | ||
|
|
||
| // Name returns the name of the integration test | ||
| func (t *Test) Name() string { | ||
| return "react" | ||
| } | ||
|
|
||
| func main() { | ||
| ctx := context.Background() | ||
|
|
||
| // Get project root | ||
| projectDir, err := filepath.Abs(os.Getenv("PWD")) | ||
| if err != nil { | ||
| fmt.Fprintf(os.Stderr, "Failed to get project dir: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Get test directory | ||
| testDir, err := filepath.Abs(filepath.Join(projectDir, "test/react-integration")) | ||
| if err != nil { | ||
| fmt.Fprintf(os.Stderr, "Failed to get test dir: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Create and run the React integration test | ||
| test := New(projectDir, testDir) | ||
|
|
||
| if err := integration.RunTest(ctx, test); err != nil { | ||
| fmt.Fprintf(os.Stderr, "Error: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,6 +45,33 @@ func main() { | |
| os.Exit(1) | ||
| } | ||
|
|
||
| // Run the Java integration test | ||
| javaCmd := exec.Command("go", "run", "github.com/open-feature/cli/test/integration/cmd/java") | ||
| javaCmd.Stdout = os.Stdout | ||
| javaCmd.Stderr = os.Stderr | ||
| if err := javaCmd.Run(); err != nil { | ||
| fmt.Fprintf(os.Stderr, "Error running Java integration test: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Run the NestJS integration test | ||
| nestjsCmd := exec.Command("go", "run", "github.com/open-feature/cli/test/integration/cmd/nestjs") | ||
| nestjsCmd.Stdout = os.Stdout | ||
| nestjsCmd.Stderr = os.Stderr | ||
| if err := nestjsCmd.Run(); err != nil { | ||
| fmt.Fprintf(os.Stderr, "Error running NestJS integration test: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
|
||
| // Run the React integration test | ||
| reactCmd := exec.Command("go", "run", "github.com/open-feature/cli/test/integration/cmd/react") | ||
| reactCmd.Stdout = os.Stdout | ||
| reactCmd.Stderr = os.Stderr | ||
| if err := reactCmd.Run(); err != nil { | ||
| fmt.Fprintf(os.Stderr, "Error running React integration test: %v\n", err) | ||
| os.Exit(1) | ||
| } | ||
|
Comment on lines
+48
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main integration test runner executes each test sequentially. This can be inefficient, especially as more tests are added. The PR description also mentions that tests can run in parallel. To improve performance and align with that benefit, consider refactoring this to run the tests concurrently using goroutines and a Here's a conceptual example of how you could structure it: func main() {
fmt.Println("=== Running all integration tests ===")
tests := map[string]string{
"C#": "github.com/open-feature/cli/test/integration/cmd/csharp",
"Go": "github.com/open-feature/cli/test/integration/cmd/go",
"NodeJS": "github.com/open-feature/cli/test/integration/cmd/nodejs",
"Angular": "github.com/open-feature/cli/test/integration/cmd/angular",
"Java": "github.com/open-feature/cli/test/integration/cmd/java",
"NestJS": "github.com/open-feature/cli/test/integration/cmd/nestjs",
"React": "github.com/open-feature/cli/test/integration/cmd/react",
}
var wg sync.WaitGroup
errChan := make(chan error, len(tests))
for name, path := range tests {
wg.Add(1)
go func(name, path string) {
defer wg.Done()
cmd := exec.Command("go", "run", path)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
errChan <- fmt.Errorf("error running %s integration test: %w", name, err)
}
}(name, path)
}
wg.Wait()
close(errChan)
hasErrors := false
for err := range errChan {
fmt.Fprintln(os.Stderr, err)
hasErrors = true
}
if hasErrors {
os.Exit(1)
}
fmt.Println("=== All integration tests passed successfully ===")
} |
||
|
|
||
| // Add more tests here as they are available | ||
|
|
||
| fmt.Println("=== All integration tests passed successfully ===") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a significant amount of duplicated code for building the CLI across the new integration test runners (
java/run.go,nestjs/run.go,react/run.go). This logic is identical in each file.To improve maintainability and reduce redundancy, consider refactoring this into a shared helper function within the
integrationpackage.For example, you could create a
BuildCLIfunction intest/integration/integration.go:Then, you could call it from each test runner like this: