package config import ( "os" "path/filepath" "strings" "testing" ) func TestAcquireInstancePathsSeparatesConcurrentInstances(t *testing.T) { baseDir := t.TempDir() t.Setenv("DOUYU_DATA_DIR", baseDir) t.Setenv("DOUYU_CONFIG", "") t.Setenv("DOUYU_USERS", "") t.Setenv("DOUYU_LOG_DIR", "") t.Setenv("DOUYU_SUCCESS_DIR", "") t.Setenv("devserver", "") t.Setenv("frontenddevserverurl", "") first, err := AcquireInstancePaths() if err != nil { t.Fatal(err) } defer first.Release() if first.Name() != "默认实例" || first.Paths().DataDir != baseDir { t.Fatalf("first instance = %q, %q", first.Name(), first.Paths().DataDir) } second, err := AcquireInstancePaths() if err != nil { t.Fatal(err) } defer second.Release() wantSecondDir := filepath.Join(baseDir, "instances", "instance-2") if second.Name() != "实例 2" || second.Paths().DataDir != wantSecondDir { t.Fatalf("second instance = %q, %q", second.Name(), second.Paths().DataDir) } if second.Paths().LegacyConfigFile != "" || second.Paths().LegacyAccountFile != "" { t.Fatal("附加实例不应迁移默认实例或旧工作目录数据") } first.Release() reused, err := AcquireInstancePaths() if err != nil { t.Fatal(err) } defer reused.Release() if reused.Name() != "默认实例" || reused.Paths().DataDir != baseDir { t.Fatalf("reused instance = %q, %q", reused.Name(), reused.Paths().DataDir) } } // TestAcquireInstancePathsNeverSharesDefaultDir 保证实例占位失败时也不会退回默认目录。 // 退回默认目录会让两个进程共享 accounts.txt/config.json,同秒启动还会写进同一个日志文件。 func TestAcquireInstancePathsNeverSharesDefaultDir(t *testing.T) { baseDir := t.TempDir() // 用一个普通文件占住 ,让 /instances/.locks 无法创建。 blocked := filepath.Join(baseDir, "blocked") if err := os.WriteFile(blocked, []byte("x"), 0600); err != nil { t.Fatal(err) } t.Setenv("DOUYU_DATA_DIR", blocked) lease, err := AcquireInstancePaths() if lease == nil { t.Fatal("实例占位必须始终返回可用目录") } defer lease.Release() if err == nil { t.Fatal("降级路径应当把原因返回给上层记录") } if lease.Name() != "临时实例" { t.Fatalf("降级实例名 = %q, want 临时实例", lease.Name()) } if lease.Paths().DataDir == blocked || !strings.Contains(lease.Paths().DataDir, "instance-tmp-") { t.Fatalf("降级目录必须与本进程绑定且独立: %q", lease.Paths().DataDir) } } // TestInstanceWebviewDirsAreIsolated WebView2 一个用户数据目录只能有一个浏览器进程, // 多个实例共用会让第二个实例偶发创建环境失败(必须全部关掉才能重开)。 func TestInstanceWebviewDirsAreIsolated(t *testing.T) { baseDir := t.TempDir() t.Setenv("DOUYU_DATA_DIR", baseDir) first, err := AcquireInstancePaths() if err != nil { t.Fatal(err) } defer first.Release() second, err := AcquireInstancePaths() if err != nil { t.Fatal(err) } defer second.Release() firstDir, secondDir := first.WebviewUserDataDir(), second.WebviewUserDataDir() if firstDir == "" || secondDir == "" { t.Fatalf("WebView2 目录不能为空: %q %q", firstDir, secondDir) } if firstDir == secondDir { t.Fatalf("两个实例的 WebView2 目录不能相同: %q", firstDir) } if !strings.HasSuffix(firstDir, "webview2") { t.Fatalf("WebView2 目录应在实例数据目录下: %q", firstDir) } }