mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-12 17:59:06 +02:00
# Conflicts: # client/android/client.go # client/android/login.go # client/android/profile_prefs.go # client/internal/connect.go # client/internal/engine.go # client/mobile/profile_state.go # client/ui/i18n/locales/de/common.json # client/ui/i18n/locales/en/common.json # client/ui/i18n/locales/es/common.json # client/ui/i18n/locales/fr/common.json # client/ui/i18n/locales/hu/common.json # client/ui/i18n/locales/it/common.json # client/ui/i18n/locales/ja/common.json # client/ui/i18n/locales/pt/common.json # client/ui/i18n/locales/ru/common.json # client/ui/i18n/locales/zh-CN/common.json # client/ui/main.go
191 lines
5.4 KiB
Go
191 lines
5.4 KiB
Go
package mobile
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/netbirdio/netbird/client/internal/profilemanager"
|
|
)
|
|
|
|
func TestProfileAccountPathFor(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
configPath string
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "default profile",
|
|
configPath: "/data/netbird/files/netbird.cfg",
|
|
want: filepath.FromSlash("/data/netbird/files/netbird.account.json"),
|
|
},
|
|
{
|
|
name: "id profile",
|
|
configPath: "/data/netbird/files/profiles/4c5f5c8198c3989cffb5b5394f5a7ae0.json",
|
|
want: filepath.FromSlash("/data/netbird/files/profiles/4c5f5c8198c3989cffb5b5394f5a7ae0.account.json"),
|
|
},
|
|
{
|
|
name: "legacy name-keyed profile is handled the same way",
|
|
configPath: "/data/netbird/files/profiles/work.json",
|
|
want: filepath.FromSlash("/data/netbird/files/profiles/work.account.json"),
|
|
},
|
|
{
|
|
name: "empty path is rejected",
|
|
configPath: "",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := profileAccountPathFor(tt.configPath)
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Fatalf("expected an error, got path %q", got)
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("got %q, want %q", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestProfileAccountPathForDefaultDoesNotCollide(t *testing.T) {
|
|
root := "/data/netbird/files"
|
|
|
|
defaultAccount, err := profileAccountPathFor(filepath.Join(root, defaultConfigFilename))
|
|
if err != nil {
|
|
t.Fatalf("default profile: %v", err)
|
|
}
|
|
|
|
idAccount, err := profileAccountPathFor(filepath.Join(root, profilesSubdir, "abc123.json"))
|
|
if err != nil {
|
|
t.Fatalf("id profile: %v", err)
|
|
}
|
|
|
|
if defaultAccount == idAccount {
|
|
t.Fatalf("default and id profile share an account file: %q", defaultAccount)
|
|
}
|
|
}
|
|
|
|
// The account file must never land on the engine state file: on mobile both
|
|
// resolve under configDir, and the state manager rewrites the whole file from
|
|
// its own keys, so sharing a path would have the two overwrite each other. The
|
|
// expected names here mirror ProfileManager.GetStateFilePath.
|
|
func TestProfileAccountPathAvoidsEngineStateFile(t *testing.T) {
|
|
root := "/data/netbird/files"
|
|
|
|
cases := []struct {
|
|
configPath string
|
|
engineState string
|
|
}{
|
|
{
|
|
configPath: filepath.Join(root, defaultConfigFilename),
|
|
engineState: filepath.Join(root, "state.json"),
|
|
},
|
|
{
|
|
configPath: filepath.Join(root, profilesSubdir, "abc123.json"),
|
|
engineState: filepath.Join(root, profilesSubdir, "abc123.state.json"),
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
account, err := profileAccountPathFor(c.configPath)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", c.configPath, err)
|
|
}
|
|
if account == c.engineState {
|
|
t.Errorf("account file collides with the engine state file: %q", account)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWriteThenReadProfileEmail(t *testing.T) {
|
|
configPath := filepath.Join(t.TempDir(), "profiles", "abc123.json")
|
|
if err := ensureDirFor(t, configPath); err != nil {
|
|
t.Fatalf("prepare dir: %v", err)
|
|
}
|
|
|
|
if got := ReadProfileEmail(configPath); got != "" {
|
|
t.Errorf("expected no email before a login, got %q", got)
|
|
}
|
|
|
|
const email = "user@example.com"
|
|
if err := WriteProfileEmail(configPath, email); err != nil {
|
|
t.Fatalf("write: %v", err)
|
|
}
|
|
|
|
if got := ReadProfileEmail(configPath); got != email {
|
|
t.Errorf("got %q, want %q", got, email)
|
|
}
|
|
|
|
if err := removeProfileEmail(configPath); err != nil {
|
|
t.Fatalf("remove: %v", err)
|
|
}
|
|
if got := ReadProfileEmail(configPath); got != "" {
|
|
t.Errorf("expected no email after removal, got %q", got)
|
|
}
|
|
|
|
// Removal may run on a never-logged-in profile, so a second remove must pass.
|
|
if err := removeProfileEmail(configPath); err != nil {
|
|
t.Fatalf("second remove should be a no-op: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestWriteProfileEmailIgnoresEmpty(t *testing.T) {
|
|
configPath := filepath.Join(t.TempDir(), "profiles", "abc123.json")
|
|
if err := ensureDirFor(t, configPath); err != nil {
|
|
t.Fatalf("prepare dir: %v", err)
|
|
}
|
|
|
|
const email = "user@example.com"
|
|
if err := WriteProfileEmail(configPath, email); err != nil {
|
|
t.Fatalf("write: %v", err)
|
|
}
|
|
if err := WriteProfileEmail(configPath, ""); err != nil {
|
|
t.Fatalf("write empty: %v", err)
|
|
}
|
|
|
|
if got := ReadProfileEmail(configPath); got != email {
|
|
t.Errorf("empty write clobbered the stored email: got %q, want %q", got, email)
|
|
}
|
|
}
|
|
|
|
func ensureDirFor(t *testing.T, path string) error {
|
|
t.Helper()
|
|
return os.MkdirAll(filepath.Dir(path), 0o700)
|
|
}
|
|
|
|
func TestProfileLocationForSplitsConfigPath(t *testing.T) {
|
|
root := t.TempDir()
|
|
|
|
dir, id, err := ProfileLocationFor(filepath.Join(root, defaultConfigFilename))
|
|
if err != nil {
|
|
t.Fatalf("default profile: %v", err)
|
|
}
|
|
if dir != root || id != profilemanager.DefaultProfileName {
|
|
t.Fatalf("default profile = (%q, %q), want (%q, %q)", dir, id, root, profilemanager.DefaultProfileName)
|
|
}
|
|
|
|
named := filepath.Join(root, profilesSubdir, "aaaaaaaabbbbbbbbccccccccdddddddd.json")
|
|
dir, id, err = ProfileLocationFor(named)
|
|
if err != nil {
|
|
t.Fatalf("named profile: %v", err)
|
|
}
|
|
if dir != root || id != "aaaaaaaabbbbbbbbccccccccdddddddd" {
|
|
t.Fatalf("named profile = (%q, %q), want (%q, %q)", dir, id, root, "aaaaaaaabbbbbbbbccccccccdddddddd")
|
|
}
|
|
|
|
for _, path := range []string{"", filepath.Join(root, "stray.json"), filepath.Join(root, profilesSubdir, "not-an-id!.json")} {
|
|
if _, _, err := ProfileLocationFor(path); err == nil {
|
|
t.Fatalf("expected an error for %q", path)
|
|
}
|
|
}
|
|
}
|