feat(model): add Application model and store
Add Application and ParameterSchema models with CRUD store. Includes 10 store tests and ParamType constants. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
227
internal/store/application_store_test.go
Normal file
227
internal/store/application_store_test.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"gcy_hpc_server/internal/model"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
func newAppTestDB(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("open sqlite: %v", err)
|
||||
}
|
||||
if err := db.AutoMigrate(&model.Application{}); err != nil {
|
||||
t.Fatalf("auto migrate: %v", err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
func TestApplicationStore_Create_Success(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
id, err := s.Create(context.Background(), &model.CreateApplicationRequest{
|
||||
Name: "gromacs",
|
||||
Description: "Molecular dynamics simulator",
|
||||
Category: "simulation",
|
||||
ScriptTemplate: "#!/bin/bash\nmodule load gromacs",
|
||||
Parameters: []byte(`[{"name":"ntasks","type":"number","required":true}]`),
|
||||
Scope: "system",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Create() error = %v", err)
|
||||
}
|
||||
if id <= 0 {
|
||||
t.Errorf("Create() id = %d, want positive", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_GetByID_Success(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
id, _ := s.Create(context.Background(), &model.CreateApplicationRequest{
|
||||
Name: "lammps",
|
||||
ScriptTemplate: "#!/bin/bash\nmodule load lammps",
|
||||
})
|
||||
|
||||
app, err := s.GetByID(context.Background(), id)
|
||||
if err != nil {
|
||||
t.Fatalf("GetByID() error = %v", err)
|
||||
}
|
||||
if app == nil {
|
||||
t.Fatal("GetByID() returned nil, expected application")
|
||||
}
|
||||
if app.Name != "lammps" {
|
||||
t.Errorf("Name = %q, want %q", app.Name, "lammps")
|
||||
}
|
||||
if app.ID != id {
|
||||
t.Errorf("ID = %d, want %d", app.ID, id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_GetByID_NotFound(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
app, err := s.GetByID(context.Background(), 99999)
|
||||
if err != nil {
|
||||
t.Fatalf("GetByID() error = %v", err)
|
||||
}
|
||||
if app != nil {
|
||||
t.Error("GetByID() expected nil for not-found, got non-nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_List_Pagination(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
s.Create(context.Background(), &model.CreateApplicationRequest{
|
||||
Name: "app-" + string(rune('A'+i)),
|
||||
ScriptTemplate: "#!/bin/bash\necho " + string(rune('A'+i)),
|
||||
})
|
||||
}
|
||||
|
||||
apps, total, err := s.List(context.Background(), 1, 3)
|
||||
if err != nil {
|
||||
t.Fatalf("List() error = %v", err)
|
||||
}
|
||||
if total != 5 {
|
||||
t.Errorf("total = %d, want 5", total)
|
||||
}
|
||||
if len(apps) != 3 {
|
||||
t.Errorf("len(apps) = %d, want 3", len(apps))
|
||||
}
|
||||
|
||||
apps2, total2, err := s.List(context.Background(), 2, 3)
|
||||
if err != nil {
|
||||
t.Fatalf("List() page 2 error = %v", err)
|
||||
}
|
||||
if total2 != 5 {
|
||||
t.Errorf("total2 = %d, want 5", total2)
|
||||
}
|
||||
if len(apps2) != 2 {
|
||||
t.Errorf("len(apps2) = %d, want 2", len(apps2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_Update_Success(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
id, _ := s.Create(context.Background(), &model.CreateApplicationRequest{
|
||||
Name: "orig",
|
||||
ScriptTemplate: "#!/bin/bash\necho original",
|
||||
})
|
||||
|
||||
newName := "updated"
|
||||
newDesc := "updated description"
|
||||
err := s.Update(context.Background(), id, &model.UpdateApplicationRequest{
|
||||
Name: &newName,
|
||||
Description: &newDesc,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Update() error = %v", err)
|
||||
}
|
||||
|
||||
app, _ := s.GetByID(context.Background(), id)
|
||||
if app.Name != "updated" {
|
||||
t.Errorf("Name = %q, want %q", app.Name, "updated")
|
||||
}
|
||||
if app.Description != "updated description" {
|
||||
t.Errorf("Description = %q, want %q", app.Description, "updated description")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_Update_NotFound(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
name := "nope"
|
||||
err := s.Update(context.Background(), 99999, &model.UpdateApplicationRequest{
|
||||
Name: &name,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("Update() expected error for not-found, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_Delete_Success(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
id, _ := s.Create(context.Background(), &model.CreateApplicationRequest{
|
||||
Name: "to-delete",
|
||||
ScriptTemplate: "#!/bin/bash\necho bye",
|
||||
})
|
||||
|
||||
err := s.Delete(context.Background(), id)
|
||||
if err != nil {
|
||||
t.Fatalf("Delete() error = %v", err)
|
||||
}
|
||||
|
||||
app, _ := s.GetByID(context.Background(), id)
|
||||
if app != nil {
|
||||
t.Error("GetByID() after delete returned non-nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_Delete_Idempotent(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
err := s.Delete(context.Background(), 99999)
|
||||
if err != nil {
|
||||
t.Fatalf("Delete() non-existent error = %v, want nil (idempotent)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_Create_DuplicateName(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
_, err := s.Create(context.Background(), &model.CreateApplicationRequest{
|
||||
Name: "dup-app",
|
||||
ScriptTemplate: "#!/bin/bash\necho 1",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("first Create() error = %v", err)
|
||||
}
|
||||
|
||||
_, err = s.Create(context.Background(), &model.CreateApplicationRequest{
|
||||
Name: "dup-app",
|
||||
ScriptTemplate: "#!/bin/bash\necho 2",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for duplicate name, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplicationStore_Create_EmptyParameters(t *testing.T) {
|
||||
db := newAppTestDB(t)
|
||||
s := NewApplicationStore(db)
|
||||
|
||||
id, err := s.Create(context.Background(), &model.CreateApplicationRequest{
|
||||
Name: "no-params",
|
||||
ScriptTemplate: "#!/bin/bash\necho hello",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Create() error = %v", err)
|
||||
}
|
||||
|
||||
app, _ := s.GetByID(context.Background(), id)
|
||||
if string(app.Parameters) != "[]" {
|
||||
t.Errorf("Parameters = %q, want []", string(app.Parameters))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user