- Fix YAML tags in auth config struct (json -> yaml) - Update CLI configs to use pre-hashed API keys - Remove double hashing in WebSocket client - Fix port mapping (9102 -> 9103) in CLI commands - Update permission keys to use jobs:read, jobs:create, etc. - Clean up all debug logging from CLI and server - All user roles now authenticate correctly: * Admin: Can queue jobs and see all jobs * Researcher: Can queue jobs and see own jobs * Analyst: Can see status (read-only access) Multi-user authentication is now fully functional.
154 lines
4.4 KiB
Go
154 lines
4.4 KiB
Go
package tests
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/jfraeys/fetch_ml/internal/fileutil"
|
|
tests "github.com/jfraeys/fetch_ml/tests/fixtures"
|
|
)
|
|
|
|
// TestExampleProjects validates that all example projects have valid structure
|
|
func TestExampleProjects(t *testing.T) {
|
|
// Use fixtures for examples directory operations
|
|
examplesDir := tests.NewExamplesDir("../fixtures/examples")
|
|
|
|
projects := []string{
|
|
"standard_ml_project",
|
|
"sklearn_project",
|
|
"xgboost_project",
|
|
"pytorch_project",
|
|
"tensorflow_project",
|
|
"statsmodels_project",
|
|
}
|
|
|
|
for _, project := range projects {
|
|
t.Run(project, func(t *testing.T) {
|
|
projectDir := examplesDir.GetPath(project)
|
|
|
|
// Check project directory exists
|
|
t.Logf("Checking project directory: %s", projectDir)
|
|
if _, err := os.Stat(projectDir); os.IsNotExist(err) {
|
|
t.Fatalf("Example project %s does not exist", project)
|
|
}
|
|
|
|
// Check required files
|
|
requiredFiles := []string{"train.py", "requirements.txt", "README.md"}
|
|
for _, file := range requiredFiles {
|
|
filePath := filepath.Join(projectDir, file)
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
t.Errorf("Missing required file %s in project %s", file, project)
|
|
}
|
|
}
|
|
|
|
// Validate train.py is executable
|
|
trainPath := filepath.Join(projectDir, "train.py")
|
|
info, err := os.Stat(trainPath)
|
|
if err != nil {
|
|
t.Fatalf("Cannot stat train.py: %v", err)
|
|
}
|
|
if info.Mode().Perm()&0111 == 0 {
|
|
t.Errorf("train.py should be executable in project %s", project)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Helper function to execute commands and return output
|
|
func executeCommand(name string, args ...string) (string, error) {
|
|
cmd := exec.CommandContext(context.Background(), name, args...)
|
|
output, err := cmd.CombinedOutput()
|
|
return string(output), err
|
|
}
|
|
|
|
// TestExampleExecution tests that examples can be executed (dry run)
|
|
func TestExampleExecution(t *testing.T) {
|
|
examplesDir := "../fixtures/examples"
|
|
|
|
projects := []string{
|
|
"standard_ml_project",
|
|
"sklearn_project",
|
|
}
|
|
|
|
for _, project := range projects {
|
|
t.Run(project, func(t *testing.T) {
|
|
projectDir := filepath.Join(examplesDir, project)
|
|
trainScript := filepath.Join(projectDir, "train.py")
|
|
|
|
// Test script syntax by checking if it can be parsed
|
|
output, err := executeCommand("python3", "-m", "py_compile", trainScript)
|
|
if err != nil {
|
|
t.Errorf("Failed to compile %s: %v", project, err)
|
|
}
|
|
|
|
// If compilation succeeds, the syntax is valid
|
|
if len(output) > 0 {
|
|
t.Logf("Compilation output for %s: %s", project, output)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestPodmanWorkspaceSync tests example projects structure using temporary directory
|
|
func TestPodmanWorkspaceSync(t *testing.T) {
|
|
// Use fixtures for examples directory operations
|
|
examplesDir := tests.NewExamplesDir("../fixtures/examples")
|
|
|
|
// Use temporary directory for test workspace
|
|
tempDir := t.TempDir()
|
|
podmanDir := filepath.Join(tempDir, "podman/workspace")
|
|
|
|
// Copy examples to temp workspace
|
|
if err := os.MkdirAll(podmanDir, 0750); err != nil {
|
|
t.Fatalf("Failed to create test workspace: %v", err)
|
|
}
|
|
|
|
// Get list of example projects using fixtures
|
|
entries, err := os.ReadDir("../fixtures/examples")
|
|
if err != nil {
|
|
t.Fatalf("Failed to read examples directory: %v", err)
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
if !entry.IsDir() {
|
|
continue
|
|
}
|
|
|
|
projectName := entry.Name()
|
|
|
|
// Copy project to temp workspace using fixtures
|
|
dstDir := filepath.Join(podmanDir, projectName)
|
|
err := examplesDir.CopyProject(projectName, dstDir)
|
|
if err != nil {
|
|
t.Fatalf("Failed to copy %s to test workspace: %v", projectName, err)
|
|
}
|
|
|
|
t.Run(projectName, func(t *testing.T) {
|
|
// Compare key files
|
|
files := []string{"train.py", "requirements.txt"}
|
|
for _, file := range files {
|
|
exampleFile := filepath.Join(examplesDir.GetPath(projectName), file)
|
|
podmanFile := filepath.Join(podmanDir, projectName, file)
|
|
|
|
exampleContent, err1 := fileutil.SecureFileRead(exampleFile)
|
|
podmanContent, err2 := fileutil.SecureFileRead(podmanFile)
|
|
|
|
if err1 != nil {
|
|
t.Errorf("Cannot read %s from examples/: %v", file, err1)
|
|
continue
|
|
}
|
|
if err2 != nil {
|
|
t.Errorf("Cannot read %s from test workspace: %v", file, err2)
|
|
continue
|
|
}
|
|
|
|
if string(exampleContent) != string(podmanContent) {
|
|
t.Errorf("File %s differs between examples/ and test workspace for project %s", file, projectName)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|