Skip to content

Commit 0b2d46f

Browse files
Consolidate logout tests
Merge shared-host token deletion verification into one main parametrized test by addding the hostBasedKey and isSharedKey parameters to each case. This replaces the TestLogoutTokenCacheCleanup test with an assertion: host-based keys are preserved when another profile shares the same host, and deleted otherwise.
1 parent 576b031 commit 0b2d46f

File tree

2 files changed

+57
-90
lines changed

2 files changed

+57
-90
lines changed

cmd/auth/logout.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ func runLogout(ctx context.Context, args logoutArgs) error {
116116
}
117117
}
118118

119+
// First delete the profile and then perform best-effort token cache cleanup
120+
// to avoid partial cleanup in case of errors from profile deletion.
119121
err = databrickscfg.DeleteProfile(ctx, args.profileName, args.configFilePath)
120122
if err != nil {
121123
return fmt.Errorf("failed to remove profile: %w", err)

cmd/auth/logout_test.go

Lines changed: 55 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ account_id = def456
3333
experimental_is_unified_host = true
3434
`
3535

36+
var logoutTestTokensCackeConfig = map[string]*oauth2.Token{
37+
"my-workspace": {AccessToken: "shared-workspace-token"},
38+
"shared-workspace": {AccessToken: "shared-workspace-token"},
39+
"my-unique-workspace": {AccessToken: "my-unique-workspace-token"},
40+
"my-account": {AccessToken: "my-account-token"},
41+
"my-unified": {AccessToken: "my-unified-token"},
42+
"https://my-workspace.cloud.databricks.com": {AccessToken: "shared-workspace-host-token"},
43+
"https://my-unique-workspace.cloud.databricks.com": {AccessToken: "unique-workspace-host-token"},
44+
"https://accounts.cloud.databricks.com/oidc/accounts/abc123": {AccessToken: "account-host-token"},
45+
"https://unified.cloud.databricks.com/oidc/accounts/def456": {AccessToken: "unified-host-token"},
46+
}
47+
3648
func writeTempConfig(t *testing.T, content string) string {
3749
t.Helper()
3850
path := filepath.Join(t.TempDir(), ".databrickscfg")
@@ -42,30 +54,55 @@ func writeTempConfig(t *testing.T, content string) string {
4254

4355
func TestLogout(t *testing.T) {
4456
cases := []struct {
45-
name string
46-
profileName string
47-
force bool
48-
wantErr string
57+
name string
58+
profileName string
59+
hostBasedKey string
60+
isSharedKey bool
61+
force bool
62+
wantErr string
4963
}{
5064
{
51-
name: "existing profile with force",
52-
profileName: "my-workspace",
53-
force: true,
65+
name: "existing workspace profile with shared host",
66+
profileName: "my-workspace",
67+
hostBasedKey: "https://my-workspace.cloud.databricks.com",
68+
isSharedKey: true,
69+
force: true,
70+
},
71+
{
72+
name: "existing workspace profile with unique host",
73+
profileName: "my-unique-workspace",
74+
hostBasedKey: "https://my-unique-workspace.cloud.databricks.com",
75+
isSharedKey: false,
76+
force: true,
5477
},
5578
{
56-
name: "existing profile without force in non-interactive mode",
79+
name: "existing account profile",
80+
profileName: "my-account",
81+
hostBasedKey: "https://accounts.cloud.databricks.com/oidc/accounts/abc123",
82+
isSharedKey: false,
83+
force: true,
84+
},
85+
{
86+
name: "existing unified profile",
87+
profileName: "my-unified",
88+
hostBasedKey: "https://unified.cloud.databricks.com/oidc/accounts/def456",
89+
isSharedKey: false,
90+
force: true,
91+
},
92+
{
93+
name: "existing workspace profile without force in non-interactive mode",
5794
profileName: "my-workspace",
5895
force: false,
5996
wantErr: "please specify --force to skip confirmation in non-interactive mode",
6097
},
6198
{
62-
name: "non-existing profile with force",
99+
name: "non-existing workspace profile with force",
63100
profileName: "nonexistent",
64101
force: true,
65102
wantErr: `profile "nonexistent" not found`,
66103
},
67104
{
68-
name: "non-existing profile without force",
105+
name: "non-existing workspace profile without force",
69106
profileName: "nonexistent",
70107
force: false,
71108
wantErr: `profile "nonexistent" not found`,
@@ -79,10 +116,7 @@ func TestLogout(t *testing.T) {
79116
t.Setenv("DATABRICKS_CONFIG_FILE", configPath)
80117

81118
tokenCache := &inMemoryTokenCache{
82-
Tokens: map[string]*oauth2.Token{
83-
"my-workspace": {AccessToken: "token1"},
84-
"https://my-workspace.cloud.databricks.com": {AccessToken: "token1"},
85-
},
119+
Tokens: logoutTestTokensCackeConfig,
86120
}
87121

88122
err := runLogout(ctx, logoutArgs{
@@ -92,6 +126,7 @@ func TestLogout(t *testing.T) {
92126
tokenCache: tokenCache,
93127
configFilePath: configPath,
94128
})
129+
95130
if tc.wantErr != "" {
96131
assert.ErrorContains(t, err, tc.wantErr)
97132
return
@@ -101,84 +136,14 @@ func TestLogout(t *testing.T) {
101136
// Verify profile was removed from config.
102137
profiles, err := profile.DefaultProfiler.LoadProfiles(ctx, profile.WithName(tc.profileName))
103138
require.NoError(t, err)
104-
assert.Empty(t, profiles)
139+
assert.Empty(t, profiles, "expected profile %q to be removed", tc.profileName)
105140

106141
// Verify tokens were cleaned up.
107-
assert.Nil(t, tokenCache.Tokens[tc.profileName])
108-
})
109-
}
110-
}
111-
112-
func TestLogoutTokenCacheCleanup(t *testing.T) {
113-
cases := []struct {
114-
name string
115-
profileName string
116-
tokens map[string]*oauth2.Token
117-
wantRemoved []string
118-
wantPreserved []string
119-
}{
120-
{
121-
name: "workspace shared host preserves host-keyed token",
122-
profileName: "my-workspace",
123-
tokens: map[string]*oauth2.Token{
124-
"my-workspace": {AccessToken: "token1"},
125-
"shared-workspace": {AccessToken: "token2"},
126-
"https://my-workspace.cloud.databricks.com": {AccessToken: "host-token"},
127-
},
128-
wantRemoved: []string{"my-workspace"},
129-
wantPreserved: []string{"https://my-workspace.cloud.databricks.com", "shared-workspace"},
130-
},
131-
{
132-
name: "workspace unique host clears host-keyed token",
133-
profileName: "my-unique-workspace",
134-
tokens: map[string]*oauth2.Token{
135-
"my-unique-workspace": {AccessToken: "token1"},
136-
"https://my-unique-workspace.cloud.databricks.com": {AccessToken: "host-token"},
137-
},
138-
wantRemoved: []string{"my-unique-workspace", "https://my-unique-workspace.cloud.databricks.com"},
139-
},
140-
{
141-
name: "account profile clears OIDC-keyed token",
142-
profileName: "my-account",
143-
tokens: map[string]*oauth2.Token{
144-
"my-account": {AccessToken: "token1"},
145-
"https://accounts.cloud.databricks.com/oidc/accounts/abc123": {AccessToken: "account-token"},
146-
},
147-
wantRemoved: []string{"my-account", "https://accounts.cloud.databricks.com/oidc/accounts/abc123"},
148-
},
149-
{
150-
name: "unified profile clears OIDC-keyed token",
151-
profileName: "my-unified",
152-
tokens: map[string]*oauth2.Token{
153-
"my-unified": {AccessToken: "token1"},
154-
"https://unified.cloud.databricks.com/oidc/accounts/def456": {AccessToken: "unified-token"},
155-
},
156-
wantRemoved: []string{"my-unified", "https://unified.cloud.databricks.com/oidc/accounts/def456"},
157-
},
158-
}
159-
160-
for _, tc := range cases {
161-
t.Run(tc.name, func(t *testing.T) {
162-
ctx := cmdio.MockDiscard(context.Background())
163-
configPath := writeTempConfig(t, logoutTestConfig)
164-
t.Setenv("DATABRICKS_CONFIG_FILE", configPath)
165-
166-
tokenCache := &inMemoryTokenCache{Tokens: tc.tokens}
167-
168-
err := runLogout(ctx, logoutArgs{
169-
profileName: tc.profileName,
170-
force: true,
171-
profiler: profile.DefaultProfiler,
172-
tokenCache: tokenCache,
173-
configFilePath: configPath,
174-
})
175-
require.NoError(t, err)
176-
177-
for _, key := range tc.wantRemoved {
178-
assert.Nil(t, tokenCache.Tokens[key], "expected token %q to be removed", key)
179-
}
180-
for _, key := range tc.wantPreserved {
181-
assert.NotNil(t, tokenCache.Tokens[key], "expected token %q to be preserved", key)
142+
assert.Nil(t, tokenCache.Tokens[tc.profileName], "expected token %q to be removed", tc.profileName)
143+
if tc.isSharedKey {
144+
assert.NotNil(t, tokenCache.Tokens[tc.hostBasedKey], "expected token %q to be preserved", tc.hostBasedKey)
145+
} else {
146+
assert.Nil(t, tokenCache.Tokens[tc.hostBasedKey], "expected token %q to be removed", tc.hostBasedKey)
182147
}
183148
})
184149
}

0 commit comments

Comments
 (0)