-
Notifications
You must be signed in to change notification settings - Fork 19
/
cli.go
148 lines (123 loc) · 3.86 KB
/
cli.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package clitest
import (
"errors"
"fmt"
"net"
"os"
"testing"
"clouditor.io/clouditor/v2/api"
"clouditor.io/clouditor/v2/cli"
"clouditor.io/clouditor/v2/internal/testdata"
"clouditor.io/clouditor/v2/internal/testutil"
"clouditor.io/clouditor/v2/server"
oauth2 "github.com/oxisto/oauth2go"
"github.com/spf13/viper"
"google.golang.org/grpc"
)
// PrepareSession prepares a session for unit tests. It creates a temporary folder to save
// the session credentials in and does a login to the specified authorization server using
// test credentials. It is the responsibility of the caller to cleanup the temporary directory.
//
// This function will use asserts and fail/panic if errors occurs.
func PrepareSession(authPort uint16, authSrv *oauth2.AuthorizationServer, grpcURL string) (dir string, err error) {
var (
token *oauth2.Token
session *cli.Session
)
// Create a temporary folder
dir, err = os.MkdirTemp(os.TempDir(), ".clouditor")
if err != nil {
return "", err
}
viper.Set("auth-server", fmt.Sprintf("http://localhost:%d", authPort))
viper.Set(cli.SessionFolderFlag, dir)
// Simulate a login by directly granting a token
token, err = authSrv.GenerateToken(testdata.MockAuthClientID, 0, 0)
if err != nil {
return "", err
}
// TODO(oxisto): This is slightly duplicated code from the Login command. Extract it into the session struct
session, err = cli.NewSession(grpcURL, &oauth2.Config{
ClientID: testdata.MockAuthClientID,
Endpoint: oauth2.Endpoint{
AuthURL: testutil.AuthURL(authPort),
TokenURL: testutil.TokenURL(authPort),
},
}, token)
if err != nil {
return "", err
}
session.SetAuthorizer(api.NewOAuthAuthorizerFromConfig(
session.Config,
token,
))
err = session.Save()
if err != nil {
return "", err
}
return dir, nil
}
// RunCLITest can be used in a TestMain function for CLI tests. It takes care of launching
// an authorization server as well as a gRPC server with the selected services supplied as options.
// It also automatically issues a login command to the auth service.
//
// Since this function is primarily used in a TestMain and no testing.T object is available at this
// point, this function WILL panic on errors.
func RunCLITest(m *testing.M, opts ...server.StartGRPCServerOption) (code int) {
ret, err := RunCLITestFunc(m.Run, opts...)
if err != nil {
panic(err)
}
return *ret
}
// RunCLITestFunc can be used to launch individual test functions with a gRPC server. It takes care of launching an
// authorization server as well as a gRPC server with the selected services supplied as options. It also automatically
// issues a login command to the auth service.
func RunCLITestFunc[T any](f func() T, opts ...server.StartGRPCServerOption) (retPtr *T, err error) {
var (
tmpDir string
auth *oauth2.AuthorizationServer
authPort uint16
grpcPort uint16
sock net.Listener
srv *grpc.Server
)
auth, authPort, err = testutil.StartAuthenticationServer()
if err != nil {
return nil, err
}
// Make sure, we are using authentication for the tests
opts = append(opts, server.WithJWKS(testutil.JWKSURL(authPort)))
sock, srv, err = server.StartGRPCServer("127.0.0.1:0", opts...)
if err != nil {
return nil, err
}
grpcPort = sock.Addr().(*net.TCPAddr).AddrPort().Port()
tmpDir, err = PrepareSession(authPort, auth, fmt.Sprintf("localhost:%d", grpcPort))
if err != nil {
return nil, err
}
ret := f()
sock.Close()
srv.Stop()
// Remove temporary session directory
os.RemoveAll(tmpDir)
return &ret, nil
}
// AutoChdir automatically guesses if we need to change the current working directory
// so that we can find the policies folder
func AutoChdir() {
var (
err error
)
// Check, if we can find the policies folder
_, err = os.Stat("policies")
if errors.Is(err, os.ErrNotExist) {
// Try again one level deeper
err = os.Chdir("..")
if err != nil {
panic(err)
}
AutoChdir()
}
}