package bootstrap import ( "encoding/json" "errors" "os" "path/filepath" "strings" "testing" "github.com/fxamacker/cbor/v2" "github.com/tailscale/hujson" ) type fakeRow struct { scan func(dest ...any) error } func (row fakeRow) Scan(dest ...any) error { return row.scan(dest...) } func TestScanInstallationRecordDefaultsMaterializationStatus(t *testing.T) { record, err := scanInstallationRecord(fakeRow{scan: func(dest ...any) error { *(dest[0].(*string)) = "installation-1" *(dest[1].(*string)) = "MangoPig" *(dest[2].(*string)) = "personal" *(dest[3].(*string)) = "local" *(dest[4].(*string)) = "http" *(dest[5].(*string)) = "localhost" *(dest[6].(*bool)) = true *(dest[7].(*string)) = "" *(dest[8].(**string)) = nil return nil }}) if err != nil { t.Fatalf("scanInstallationRecord: %v", err) } if record.MaterializationStatus != materializationNotStarted { t.Fatalf("expected default materialization status %q, got %q", materializationNotStarted, record.MaterializationStatus) } if record.MaterializationError != nil { t.Fatalf("expected nil materialization error, got %#v", record.MaterializationError) } } func TestScanInstallationRecordPreservesMaterializationFields(t *testing.T) { failure := "projection rebuild failed" record, err := scanInstallationRecord(fakeRow{scan: func(dest ...any) error { *(dest[0].(*string)) = "installation-2" *(dest[1].(*string)) = "MangoPig" *(dest[2].(*string)) = "personal" *(dest[3].(*string)) = "local" *(dest[4].(*string)) = "http" *(dest[5].(*string)) = "localhost" *(dest[6].(*bool)) = true *(dest[7].(*string)) = materializationFailed *(dest[8].(**string)) = &failure return nil }}) if err != nil { t.Fatalf("scanInstallationRecord: %v", err) } if record.MaterializationStatus != materializationFailed { t.Fatalf("expected materialization status %q, got %q", materializationFailed, record.MaterializationStatus) } if record.MaterializationError == nil || *record.MaterializationError != failure { t.Fatalf("expected materialization error %q, got %#v", failure, record.MaterializationError) } } func TestEnsureBootstrapPOSIXSkeletonInitializesEmptyRoot(t *testing.T) { rootPath := filepath.Join(t.TempDir(), "POSIX") t.Setenv("POSIX_ROOT", rootPath) if _, err := os.Stat(rootPath); !os.IsNotExist(err) { t.Fatalf("expected isolated POSIX root to start absent, got err=%v", err) } service := NewService(nil, os.Getenv("POSIX_ROOT")) err := service.ensureBootstrapPOSIXSkeleton( InstallationRecord{ ID: "installation-1", Name: "MangoPig", Mode: "personal", Access: "local", Protocol: "http", Host: "localhost", IsBootstrapped: true, }, AdminSummary{ ID: "admin-1", Email: "ronald@example.com", DisplayName: "Ronald", }, namedRecord{ID: "org-1", Name: "Primary Organization", Slug: "primary-organization"}, namedRecord{ID: "dept-1", Name: "Primary Department", Slug: "primary-department"}, namedRecord{ID: "team-1", Name: "Primary Team", Slug: "primary-team"}, namedRecord{ID: "project-1", Name: "Primary Project", Slug: "primary-project"}, ) if err != nil { t.Fatalf("ensure bootstrap POSIX skeleton: %v", err) } requiredPaths := []string{ filepath.Join(rootPath, posixSettingsFileName), filepath.Join(rootPath, posixLayoutFileName), filepath.Join(rootPath, "catalog", "packs"), filepath.Join(rootPath, "catalog", "standalone"), filepath.Join(rootPath, "catalog", "packs", "pack-core", posixManifestFileName), filepath.Join(rootPath, "catalog", "packs", "pack-core", "entries", "app-shell", posixManifestFileName), filepath.Join(rootPath, "catalog", "standalone", "app-shell", posixManifestFileName), filepath.Join(rootPath, "departments", "department-primary-department", posixSettingsFileName), filepath.Join(rootPath, "departments", "department-primary-department", posixUsersFileName), filepath.Join(rootPath, "departments", "department-primary-department", "teams", "team-primary-team", posixSettingsFileName), filepath.Join(rootPath, "departments", "department-primary-department", "teams", "team-primary-team", posixUsersFileName), filepath.Join(rootPath, "projects", "project-primary-project", posixSettingsFileName), filepath.Join(rootPath, "projects", "project-primary-project", posixHomeFileName), filepath.Join(rootPath, "projects", "project-primary-project", posixACLFileName), filepath.Join(rootPath, "projects", "project-primary-project", "children"), filepath.Join(rootPath, "projects", "project-primary-project", "tree"), filepath.Join(rootPath, "users", posixSettingsFileName), filepath.Join(rootPath, "users", posixDataFileName), filepath.Join(rootPath, "users", "personals"), filepath.Join(rootPath, "users", "personals", "personal-ronald", posixSettingsFileName), filepath.Join(rootPath, "users", "personals", "personal-ronald", posixLayoutFileName), filepath.Join(rootPath, "users", "personals", "personal-ronald", posixHomeFileName), filepath.Join(rootPath, "users", "personals", "personal-ronald", "tree"), } for _, path := range requiredPaths { if _, err := os.Stat(path); err != nil { t.Fatalf("expected path to exist %s: %v", path, err) } } settingsPayload := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, posixSettingsFileName)) installationPayload, ok := settingsPayload["installation"].(map[string]any) if !ok { t.Fatalf("%s missing installation object: %#v", posixSettingsFileName, settingsPayload) } if installationPayload["name"] != "MangoPig" { t.Fatalf("expected installation name MangoPig, got %#v", installationPayload["name"]) } if installationPayload["isBootstrapped"] != true { t.Fatalf("expected installation to be bootstrapped, got %#v", installationPayload["isBootstrapped"]) } layoutPayload := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, posixLayoutFileName)) homePayload, ok := layoutPayload["home"].(map[string]any) if !ok { t.Fatalf("%s missing home object: %#v", posixLayoutFileName, layoutPayload) } if homePayload["defaultProjectSlug"] != "primary-project" { t.Fatalf("expected default project slug primary-project, got %#v", homePayload["defaultProjectSlug"]) } packManifest := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, "catalog", "packs", "pack-core", posixManifestFileName)) if packManifest["type"] != "pack" { t.Fatalf("expected pack manifest type pack, got %#v", packManifest["type"]) } if packManifest["slug"] != "core" { t.Fatalf("expected pack manifest slug core, got %#v", packManifest["slug"]) } entryManifest := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, "catalog", "packs", "pack-core", "entries", "app-shell", posixManifestFileName)) runtimePayload, ok := entryManifest["runtime"].(map[string]any) if !ok { t.Fatalf("%s missing runtime object: %#v", posixManifestFileName, entryManifest) } if runtimePayload["path"] != "/v1/app-shell" { t.Fatalf("expected app-shell runtime path /v1/app-shell, got %#v", runtimePayload["path"]) } standaloneManifest := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, "catalog", "standalone", "app-shell", posixManifestFileName)) if standaloneManifest["source"] != "standalone" { t.Fatalf("expected standalone manifest source standalone, got %#v", standaloneManifest["source"]) } projectSettings := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, "projects", "project-primary-project", posixSettingsFileName)) if projectSettings["type"] != "project" { t.Fatalf("expected project settings type project, got %#v", projectSettings["type"]) } projectACL := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, "projects", "project-primary-project", posixACLFileName)) if projectACL["inherits"] != true { t.Fatalf("expected project acl to inherit by default, got %#v", projectACL["inherits"]) } usersSettings := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, "users", posixSettingsFileName)) if usersSettings["primaryAdminId"] != "admin-1" { t.Fatalf("expected primary admin id admin-1, got %#v", usersSettings["primaryAdminId"]) } personalSettings := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, "users", "personals", "personal-ronald", posixSettingsFileName)) if personalSettings["type"] != "personal" { t.Fatalf("expected personal settings type personal, got %#v", personalSettings["type"]) } if personalSettings["name"] != "Ronald" { t.Fatalf("expected personal name Ronald, got %#v", personalSettings["name"]) } if personalSettings["slug"] != "ronald" { t.Fatalf("expected personal slug ronald, got %#v", personalSettings["slug"]) } personalHome := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, "users", "personals", "personal-ronald", posixHomeFileName)) if personalHome["type"] != "personal-home" { t.Fatalf("expected personal home type personal-home, got %#v", personalHome["type"]) } if personalHome["title"] != "Ronald's Home" { t.Fatalf("expected personal home title Ronald's Home, got %#v", personalHome["title"]) } } func TestCreateProjectHierarchyFolderOnDiskCreatesExpectedFolderShape(t *testing.T) { rootPath := filepath.Join(t.TempDir(), "POSIX") service := NewService(nil, rootPath) err := service.ensureBootstrapPOSIXSkeleton( InstallationRecord{ID: "installation-1", Name: "MangoPig", Mode: "personal", Access: "local", Protocol: "http", Host: "localhost", IsBootstrapped: true}, AdminSummary{ID: "admin-1", Email: "ronald@example.com", DisplayName: "Ronald"}, namedRecord{ID: "org-1", Name: "Primary Organization", Slug: "primary-organization"}, namedRecord{ID: "dept-1", Name: "Primary Department", Slug: "primary-department"}, namedRecord{ID: "team-1", Name: "Primary Team", Slug: "primary-team"}, namedRecord{ID: "project-1", Name: "Primary Project", Slug: "primary-project"}, ) if err != nil { t.Fatalf("ensure bootstrap POSIX skeleton: %v", err) } createdPath, createdSlug, err := service.createProjectHierarchyFolderOnDisk("primary-project", "", "Design System") if err != nil { t.Fatalf("createProjectHierarchyFolderOnDisk root folder: %v", err) } if createdPath != "projects/project-primary-project/children/folder-design-system" { t.Fatalf("unexpected created path: %s", createdPath) } if createdSlug != "design-system" { t.Fatalf("unexpected created slug: %s", createdSlug) } createdFolderPath := filepath.Join(rootPath, "projects", "project-primary-project", "children", "folder-design-system") for _, path := range []string{ filepath.Join(createdFolderPath, posixFolderFileName), filepath.Join(createdFolderPath, posixACLFileName), filepath.Join(createdFolderPath, "children"), } { if _, err := os.Stat(path); err != nil { t.Fatalf("expected path to exist %s: %v", path, err) } } folderPayload := readStructuredFileForTest[map[string]any](t, filepath.Join(createdFolderPath, posixFolderFileName)) if strings.TrimSpace(asStringForTest(folderPayload["id"])) == "" { t.Fatalf("expected created folder to have stable id, got %#v", folderPayload["id"]) } if folderPayload["name"] != "Design System" { t.Fatalf("expected folder name Design System, got %#v", folderPayload["name"]) } if folderPayload["slug"] != "design-system" { t.Fatalf("expected folder slug design-system, got %#v", folderPayload["slug"]) } nestedPath, nestedSlug, err := service.createProjectHierarchyFolderOnDisk("primary-project", createdPath, "Research") if err != nil { t.Fatalf("createProjectHierarchyFolderOnDisk nested folder: %v", err) } if nestedPath != "projects/project-primary-project/children/folder-design-system/children/folder-research" { t.Fatalf("unexpected nested path: %s", nestedPath) } if nestedSlug != "research" { t.Fatalf("unexpected nested slug: %s", nestedSlug) } } func TestCreateProjectTreeFolderOnDiskCreatesExpectedFolderShape(t *testing.T) { rootPath := filepath.Join(t.TempDir(), "POSIX") service := NewService(nil, rootPath) err := service.ensureBootstrapPOSIXSkeleton( InstallationRecord{ID: "installation-1", Name: "MangoPig", Mode: "personal", Access: "local", Protocol: "http", Host: "localhost", IsBootstrapped: true}, AdminSummary{ID: "admin-1", Email: "ronald@example.com", DisplayName: "Ronald"}, namedRecord{ID: "org-1", Name: "Primary Organization", Slug: "primary-organization"}, namedRecord{ID: "dept-1", Name: "Primary Department", Slug: "primary-department"}, namedRecord{ID: "team-1", Name: "Primary Team", Slug: "primary-team"}, namedRecord{ID: "project-1", Name: "Primary Project", Slug: "primary-project"}, ) if err != nil { t.Fatalf("ensure bootstrap POSIX skeleton: %v", err) } createdPath, createdSlug, err := service.createProjectTreeFolderOnDisk("primary-project", "", "Docs") if err != nil { t.Fatalf("createProjectTreeFolderOnDisk root folder: %v", err) } if createdPath != "projects/project-primary-project/tree/folder-docs" { t.Fatalf("unexpected created path: %s", createdPath) } if createdSlug != "docs" { t.Fatalf("unexpected created slug: %s", createdSlug) } createdFolderPath := filepath.Join(rootPath, "projects", "project-primary-project", "tree", "folder-docs") for _, path := range []string{ filepath.Join(createdFolderPath, posixFolderFileName), filepath.Join(createdFolderPath, posixACLFileName), filepath.Join(createdFolderPath, "children"), } { if _, err := os.Stat(path); err != nil { t.Fatalf("expected path to exist %s: %v", path, err) } } nestedPath, nestedSlug, err := service.createProjectTreeFolderOnDisk("primary-project", createdPath, "Research") if err != nil { t.Fatalf("createProjectTreeFolderOnDisk nested folder: %v", err) } if nestedPath != "projects/project-primary-project/tree/folder-docs/children/folder-research" { t.Fatalf("unexpected nested path: %s", nestedPath) } if nestedSlug != "research" { t.Fatalf("unexpected nested slug: %s", nestedSlug) } } func TestRenameProjectHierarchyFolderOnDiskRenamesFolderShape(t *testing.T) { rootPath := filepath.Join(t.TempDir(), "POSIX") service := NewService(nil, rootPath) err := service.ensureBootstrapPOSIXSkeleton( InstallationRecord{ID: "installation-1", Name: "MangoPig", Mode: "personal", Access: "local", Protocol: "http", Host: "localhost", IsBootstrapped: true}, AdminSummary{ID: "admin-1", Email: "ronald@example.com", DisplayName: "Ronald"}, namedRecord{ID: "org-1", Name: "Primary Organization", Slug: "primary-organization"}, namedRecord{ID: "dept-1", Name: "Primary Department", Slug: "primary-department"}, namedRecord{ID: "team-1", Name: "Primary Team", Slug: "primary-team"}, namedRecord{ID: "project-1", Name: "Primary Project", Slug: "primary-project"}, ) if err != nil { t.Fatalf("ensure bootstrap POSIX skeleton: %v", err) } createdPath, _, err := service.createProjectHierarchyFolderOnDisk("primary-project", "", "Design System") if err != nil { t.Fatalf("createProjectHierarchyFolderOnDisk root folder: %v", err) } nestedPath, _, err := service.createProjectHierarchyFolderOnDisk("primary-project", createdPath, "Research") if err != nil { t.Fatalf("createProjectHierarchyFolderOnDisk nested folder: %v", err) } previousPath, renamedPath, err := service.renameProjectHierarchyFolderOnDisk("primary-project", createdPath, "Platform Design") if err != nil { t.Fatalf("renameProjectHierarchyFolderOnDisk: %v", err) } if previousPath != createdPath { t.Fatalf("expected previous path %s, got %s", createdPath, previousPath) } if renamedPath != "projects/project-primary-project/children/folder-platform-design" { t.Fatalf("unexpected renamed path: %s", renamedPath) } if _, err := os.Stat(filepath.Join(rootPath, filepath.FromSlash(createdPath))); !os.IsNotExist(err) { t.Fatalf("expected previous folder path to be gone, got err=%v", err) } renamedFolderPath := filepath.Join(rootPath, filepath.FromSlash(renamedPath)) if _, err := os.Stat(filepath.Join(renamedFolderPath, "children", filepath.Base(nestedPath))); err != nil { t.Fatalf("expected nested child folder to move with renamed parent: %v", err) } folderPayload := readStructuredFileForTest[map[string]any](t, filepath.Join(renamedFolderPath, posixFolderFileName)) if strings.TrimSpace(asStringForTest(folderPayload["id"])) == "" { t.Fatalf("expected renamed folder to preserve stable id, got %#v", folderPayload["id"]) } if folderPayload["name"] != "Platform Design" { t.Fatalf("expected renamed folder name Platform Design, got %#v", folderPayload["name"]) } if folderPayload["slug"] != "platform-design" { t.Fatalf("expected renamed folder slug platform-design, got %#v", folderPayload["slug"]) } if folderPayload["type"] != "folder" { t.Fatalf("expected renamed folder type folder, got %#v", folderPayload["type"]) } } func TestRenameProjectTreeFolderOnDiskRenamesFolderShape(t *testing.T) { rootPath := filepath.Join(t.TempDir(), "POSIX") service := NewService(nil, rootPath) err := service.ensureBootstrapPOSIXSkeleton( InstallationRecord{ID: "installation-1", Name: "MangoPig", Mode: "personal", Access: "local", Protocol: "http", Host: "localhost", IsBootstrapped: true}, AdminSummary{ID: "admin-1", Email: "ronald@example.com", DisplayName: "Ronald"}, namedRecord{ID: "org-1", Name: "Primary Organization", Slug: "primary-organization"}, namedRecord{ID: "dept-1", Name: "Primary Department", Slug: "primary-department"}, namedRecord{ID: "team-1", Name: "Primary Team", Slug: "primary-team"}, namedRecord{ID: "project-1", Name: "Primary Project", Slug: "primary-project"}, ) if err != nil { t.Fatalf("ensure bootstrap POSIX skeleton: %v", err) } createdPath, _, err := service.createProjectTreeFolderOnDisk("primary-project", "", "Docs") if err != nil { t.Fatalf("createProjectTreeFolderOnDisk root folder: %v", err) } previousPath, renamedPath, err := service.renameProjectTreeFolderOnDisk("primary-project", createdPath, "Specifications") if err != nil { t.Fatalf("renameProjectTreeFolderOnDisk: %v", err) } if previousPath != createdPath { t.Fatalf("expected previous path %s, got %s", createdPath, previousPath) } if renamedPath != "projects/project-primary-project/tree/folder-specifications" { t.Fatalf("unexpected renamed path: %s", renamedPath) } folderPayload := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, filepath.FromSlash(renamedPath), posixFolderFileName)) if folderPayload["name"] != "Specifications" { t.Fatalf("expected renamed folder name Specifications, got %#v", folderPayload["name"]) } if folderPayload["slug"] != "specifications" { t.Fatalf("expected renamed folder slug specifications, got %#v", folderPayload["slug"]) } } func TestMoveProjectHierarchyFolderOnDiskMovesFolderToNewParent(t *testing.T) { rootPath := filepath.Join(t.TempDir(), "POSIX") service := NewService(nil, rootPath) err := service.ensureBootstrapPOSIXSkeleton( InstallationRecord{ID: "installation-1", Name: "MangoPig", Mode: "personal", Access: "local", Protocol: "http", Host: "localhost", IsBootstrapped: true}, AdminSummary{ID: "admin-1", Email: "ronald@example.com", DisplayName: "Ronald"}, namedRecord{ID: "org-1", Name: "Primary Organization", Slug: "primary-organization"}, namedRecord{ID: "dept-1", Name: "Primary Department", Slug: "primary-department"}, namedRecord{ID: "team-1", Name: "Primary Team", Slug: "primary-team"}, namedRecord{ID: "project-1", Name: "Primary Project", Slug: "primary-project"}, ) if err != nil { t.Fatalf("ensure bootstrap POSIX skeleton: %v", err) } designPath, _, err := service.createProjectHierarchyFolderOnDisk("primary-project", "", "Design") if err != nil { t.Fatalf("create design folder: %v", err) } operationsPath, _, err := service.createProjectHierarchyFolderOnDisk("primary-project", "", "Operations") if err != nil { t.Fatalf("create operations folder: %v", err) } researchPath, _, err := service.createProjectHierarchyFolderOnDisk("primary-project", designPath, "Research") if err != nil { t.Fatalf("create research folder: %v", err) } nestedPath, _, err := service.createProjectHierarchyFolderOnDisk("primary-project", researchPath, "Interview Notes") if err != nil { t.Fatalf("create nested folder: %v", err) } previousPath, movedPath, err := service.moveProjectHierarchyFolderOnDisk("primary-project", researchPath, operationsPath) if err != nil { t.Fatalf("moveProjectHierarchyFolderOnDisk: %v", err) } if previousPath != researchPath { t.Fatalf("expected previous path %s, got %s", researchPath, previousPath) } if movedPath != "projects/project-primary-project/children/folder-operations/children/folder-research" { t.Fatalf("unexpected moved path: %s", movedPath) } if _, err := os.Stat(filepath.Join(rootPath, filepath.FromSlash(researchPath))); !os.IsNotExist(err) { t.Fatalf("expected previous folder path to be gone, got err=%v", err) } movedFolderPath := filepath.Join(rootPath, filepath.FromSlash(movedPath)) if _, err := os.Stat(filepath.Join(movedFolderPath, "children", filepath.Base(nestedPath))); err != nil { t.Fatalf("expected nested child folder to move with moved parent: %v", err) } folderPayload := readStructuredFileForTest[map[string]any](t, filepath.Join(movedFolderPath, posixFolderFileName)) if strings.TrimSpace(asStringForTest(folderPayload["id"])) == "" { t.Fatalf("expected moved folder to preserve stable id, got %#v", folderPayload["id"]) } if folderPayload["name"] != "Research" { t.Fatalf("expected moved folder name Research, got %#v", folderPayload["name"]) } if folderPayload["slug"] != "research" { t.Fatalf("expected moved folder slug research, got %#v", folderPayload["slug"]) } if folderPayload["type"] != "folder" { t.Fatalf("expected moved folder type folder, got %#v", folderPayload["type"]) } } func TestMoveProjectTreeFolderOnDiskMovesFolderToNewParent(t *testing.T) { rootPath := filepath.Join(t.TempDir(), "POSIX") service := NewService(nil, rootPath) err := service.ensureBootstrapPOSIXSkeleton( InstallationRecord{ID: "installation-1", Name: "MangoPig", Mode: "personal", Access: "local", Protocol: "http", Host: "localhost", IsBootstrapped: true}, AdminSummary{ID: "admin-1", Email: "ronald@example.com", DisplayName: "Ronald"}, namedRecord{ID: "org-1", Name: "Primary Organization", Slug: "primary-organization"}, namedRecord{ID: "dept-1", Name: "Primary Department", Slug: "primary-department"}, namedRecord{ID: "team-1", Name: "Primary Team", Slug: "primary-team"}, namedRecord{ID: "project-1", Name: "Primary Project", Slug: "primary-project"}, ) if err != nil { t.Fatalf("ensure bootstrap POSIX skeleton: %v", err) } docsPath, _, err := service.createProjectTreeFolderOnDisk("primary-project", "", "Docs") if err != nil { t.Fatalf("create docs folder: %v", err) } archivePath, _, err := service.createProjectTreeFolderOnDisk("primary-project", "", "Archive") if err != nil { t.Fatalf("create archive folder: %v", err) } previousPath, movedPath, err := service.moveProjectTreeFolderOnDisk("primary-project", docsPath, archivePath) if err != nil { t.Fatalf("moveProjectTreeFolderOnDisk: %v", err) } if previousPath != docsPath { t.Fatalf("expected previous path %s, got %s", docsPath, previousPath) } if movedPath != "projects/project-primary-project/tree/folder-archive/children/folder-docs" { t.Fatalf("unexpected moved path: %s", movedPath) } folderPayload := readStructuredFileForTest[map[string]any](t, filepath.Join(rootPath, filepath.FromSlash(movedPath), posixFolderFileName)) if folderPayload["name"] != "Docs" { t.Fatalf("expected moved folder name Docs, got %#v", folderPayload["name"]) } if folderPayload["slug"] != "docs" { t.Fatalf("expected moved folder slug docs, got %#v", folderPayload["slug"]) } } func TestMoveProjectHierarchyFolderOnDiskRejectsDescendantTarget(t *testing.T) { rootPath := filepath.Join(t.TempDir(), "POSIX") service := NewService(nil, rootPath) err := service.ensureBootstrapPOSIXSkeleton( InstallationRecord{ID: "installation-1", Name: "MangoPig", Mode: "personal", Access: "local", Protocol: "http", Host: "localhost", IsBootstrapped: true}, AdminSummary{ID: "admin-1", Email: "ronald@example.com", DisplayName: "Ronald"}, namedRecord{ID: "org-1", Name: "Primary Organization", Slug: "primary-organization"}, namedRecord{ID: "dept-1", Name: "Primary Department", Slug: "primary-department"}, namedRecord{ID: "team-1", Name: "Primary Team", Slug: "primary-team"}, namedRecord{ID: "project-1", Name: "Primary Project", Slug: "primary-project"}, ) if err != nil { t.Fatalf("ensure bootstrap POSIX skeleton: %v", err) } parentPath, _, err := service.createProjectHierarchyFolderOnDisk("primary-project", "", "Parent") if err != nil { t.Fatalf("create parent folder: %v", err) } childPath, _, err := service.createProjectHierarchyFolderOnDisk("primary-project", parentPath, "Child") if err != nil { t.Fatalf("create child folder: %v", err) } _, _, err = service.moveProjectHierarchyFolderOnDisk("primary-project", parentPath, childPath) if !errors.Is(err, ErrInvalidProjectFolderMove) { t.Fatalf("expected ErrInvalidProjectFolderMove, got %v", err) } } func TestBuildProjectHierarchyFolderTreeBuildsNestedStructure(t *testing.T) { rows := []projectHierarchyFolderRow{ {ID: "folder-design-id", Path: "projects/project-primary-project/children/folder-design", ParentPath: projectHierarchyRootPath("primary-project"), Label: "Design"}, {ID: "folder-research-id", Path: "projects/project-primary-project/children/folder-design/children/folder-research", ParentPath: "projects/project-primary-project/children/folder-design/children", Label: "Research"}, {ID: "folder-ops-id", Path: "projects/project-primary-project/children/folder-ops", ParentPath: projectHierarchyRootPath("primary-project"), Label: "Ops"}, } folders := buildProjectHierarchyFolderTree(rows, projectHierarchyRootPath("primary-project")) if len(folders) != 2 { t.Fatalf("expected 2 top-level folders, got %d", len(folders)) } if folders[0].Label != "Design" || folders[1].Label != "Ops" { t.Fatalf("unexpected top-level folder labels: %#v", folders) } if len(folders[0].Children) != 1 || folders[0].Children[0].Label != "Research" { t.Fatalf("unexpected nested folder structure: %#v", folders[0].Children) } if folders[0].ID != "folder-design-id" || folders[0].Path != "projects/project-primary-project/children/folder-design" { t.Fatalf("expected design folder to retain stable id/path, got %#v", folders[0]) } if folders[0].Children[0].ID != "folder-research-id" || folders[1].ID != "folder-ops-id" { t.Fatalf("expected nested/top-level folder ids to be preserved, got %#v / %#v", folders[0].Children[0], folders[1]) } } func TestApplyProjectHierarchyFolderOrderingOrdersRootAndChildrenByStableID(t *testing.T) { folders := []ProjectHierarchyFolderRecord{ { ID: "folder-design-id", Path: "projects/project-primary-project/children/folder-design", Label: "Design", Children: []ProjectHierarchyFolderRecord{ {ID: "folder-research-id", Path: "projects/project-primary-project/children/folder-design/children/folder-research", Label: "Research"}, {ID: "folder-assets-id", Path: "projects/project-primary-project/children/folder-design/children/folder-assets", Label: "Assets"}, }, }, {ID: "folder-ops-id", Path: "projects/project-primary-project/children/folder-ops", Label: "Ops"}, {ID: "folder-qa-id", Path: "projects/project-primary-project/children/folder-qa", Label: "QA"}, } ordered := applyProjectHierarchyFolderOrdering(folders, map[string][]string{ projectFolderOrderRootKey: {"folder-qa-id", "folder-design-id"}, "folder-design-id": {"folder-assets-id", "folder-research-id"}, }) if len(ordered) != 3 { t.Fatalf("expected 3 ordered root folders, got %d", len(ordered)) } if ordered[0].ID != "folder-qa-id" || ordered[1].ID != "folder-design-id" || ordered[2].ID != "folder-ops-id" { t.Fatalf("unexpected ordered root ids: %#v", ordered) } if len(ordered[1].Children) != 2 { t.Fatalf("expected design folder children to be preserved, got %#v", ordered[1].Children) } if ordered[1].Children[0].ID != "folder-assets-id" || ordered[1].Children[1].ID != "folder-research-id" { t.Fatalf("unexpected ordered child ids: %#v", ordered[1].Children) } } func TestInsertFolderOrderReordersWithinSameParent(t *testing.T) { folderOrder := map[string][]string{ projectFolderOrderRootKey: {"folder-a", "folder-b", "folder-c"}, } insertFolderOrder(folderOrder, "", "folder-c", 0) got := folderOrder[projectFolderOrderRootKey] if len(got) != 3 || got[0] != "folder-c" || got[1] != "folder-a" || got[2] != "folder-b" { t.Fatalf("unexpected reordered root children: %#v", got) } } func asStringForTest(value any) string { text, _ := value.(string) return text } func readStructuredFileForTest[T any](t *testing.T, path string) T { t.Helper() data, err := os.ReadFile(path) if err != nil { t.Fatalf("read %s: %v", path, err) } var raw any switch strings.ToLower(filepath.Ext(path)) { case ".cbor": if err := cbor.Unmarshal(data, &raw); err != nil { t.Fatalf("unmarshal %s: %v", path, err) } case ".json": if err := json.Unmarshal(data, &raw); err != nil { t.Fatalf("unmarshal %s: %v", path, err) } case ".jsonc": ast, err := hujson.Parse(data) if err != nil { t.Fatalf("parse jsonc %s: %v", path, err) } ast.Standardize() if err := json.Unmarshal(ast.Pack(), &raw); err != nil { t.Fatalf("unmarshal standardized %s: %v", path, err) } default: t.Fatalf("unsupported structured test file %s", path) } normalizedBytes, err := json.Marshal(normalizeStructuredValue(raw)) if err != nil { t.Fatalf("normalize %s: %v", path, err) } var payload T if err := json.Unmarshal(normalizedBytes, &payload); err != nil { t.Fatalf("decode normalized %s: %v", path, err) } return payload }