|
5 | 5 | "context" |
6 | 6 | "errors" |
7 | 7 | "os" |
| 8 | + "os/user" |
8 | 9 | "path/filepath" |
9 | 10 | "strings" |
10 | 11 | "testing" |
@@ -137,6 +138,46 @@ dbs: |
137 | 138 | }) |
138 | 139 | } |
139 | 140 |
|
| 141 | +func TestNewDBFromConfig_MetaPathExpansion(t *testing.T) { |
| 142 | + u, err := user.Current() |
| 143 | + if err != nil { |
| 144 | + t.Skipf("user.Current failed: %v", err) |
| 145 | + } |
| 146 | + if u.HomeDir == "" { |
| 147 | + t.Skip("no home directory available for expansion test") |
| 148 | + } |
| 149 | + |
| 150 | + tmpDir := t.TempDir() |
| 151 | + dbPath := filepath.Join(tmpDir, "db.sqlite") |
| 152 | + replicaPath := filepath.Join(tmpDir, "replica") |
| 153 | + if err := os.MkdirAll(replicaPath, 0o755); err != nil { |
| 154 | + t.Fatalf("failed to create replica directory: %v", err) |
| 155 | + } |
| 156 | + |
| 157 | + metaPath := filepath.Join("~", "litestream-meta") |
| 158 | + config := &main.DBConfig{ |
| 159 | + Path: dbPath, |
| 160 | + MetaPath: &metaPath, |
| 161 | + Replica: &main.ReplicaConfig{ |
| 162 | + Type: "file", |
| 163 | + Path: replicaPath, |
| 164 | + }, |
| 165 | + } |
| 166 | + |
| 167 | + db, err := main.NewDBFromConfig(config) |
| 168 | + if err != nil { |
| 169 | + t.Fatalf("NewDBFromConfig failed: %v", err) |
| 170 | + } |
| 171 | + |
| 172 | + expectedMetaPath := filepath.Join(u.HomeDir, "litestream-meta") |
| 173 | + if got := db.MetaPath(); got != expectedMetaPath { |
| 174 | + t.Fatalf("MetaPath not expanded: got %s, want %s", got, expectedMetaPath) |
| 175 | + } |
| 176 | + if config.MetaPath == nil || *config.MetaPath != expectedMetaPath { |
| 177 | + t.Fatalf("config MetaPath not updated: got %v, want %s", config.MetaPath, expectedMetaPath) |
| 178 | + } |
| 179 | +} |
| 180 | + |
140 | 181 | func TestNewFileReplicaFromConfig(t *testing.T) { |
141 | 182 | r, err := main.NewReplicaFromConfig(&main.ReplicaConfig{Path: "/foo"}, nil) |
142 | 183 | if err != nil { |
@@ -1614,6 +1655,74 @@ func TestNewDBsFromDirectoryConfig_UniquePaths(t *testing.T) { |
1614 | 1655 | } |
1615 | 1656 | } |
1616 | 1657 |
|
| 1658 | +// TestNewDBsFromDirectoryConfig_MetaPathPerDatabase ensures that each database |
| 1659 | +// discovered via a directory config receives a unique metadata directory when a |
| 1660 | +// base meta-path is provided. |
| 1661 | +func TestNewDBsFromDirectoryConfig_MetaPathPerDatabase(t *testing.T) { |
| 1662 | + tmpDir := t.TempDir() |
| 1663 | + |
| 1664 | + rootDB := filepath.Join(tmpDir, "primary.db") |
| 1665 | + createSQLiteDB(t, rootDB) |
| 1666 | + |
| 1667 | + nestedDir := filepath.Join(tmpDir, "team", "nested") |
| 1668 | + if err := os.MkdirAll(nestedDir, 0o755); err != nil { |
| 1669 | + t.Fatalf("failed to create nested directory: %v", err) |
| 1670 | + } |
| 1671 | + nestedDB := filepath.Join(nestedDir, "analytics.db") |
| 1672 | + createSQLiteDB(t, nestedDB) |
| 1673 | + |
| 1674 | + u, err := user.Current() |
| 1675 | + if err != nil { |
| 1676 | + t.Skipf("user.Current failed: %v", err) |
| 1677 | + } |
| 1678 | + if u.HomeDir == "" { |
| 1679 | + t.Skip("no home directory available for expansion test") |
| 1680 | + } |
| 1681 | + |
| 1682 | + metaRoot := filepath.Join("~", "meta-root") |
| 1683 | + expandedMetaRoot := filepath.Join(u.HomeDir, "meta-root") |
| 1684 | + replicaDir := filepath.Join(t.TempDir(), "replica") |
| 1685 | + config := &main.DBConfig{ |
| 1686 | + Dir: tmpDir, |
| 1687 | + Pattern: "*.db", |
| 1688 | + Recursive: true, |
| 1689 | + MetaPath: &metaRoot, |
| 1690 | + Replica: &main.ReplicaConfig{ |
| 1691 | + Type: "file", |
| 1692 | + Path: replicaDir, |
| 1693 | + }, |
| 1694 | + } |
| 1695 | + |
| 1696 | + dbs, err := main.NewDBsFromDirectoryConfig(config) |
| 1697 | + if err != nil { |
| 1698 | + t.Fatalf("NewDBsFromDirectoryConfig failed: %v", err) |
| 1699 | + } |
| 1700 | + if len(dbs) != 2 { |
| 1701 | + t.Fatalf("expected 2 databases, got %d", len(dbs)) |
| 1702 | + } |
| 1703 | + |
| 1704 | + expectedMetaPaths := map[string]string{ |
| 1705 | + rootDB: filepath.Join(expandedMetaRoot, ".primary.db"+litestream.MetaDirSuffix), |
| 1706 | + nestedDB: filepath.Join(expandedMetaRoot, "team", "nested", ".analytics.db"+litestream.MetaDirSuffix), |
| 1707 | + } |
| 1708 | + |
| 1709 | + metaSeen := make(map[string]struct{}) |
| 1710 | + for _, db := range dbs { |
| 1711 | + metaPath := db.MetaPath() |
| 1712 | + want, ok := expectedMetaPaths[db.Path()] |
| 1713 | + if !ok { |
| 1714 | + t.Fatalf("unexpected database path returned: %s", db.Path()) |
| 1715 | + } |
| 1716 | + if metaPath != want { |
| 1717 | + t.Fatalf("database %s meta path mismatch: got %s, want %s", db.Path(), metaPath, want) |
| 1718 | + } |
| 1719 | + if _, dup := metaSeen[metaPath]; dup { |
| 1720 | + t.Fatalf("duplicate meta path detected: %s", metaPath) |
| 1721 | + } |
| 1722 | + metaSeen[metaPath] = struct{}{} |
| 1723 | + } |
| 1724 | +} |
| 1725 | + |
1617 | 1726 | // TestNewDBsFromDirectoryConfig_SubdirectoryPaths verifies that the relative |
1618 | 1727 | // directory structure is preserved in replica paths when using recursive scanning. |
1619 | 1728 | func TestNewDBsFromDirectoryConfig_SubdirectoryPaths(t *testing.T) { |
|
0 commit comments