Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions cli/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,41 @@ import (
func logout() *cobra.Command {
return &cobra.Command{
Use: "logout",
Short: "Remove local autheticated session",
Short: "Remove the local authenticated session",
RunE: func(cmd *cobra.Command, args []string) error {
var isLoggedOut bool

config := createConfig(cmd)
err := os.RemoveAll(string(config))

err := config.URL().Delete()
if err != nil {
// Only throw error if the URL configuration file is present,
// otherwise the user is already logged out, and we proceed
if !os.IsNotExist(err) {
return xerrors.Errorf("remove URL file: %w", err)
}
isLoggedOut = true
}

err = config.Session().Delete()
if err != nil {
return xerrors.Errorf("remove files at %s: %w", config, err)
// Only throw error if the session configuration file is present,
// otherwise the user is already logged out, and we proceed
if !os.IsNotExist(err) {
return xerrors.Errorf("remove session file: %w", err)
}
isLoggedOut = true
}

err = config.Organization().Delete()
// If the organization configuration file is absent, we still proceed
if err != nil && !os.IsNotExist(err) {
return xerrors.Errorf("remove organization file: %w", err)
}

// If the user was already logged out, we show them a message
if isLoggedOut {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), notLoggedInMessage+"\n")
}

_, _ = fmt.Fprintf(cmd.OutOrStdout(), caret+"Successfully logged out.\n")
Expand Down
110 changes: 96 additions & 14 deletions cli/logout_test.go
Original file line number Diff line number Diff line change
@@ -1,45 +1,127 @@
package cli_test

import (
"os"
"testing"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/assert"

"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/cli/config"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/pty/ptytest"
)

func TestLogout(t *testing.T) {
t.Parallel()
t.Run("Logout", func(t *testing.T) {
t.Parallel()

pty := ptytest.New(t)
config := login(t, pty)

// ensure session files exist
assert.FileExists(t, string(config.URL()))
assert.FileExists(t, string(config.Session()))

logoutChan := make(chan struct{})
logout, _ := clitest.New(t, "logout", "--global-config", string(config))
logout.SetIn(pty.Input())
logout.SetOut(pty.Output())

go func() {
defer close(logoutChan)
err := logout.Execute()
assert.NoError(t, err)
assert.NoFileExists(t, string(config.URL()))
assert.NoFileExists(t, string(config.Session()))
}()

pty.ExpectMatch("Successfully logged out")
<-logoutChan
})
t.Run("NoURLFile", func(t *testing.T) {
t.Parallel()

pty := ptytest.New(t)
config := login(t, pty)

// ensure session files exist
assert.FileExists(t, string(config.URL()))
assert.FileExists(t, string(config.Session()))

os.RemoveAll(string(config.URL()))

logoutChan := make(chan struct{})
logout, _ := clitest.New(t, "logout", "--global-config", string(config))

logout.SetIn(pty.Input())
logout.SetOut(pty.Output())

go func() {
defer close(logoutChan)
err := logout.Execute()
assert.NoError(t, err)
assert.NoFileExists(t, string(config.URL()))
assert.NoFileExists(t, string(config.Session()))
}()

pty.ExpectMatch("You are not logged in. Try logging in using 'coder login <url>'.")
pty.ExpectMatch("Successfully logged out")
<-logoutChan
})
t.Run("NoSessionFile", func(t *testing.T) {
t.Parallel()

pty := ptytest.New(t)
config := login(t, pty)

// ensure session files exist
assert.FileExists(t, string(config.URL()))
assert.FileExists(t, string(config.Session()))

os.RemoveAll(string(config.Session()))

logoutChan := make(chan struct{})
logout, _ := clitest.New(t, "logout", "--global-config", string(config))

logout.SetIn(pty.Input())
logout.SetOut(pty.Output())

go func() {
defer close(logoutChan)
err := logout.Execute()
assert.NoError(t, err)
assert.NoFileExists(t, string(config.URL()))
assert.NoFileExists(t, string(config.Session()))
}()

pty.ExpectMatch("You are not logged in. Try logging in using 'coder login <url>'.")
pty.ExpectMatch("Successfully logged out")
<-logoutChan
})
}

func login(t *testing.T, pty *ptytest.PTY) config.Root {
t.Helper()

// login
client := coderdtest.New(t, nil)
coderdtest.CreateFirstUser(t, client)

doneChan := make(chan struct{})
root, config := clitest.New(t, "login", "--force-tty", client.URL.String(), "--no-open")
pty := ptytest.New(t)
root, cfg := clitest.New(t, "login", "--force-tty", client.URL.String(), "--no-open")
root.SetIn(pty.Input())
root.SetOut(pty.Output())
go func() {
defer close(doneChan)
err := root.Execute()
require.NoError(t, err)
assert.NoError(t, err)
}()

pty.ExpectMatch("Paste your token here:")
pty.WriteLine(client.SessionToken)
pty.ExpectMatch("Welcome to Coder")
<-doneChan

// ensure session files exist
require.FileExists(t, string(config.URL()))
require.FileExists(t, string(config.Session()))

logout, _ := clitest.New(t, "logout", "--global-config", string(config))
err := logout.Execute()
require.NoError(t, err)
require.NoFileExists(t, string(config.URL()))
require.NoFileExists(t, string(config.Session()))
return cfg
}
19 changes: 10 additions & 9 deletions cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ var (
)

const (
varURL = "url"
varToken = "token"
varAgentToken = "agent-token"
varAgentURL = "agent-url"
varGlobalConfig = "global-config"
varNoOpen = "no-open"
varForceTty = "force-tty"
varURL = "url"
varToken = "token"
varAgentToken = "agent-token"
varAgentURL = "agent-url"
varGlobalConfig = "global-config"
varNoOpen = "no-open"
varForceTty = "force-tty"
notLoggedInMessage = "You are not logged in. Try logging in using 'coder login <url>'."
)

func init() {
Expand Down Expand Up @@ -117,7 +118,7 @@ func createClient(cmd *cobra.Command) (*codersdk.Client, error) {
if err != nil {
// If the configuration files are absent, the user is logged out
if os.IsNotExist(err) {
return nil, xerrors.New("You are not logged in. Try logging in using 'coder login <url>'.")
return nil, xerrors.New(notLoggedInMessage)
}
return nil, err
}
Expand All @@ -132,7 +133,7 @@ func createClient(cmd *cobra.Command) (*codersdk.Client, error) {
if err != nil {
// If the configuration files are absent, the user is logged out
if os.IsNotExist(err) {
return nil, xerrors.New("You are not logged in. Try logging in using 'coder login <url>'.")
return nil, xerrors.New(notLoggedInMessage)
}
return nil, err
}
Expand Down
1 change: 1 addition & 0 deletions cli/userlist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

func TestUserList(t *testing.T) {
t.Parallel()
t.Run("List", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
Expand Down