Skip to content

Commit 21ef046

Browse files
committed
Clean up cache on logout and add test
1 parent 1fc88a7 commit 21ef046

8 files changed

Lines changed: 82 additions & 18 deletions

File tree

cmd/logout.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ func newLogoutCmd(cfg *env.Env, tel *telemetry.Client, logger log.Logger) *cobra
4343
if err != nil {
4444
return fmt.Errorf("failed to initialize token storage: %w", err)
4545
}
46-
a := auth.New(sink, platformClient, tokenStorage, cfg.AuthToken, "", false)
46+
licenseFilePath, _ := config.LicenseFilePath()
47+
a := auth.New(sink, platformClient, tokenStorage, cfg.AuthToken, "", false, licenseFilePath)
4748
if err := a.Logout(); err != nil {
4849
if errors.Is(err, auth.ErrNotLoggedIn) {
4950
return nil

internal/auth/auth.go

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"os"
78

89
"github.com/localstack/lstk/internal/api"
910
"github.com/localstack/lstk/internal/output"
@@ -12,20 +13,22 @@ import (
1213
var ErrNotLoggedIn = errors.New("not logged in")
1314

1415
type Auth struct {
15-
tokenStorage AuthTokenStorage
16-
login LoginProvider
17-
sink output.Sink
18-
authToken string
19-
allowLogin bool
16+
tokenStorage AuthTokenStorage
17+
login LoginProvider
18+
sink output.Sink
19+
authToken string
20+
allowLogin bool
21+
licenseFilePath string
2022
}
2123

22-
func New(sink output.Sink, platform api.PlatformAPI, storage AuthTokenStorage, authToken, webAppURL string, allowLogin bool) *Auth {
24+
func New(sink output.Sink, platform api.PlatformAPI, storage AuthTokenStorage, authToken, webAppURL string, allowLogin bool, licenseFilePath string) *Auth {
2325
return &Auth{
24-
tokenStorage: storage,
25-
login: newLoginProvider(sink, platform, webAppURL),
26-
sink: sink,
27-
authToken: authToken,
28-
allowLogin: allowLogin,
26+
tokenStorage: storage,
27+
login: newLoginProvider(sink, platform, webAppURL),
28+
sink: sink,
29+
authToken: authToken,
30+
allowLogin: allowLogin,
31+
licenseFilePath: licenseFilePath,
2932
}
3033
}
3134

@@ -83,6 +86,10 @@ func (a *Auth) Logout() error {
8386
return fmt.Errorf("failed to delete auth token: %w", err)
8487
}
8588

89+
if a.licenseFilePath != "" {
90+
_ = os.Remove(a.licenseFilePath)
91+
}
92+
8693
output.EmitSpinnerStop(a.sink)
8794
output.EmitSuccess(a.sink, "Logged out successfully")
8895
return nil

internal/container/start.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func Start(ctx context.Context, rt runtime.Runtime, sink output.Sink, opts Start
8181
if err != nil {
8282
return fmt.Errorf("failed to initialize token storage: %w", err)
8383
}
84-
a := auth.New(sink, opts.PlatformClient, tokenStorage, opts.AuthToken, opts.WebAppURL, interactive)
84+
a := auth.New(sink, opts.PlatformClient, tokenStorage, opts.AuthToken, opts.WebAppURL, interactive, "")
8585

8686
token, err := a.GetToken(ctx)
8787
if err != nil {

internal/ui/run_login.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func RunLogin(parentCtx context.Context, version string, platformClient api.Plat
2727
p.Send(runErrMsg{err: err})
2828
return
2929
}
30-
a := auth.New(output.NewTUISink(programSender{p: p}), platformClient, tokenStorage, authToken, webAppURL, true)
30+
a := auth.New(output.NewTUISink(programSender{p: p}), platformClient, tokenStorage, authToken, webAppURL, true, "")
3131

3232
_, err = a.GetToken(ctx)
3333
runErrCh <- err

internal/ui/run_login_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func TestLoginFlow_DeviceFlowSuccess(t *testing.T) {
9898

9999
errCh := make(chan error, 1)
100100
go func() {
101-
a := auth.New(output.NewTUISink(sender), platformClient, mockStorage, "", mockServer.URL, true)
101+
a := auth.New(output.NewTUISink(sender), platformClient, mockStorage, "", mockServer.URL, true, "")
102102
_, err := a.GetToken(ctx)
103103
errCh <- err
104104
if err != nil && !errors.Is(err, context.Canceled) {
@@ -146,7 +146,7 @@ func TestLoginFlow_DeviceFlowFailure_NotConfirmed(t *testing.T) {
146146

147147
errCh := make(chan error, 1)
148148
go func() {
149-
a := auth.New(output.NewTUISink(sender), platformClient, mockStorage, "", mockServer.URL, true)
149+
a := auth.New(output.NewTUISink(sender), platformClient, mockStorage, "", mockServer.URL, true, "")
150150
_, err := a.GetToken(ctx)
151151
errCh <- err
152152
if err != nil && !errors.Is(err, context.Canceled) {
@@ -195,7 +195,7 @@ func TestLoginFlow_DeviceFlowCancelWithCtrlC(t *testing.T) {
195195

196196
errCh := make(chan error, 1)
197197
go func() {
198-
a := auth.New(output.NewTUISink(sender), platformClient, mockStorage, "", mockServer.URL, true)
198+
a := auth.New(output.NewTUISink(sender), platformClient, mockStorage, "", mockServer.URL, true, "")
199199
_, err := a.GetToken(ctx)
200200
errCh <- err
201201
if err != nil && !errors.Is(err, context.Canceled) {

internal/ui/run_logout.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ func RunLogout(parentCtx context.Context, rt runtime.Runtime, platformClient api
3333
}
3434

3535
sink := output.NewTUISink(programSender{p: p})
36-
a := auth.New(sink, platformClient, tokenStorage, authToken, "", false)
36+
licenseFilePath, _ := config.LicenseFilePath()
37+
a := auth.New(sink, platformClient, tokenStorage, authToken, "", false, licenseFilePath)
3738
err = a.Logout()
3839
if err == nil && rt != nil {
3940
if running, runningErr := container.AnyRunning(ctx, rt, containers); runningErr == nil && running {

test/integration/license_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"fmt"
77
"net/http"
88
"net/http/httptest"
9+
"os"
10+
"path/filepath"
911
"testing"
1012

1113
"github.com/docker/docker/api/types/container"
@@ -93,8 +95,50 @@ func TestLicenseValidationFailure(t *testing.T) {
9395
assert.Error(t, err, "container should not exist after license failure")
9496
}
9597

98+
func licenseFilePath(t *testing.T) string {
99+
t.Helper()
100+
cacheDir, err := os.UserCacheDir()
101+
require.NoError(t, err)
102+
return filepath.Join(cacheDir, "lstk", "license.json")
103+
}
104+
96105
func cleanupLicense() {
97106
ctx := context.Background()
98107
_ = dockerClient.ContainerStop(ctx, containerName, container.StopOptions{})
99108
_ = dockerClient.ContainerRemove(ctx, containerName, container.RemoveOptions{Force: true})
109+
if cacheDir, err := os.UserCacheDir(); err == nil {
110+
_ = os.Remove(filepath.Join(cacheDir, "lstk", "license.json"))
111+
}
112+
}
113+
114+
func TestLicenseCacheAndMount(t *testing.T) {
115+
requireDocker(t)
116+
env.Require(t, env.AuthToken)
117+
118+
cleanupLicense()
119+
t.Cleanup(cleanupLicense)
120+
121+
licenseBody := `{"license":"test-license-data"}`
122+
mockServer := createMockLicenseServerWithBody(licenseBody)
123+
defer mockServer.Close()
124+
125+
ctx := testContext(t)
126+
_, stderr, err := runLstk(t, ctx, "", env.With(env.APIEndpoint, mockServer.URL), "start")
127+
require.NoError(t, err, "lstk start failed: %s", stderr)
128+
129+
data, err := os.ReadFile(licenseFilePath(t))
130+
require.NoError(t, err, "license cache file should exist after successful start")
131+
assert.Equal(t, licenseBody, string(data))
132+
133+
inspect, err := dockerClient.ContainerInspect(ctx, containerName)
134+
require.NoError(t, err, "failed to inspect container")
135+
136+
var mounted bool
137+
for _, m := range inspect.Mounts {
138+
if m.Destination == "/etc/localstack/conf.d/license.json" {
139+
mounted = true
140+
break
141+
}
142+
}
143+
assert.True(t, mounted, "license file should be mounted into container at /etc/localstack/conf.d/license.json")
100144
}

test/integration/main_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,14 @@ func createMockLicenseServer(success bool) *httptest.Server {
289289
w.WriteHeader(http.StatusNotFound)
290290
}))
291291
}
292+
293+
func createMockLicenseServerWithBody(body string) *httptest.Server {
294+
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
295+
if r.Method == "POST" && r.URL.Path == "/v1/license/request" {
296+
w.WriteHeader(http.StatusOK)
297+
_, _ = w.Write([]byte(body))
298+
return
299+
}
300+
w.WriteHeader(http.StatusNotFound)
301+
}))
302+
}

0 commit comments

Comments
 (0)