Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
|
|
@ -0,0 +1,111 @@
|
|||
package management
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/auth/codex"
|
||||
"github.com/router-for-me/CLIProxyAPI/v7/internal/config"
|
||||
)
|
||||
|
||||
type fakeCodexOAuthService struct{}
|
||||
|
||||
func (f *fakeCodexOAuthService) GenerateAuthURL(state string, pkceCodes *codex.PKCECodes) (string, error) {
|
||||
return "https://auth.example.test/oauth?state=" + state, nil
|
||||
}
|
||||
|
||||
func (f *fakeCodexOAuthService) ExchangeCodeForTokens(ctx context.Context, code string, pkceCodes *codex.PKCECodes) (*codex.CodexAuthBundle, error) {
|
||||
now := time.Now()
|
||||
return &codex.CodexAuthBundle{
|
||||
TokenData: codex.CodexTokenData{
|
||||
IDToken: "invalid-test-id-token",
|
||||
AccessToken: "access-" + code,
|
||||
RefreshToken: "refresh-" + code,
|
||||
Email: "codex-" + code + "@example.test",
|
||||
Expire: now.Add(time.Hour).Format(time.RFC3339),
|
||||
},
|
||||
LastRefresh: now.Format(time.RFC3339),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *fakeCodexOAuthService) CreateTokenStorage(bundle *codex.CodexAuthBundle) *codex.CodexTokenStorage {
|
||||
return &codex.CodexTokenStorage{
|
||||
IDToken: bundle.TokenData.IDToken,
|
||||
AccessToken: bundle.TokenData.AccessToken,
|
||||
RefreshToken: bundle.TokenData.RefreshToken,
|
||||
AccountID: bundle.TokenData.AccountID,
|
||||
LastRefresh: bundle.LastRefresh,
|
||||
Email: bundle.TokenData.Email,
|
||||
Expire: bundle.TokenData.Expire,
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestCodexTokenCompletionKeepsConcurrentSessionPending(t *testing.T) {
|
||||
originalNewCodexOAuthService := newCodexOAuthService
|
||||
newCodexOAuthService = func(cfg *config.Config) codexOAuthService {
|
||||
return &fakeCodexOAuthService{}
|
||||
}
|
||||
defer func() {
|
||||
newCodexOAuthService = originalNewCodexOAuthService
|
||||
}()
|
||||
|
||||
authDir := filepath.Join(t.TempDir(), "auths")
|
||||
handler := NewHandlerWithoutConfigFilePath(&config.Config{AuthDir: authDir}, nil)
|
||||
router := gin.New()
|
||||
router.GET("/codex-auth-url", handler.RequestCodexToken)
|
||||
|
||||
firstState := requestCodexTokenState(t, router)
|
||||
secondState := requestCodexTokenState(t, router)
|
||||
defer CompleteOAuthSession(firstState)
|
||||
defer CompleteOAuthSession(secondState)
|
||||
|
||||
if _, errWrite := WriteOAuthCallbackFileForPendingSession(authDir, "codex", firstState, "first-code", ""); errWrite != nil {
|
||||
t.Fatalf("write first callback file: %v", errWrite)
|
||||
}
|
||||
|
||||
waitForOAuthSessionDone(t, firstState)
|
||||
if !IsOAuthSessionPending(secondState, "codex") {
|
||||
t.Fatalf("expected concurrent codex session %s to remain pending after %s completed", secondState, firstState)
|
||||
}
|
||||
}
|
||||
|
||||
func requestCodexTokenState(t *testing.T, router http.Handler) string {
|
||||
t.Helper()
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/codex-auth-url", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected status %d, got %d with body %s", http.StatusOK, w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var payload struct {
|
||||
State string `json:"state"`
|
||||
}
|
||||
if errDecode := json.Unmarshal(w.Body.Bytes(), &payload); errDecode != nil {
|
||||
t.Fatalf("decode codex auth URL response: %v", errDecode)
|
||||
}
|
||||
if payload.State == "" {
|
||||
t.Fatalf("expected codex auth URL response to include state")
|
||||
}
|
||||
return payload.State
|
||||
}
|
||||
|
||||
func waitForOAuthSessionDone(t *testing.T, state string) {
|
||||
t.Helper()
|
||||
|
||||
deadline := time.Now().Add(3 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
if !IsOAuthSessionPending(state, "codex") {
|
||||
return
|
||||
}
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
}
|
||||
t.Fatalf("timed out waiting for codex session %s to complete", state)
|
||||
}
|
||||
Loading…
Reference in a new issue