Skip to content

Commit b1d2682

Browse files
Add missing endpoints in general-request-handling (#706)
1 parent 7cb09b2 commit b1d2682

File tree

6 files changed

+141
-29
lines changed

6 files changed

+141
-29
lines changed

v2/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Add missing endpoints from cluster to v2
88
- Add missing endpoints from security to v2
99
- Add missing endpoints from authentication to v2
10+
- Add missing endpoints from general-request-handling to v2
1011

1112
## [2.1.5](https://github.com/arangodb/go-driver/tree/v2.1.5) (2025-08-31)
1213
- Add tasks endpoints to v2

v2/arangodb/client_admin_impl.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,19 @@ func (c *clientAdmin) GetSystemTime(ctx context.Context, dbName string) (float64
199199

200200
// GetServerStatus returns status information about the server
201201
func (c *clientAdmin) GetServerStatus(ctx context.Context, dbName string) (ServerStatusResponse, error) {
202-
url := connection.NewUrl("_db", url.PathEscape(dbName), "_admin", "status")
202+
var endPoint string
203+
if dbName == "" {
204+
endPoint = connection.NewUrl("_admin", "status")
205+
} else {
206+
endPoint = connection.NewUrl("_db", url.PathEscape(dbName), "_admin", "status")
207+
}
203208

204209
var response struct {
205210
shared.ResponseStruct `json:",inline"`
206211
ServerStatusResponse `json:",inline"`
207212
}
208213

209-
resp, err := connection.CallGet(ctx, c.client.connection, url, &response)
214+
resp, err := connection.CallGet(ctx, c.client.connection, endPoint, &response)
210215
if err != nil {
211216
return ServerStatusResponse{}, errors.WithStack(err)
212217
}

v2/arangodb/client_server_info.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ type ClientServerInfo interface {
4040
// ServerID Gets the ID of this server in the cluster.
4141
// An error is returned when calling this to a server that is not part of a cluster.
4242
ServerID(ctx context.Context) (string, error)
43+
44+
// HandleAdminVersion retrieves the ArangoDB server version information
45+
// This endpoint is an alias for `GET /_api/version`.
46+
HandleAdminVersion(ctx context.Context, opts *GetVersionOptions) (VersionInfo, error)
4347
}
4448

4549
// VersionInfo describes the version of a database server.

v2/arangodb/client_server_info_impl.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,32 @@ func (o *GetVersionOptions) modifyRequest(r connection.Request) error {
206206
}
207207
return nil
208208
}
209+
210+
// HandleAdminVersion retrieves the ArangoDB server version information
211+
// This endpoint is an alias for `GET /_api/version`.
212+
func (c clientServerInfo) HandleAdminVersion(ctx context.Context, opts *GetVersionOptions) (VersionInfo, error) {
213+
url := connection.NewUrl("_admin", "version")
214+
215+
var response struct {
216+
shared.ResponseStruct `json:",inline"`
217+
VersionInfo
218+
}
219+
220+
// Always provide a non-nil modifier
221+
modifier := func(r connection.Request) error { return nil }
222+
if opts != nil {
223+
modifier = opts.modifyRequest
224+
}
225+
226+
resp, err := connection.CallGet(ctx, c.client.connection, url, &response, modifier)
227+
if err != nil {
228+
return VersionInfo{}, errors.WithStack(err)
229+
}
230+
231+
switch code := resp.Code(); code {
232+
case http.StatusOK:
233+
return response.VersionInfo, nil
234+
default:
235+
return VersionInfo{}, response.AsArangoErrorWithCode(code)
236+
}
237+
}

v2/tests/admin_test.go

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,26 @@ func Test_GetSystemTime(t *testing.T) {
112112

113113
func Test_GetServerStatus(t *testing.T) {
114114
Wrap(t, func(t *testing.T, client arangodb.Client) {
115-
withContextT(t, time.Minute, func(ctx context.Context, t testing.TB) {
116-
db, err := client.GetDatabase(context.Background(), "_system", nil)
117-
require.NoError(t, err)
118-
require.NotEmpty(t, db)
115+
withContextT(t, time.Minute, func(ctx context.Context, tb testing.TB) {
116+
t.Run("WithoutDBName", func(t *testing.T) {
117+
resp, err := client.GetServerStatus(context.Background(), "")
118+
require.NoError(t, err)
119+
require.NotEmpty(t, resp)
120+
})
121+
t.Run("WithDBName", func(t *testing.T) {
122+
db, err := client.GetDatabase(context.Background(), "_system", nil)
123+
require.NoError(t, err)
124+
require.NotEmpty(t, db)
119125

120-
resp, err := client.GetServerStatus(context.Background(), db.Name())
121-
require.NoError(t, err)
122-
require.NotEmpty(t, resp)
126+
resp, err := client.GetServerStatus(context.Background(), db.Name())
127+
require.NoError(t, err)
128+
require.NotEmpty(t, resp)
129+
})
130+
t.Run("InvalidDBName", func(t *testing.T) {
131+
_, err := client.GetServerStatus(context.Background(), "invalid/db/name")
132+
t.Logf("error :%v\n", err)
133+
require.Error(t, err)
134+
})
123135
})
124136
})
125137
}
@@ -555,3 +567,26 @@ func validateJWTSecretsResponse(t testing.TB, resp arangodb.JWTSecretsResult, op
555567

556568
t.Logf("%s JWT secrets validation completed successfully with %d total secrets", operation, len(resp.Passive)+1)
557569
}
570+
func Test_HandleAdminVersion(t *testing.T) {
571+
Wrap(t, func(t *testing.T, client arangodb.Client) {
572+
withContextT(t, time.Minute, func(ctx context.Context, tb testing.TB) {
573+
t.Run("With Options", func(t *testing.T) {
574+
resp, err := client.HandleAdminVersion(context.Background(), &arangodb.GetVersionOptions{
575+
Details: utils.NewType(true),
576+
})
577+
require.NoError(t, err)
578+
require.NotEmpty(t, resp.Version)
579+
require.NotEmpty(t, resp.Server)
580+
require.NotEmpty(t, resp.License)
581+
require.NotEmpty(t, resp.Details)
582+
})
583+
t.Run("Without options", func(t *testing.T) {
584+
resp, err := client.HandleAdminVersion(context.Background(), nil)
585+
require.NoError(t, err)
586+
require.NotEmpty(t, resp.Version)
587+
require.NotEmpty(t, resp.Server)
588+
require.NotEmpty(t, resp.License)
589+
})
590+
})
591+
})
592+
}

v2/tests/client_access_tokens_test.go

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ import (
2424
"context"
2525
"errors"
2626
"fmt"
27-
"math/rand"
2827
"testing"
2928
"time"
3029

3130
"github.com/arangodb/go-driver/v2/arangodb"
3231
"github.com/arangodb/go-driver/v2/arangodb/shared"
3332
"github.com/arangodb/go-driver/v2/utils"
33+
"github.com/google/uuid"
3434
"github.com/stretchr/testify/require"
3535
)
3636

@@ -44,23 +44,41 @@ func Test_AccessTokens(t *testing.T) {
4444
user := "root"
4545

4646
t.Run("Create Access Token With All valid data", func(t *testing.T) {
47-
tokenName := fmt.Sprintf("Token-%d-%d", time.Now().UnixNano(), rand.Int())
48-
t.Logf("Create Access Token With All valid data - Creating token with name: %s\n", tokenName)
49-
req := arangodb.AccessTokenRequest{
50-
Name: utils.NewType(tokenName),
51-
ValidUntil: utils.NewType(expiresAt),
52-
}
5347
var err error
54-
resp, err := client.CreateAccessToken(ctx, &user, req)
48+
maxRetries := 3
49+
50+
for i := 0; i < maxRetries; i++ {
51+
tokenName := fmt.Sprintf("Token-%s", uuid.New().String())
52+
cleanupToken(ctx, t, client, user, tokenName)
53+
54+
req := arangodb.AccessTokenRequest{
55+
Name: utils.NewType(tokenName),
56+
ValidUntil: utils.NewType(expiresAt),
57+
}
58+
59+
resp, err := client.CreateAccessToken(ctx, &user, req)
60+
if err == nil {
61+
tokenResp = &resp
62+
require.NotNil(t, tokenResp)
63+
require.NotNil(t, tokenResp.Id)
64+
require.NotNil(t, tokenResp.Token)
65+
require.NotNil(t, tokenResp.Fingerprint)
66+
require.Equal(t, tokenName, *tokenResp.Name)
67+
require.Equal(t, true, *tokenResp.Active)
68+
require.Equal(t, expiresAt, *tokenResp.ValidUntil)
69+
break // success
70+
}
71+
72+
// if conflict, retry; else fail immediately
73+
var arangoErr shared.ArangoError
74+
if errors.As(err, &arangoErr) && arangoErr.Code == 409 {
75+
t.Logf("Conflict detected, retrying token creation... attempt %d\n", i+1)
76+
continue
77+
} else {
78+
break
79+
}
80+
}
5581
require.NoError(t, err)
56-
require.NotNil(t, resp)
57-
tokenResp = &resp
58-
require.NotNil(t, tokenResp.Id)
59-
require.NotNil(t, tokenResp.Token)
60-
require.NotNil(t, tokenResp.Fingerprint)
61-
require.Equal(t, tokenName, *tokenResp.Name)
62-
require.Equal(t, true, *tokenResp.Active)
63-
require.Equal(t, expiresAt, *tokenResp.ValidUntil)
6482
})
6583

6684
t.Run("Get All Access Tokens", func(t *testing.T) {
@@ -86,7 +104,7 @@ func Test_AccessTokens(t *testing.T) {
86104
})
87105

88106
t.Run("Client try to create duplicate access token name", func(t *testing.T) {
89-
if tokenResp.Name == nil {
107+
if tokenResp == nil || tokenResp.Name == nil {
90108
t.Skip("Skipping delete test because token creation failed")
91109
}
92110
t.Logf("Client try to create duplicate access token name - token name: %s\n", *tokenResp.Name)
@@ -106,7 +124,7 @@ func Test_AccessTokens(t *testing.T) {
106124
})
107125

108126
t.Run("Delete Access Token", func(t *testing.T) {
109-
if tokenResp.Id == nil {
127+
if tokenResp == nil || tokenResp.Id == nil {
110128
t.Skip("Skipping delete test because token creation failed")
111129
}
112130
err := client.DeleteAccessToken(ctx, &user, tokenResp.Id)
@@ -118,7 +136,7 @@ func Test_AccessTokens(t *testing.T) {
118136

119137
t.Run("Create Access Token With invalid user", func(t *testing.T) {
120138
invalidUser := "roothyd"
121-
tokenName := fmt.Sprintf("Token-%d-%d", time.Now().UnixNano(), rand.Int())
139+
tokenName := fmt.Sprintf("Token-%s", uuid.New().String())
122140
t.Logf("Create Access Token With invalid user - Creating token with name: %s\n", tokenName)
123141
req := arangodb.AccessTokenRequest{
124142
Name: utils.NewType(tokenName),
@@ -137,7 +155,7 @@ func Test_AccessTokens(t *testing.T) {
137155
})
138156

139157
t.Run("Create Access Token With missing user", func(t *testing.T) {
140-
tokenName := fmt.Sprintf("Token-%d-%d", time.Now().UnixNano(), rand.Int())
158+
tokenName := fmt.Sprintf("Token-%s", uuid.New().String())
141159
t.Logf("Create Access Token With missing user - Creating token with name: %s\n", tokenName)
142160
localExpiresAt := time.Now().Add(5 * time.Minute).Unix()
143161
req := arangodb.AccessTokenRequest{
@@ -174,3 +192,23 @@ func Test_AccessTokens(t *testing.T) {
174192
})
175193
})
176194
}
195+
196+
// Cleanup tokens with the same name
197+
func cleanupToken(ctx context.Context, t *testing.T, client arangodb.Client, user string, tokenName string) {
198+
tokens, err := client.GetAllAccessToken(ctx, &user)
199+
if err != nil {
200+
t.Logf("Failed to list tokens for cleanup: %v", err)
201+
return
202+
}
203+
204+
for _, token := range tokens.Tokens {
205+
if token.Name != nil && *token.Name == tokenName {
206+
if token.Id != nil {
207+
err := client.DeleteAccessToken(ctx, &user, token.Id)
208+
if err != nil {
209+
t.Logf("Failed to delete token %s: %v", *token.Name, err)
210+
}
211+
}
212+
}
213+
}
214+
}

0 commit comments

Comments
 (0)