|
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 { |
@@ -1792,6 +1833,74 @@ func TestNewDBsFromDirectoryConfig_UniquePaths(t *testing.T) { |
1792 | 1833 | } |
1793 | 1834 | } |
1794 | 1835 |
|
| 1836 | +// TestNewDBsFromDirectoryConfig_MetaPathPerDatabase ensures that each database |
| 1837 | +// discovered via a directory config receives a unique metadata directory when a |
| 1838 | +// base meta-path is provided. |
| 1839 | +func TestNewDBsFromDirectoryConfig_MetaPathPerDatabase(t *testing.T) { |
| 1840 | + tmpDir := t.TempDir() |
| 1841 | + |
| 1842 | + rootDB := filepath.Join(tmpDir, "primary.db") |
| 1843 | + createSQLiteDB(t, rootDB) |
| 1844 | + |
| 1845 | + nestedDir := filepath.Join(tmpDir, "team", "nested") |
| 1846 | + if err := os.MkdirAll(nestedDir, 0o755); err != nil { |
| 1847 | + t.Fatalf("failed to create nested directory: %v", err) |
| 1848 | + } |
| 1849 | + nestedDB := filepath.Join(nestedDir, "analytics.db") |
| 1850 | + createSQLiteDB(t, nestedDB) |
| 1851 | + |
| 1852 | + u, err := user.Current() |
| 1853 | + if err != nil { |
| 1854 | + t.Skipf("user.Current failed: %v", err) |
| 1855 | + } |
| 1856 | + if u.HomeDir == "" { |
| 1857 | + t.Skip("no home directory available for expansion test") |
| 1858 | + } |
| 1859 | + |
| 1860 | + metaRoot := filepath.Join("~", "meta-root") |
| 1861 | + expandedMetaRoot := filepath.Join(u.HomeDir, "meta-root") |
| 1862 | + replicaDir := filepath.Join(t.TempDir(), "replica") |
| 1863 | + config := &main.DBConfig{ |
| 1864 | + Dir: tmpDir, |
| 1865 | + Pattern: "*.db", |
| 1866 | + Recursive: true, |
| 1867 | + MetaPath: &metaRoot, |
| 1868 | + Replica: &main.ReplicaConfig{ |
| 1869 | + Type: "file", |
| 1870 | + Path: replicaDir, |
| 1871 | + }, |
| 1872 | + } |
| 1873 | + |
| 1874 | + dbs, err := main.NewDBsFromDirectoryConfig(config) |
| 1875 | + if err != nil { |
| 1876 | + t.Fatalf("NewDBsFromDirectoryConfig failed: %v", err) |
| 1877 | + } |
| 1878 | + if len(dbs) != 2 { |
| 1879 | + t.Fatalf("expected 2 databases, got %d", len(dbs)) |
| 1880 | + } |
| 1881 | + |
| 1882 | + expectedMetaPaths := map[string]string{ |
| 1883 | + rootDB: filepath.Join(expandedMetaRoot, ".primary.db"+litestream.MetaDirSuffix), |
| 1884 | + nestedDB: filepath.Join(expandedMetaRoot, "team", "nested", ".analytics.db"+litestream.MetaDirSuffix), |
| 1885 | + } |
| 1886 | + |
| 1887 | + metaSeen := make(map[string]struct{}) |
| 1888 | + for _, db := range dbs { |
| 1889 | + metaPath := db.MetaPath() |
| 1890 | + want, ok := expectedMetaPaths[db.Path()] |
| 1891 | + if !ok { |
| 1892 | + t.Fatalf("unexpected database path returned: %s", db.Path()) |
| 1893 | + } |
| 1894 | + if metaPath != want { |
| 1895 | + t.Fatalf("database %s meta path mismatch: got %s, want %s", db.Path(), metaPath, want) |
| 1896 | + } |
| 1897 | + if _, dup := metaSeen[metaPath]; dup { |
| 1898 | + t.Fatalf("duplicate meta path detected: %s", metaPath) |
| 1899 | + } |
| 1900 | + metaSeen[metaPath] = struct{}{} |
| 1901 | + } |
| 1902 | +} |
| 1903 | + |
1795 | 1904 | // TestNewDBsFromDirectoryConfig_SubdirectoryPaths verifies that the relative |
1796 | 1905 | // directory structure is preserved in replica paths when using recursive scanning. |
1797 | 1906 | func TestNewDBsFromDirectoryConfig_SubdirectoryPaths(t *testing.T) { |
|
0 commit comments