133 lines
3.2 KiB
Go
133 lines
3.2 KiB
Go
|
|
//go:build e2e
|
||
|
|
|
||
|
|
package e2e
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"io"
|
||
|
|
"net/http"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
var sharedFixture Fixture
|
||
|
|
|
||
|
|
func TestMain(m *testing.M) {
|
||
|
|
if err := loadSharedFixture(); err != nil {
|
||
|
|
fmt.Fprintf(os.Stderr, "e2e bootstrap: %v\n", err)
|
||
|
|
os.Exit(1)
|
||
|
|
}
|
||
|
|
os.Exit(m.Run())
|
||
|
|
}
|
||
|
|
|
||
|
|
func loadSharedFixture() error {
|
||
|
|
path := os.Getenv("E2E_STATE_FILE")
|
||
|
|
if path == "" {
|
||
|
|
path = filepath.Join("fixtures", "state.json")
|
||
|
|
}
|
||
|
|
raw, err := os.ReadFile(path)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("read %s: %w (run make e2e-full)", path, err)
|
||
|
|
}
|
||
|
|
if err := json.Unmarshal(raw, &sharedFixture); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if sharedFixture.BaseURL == "" || sharedFixture.AccessToken == "" {
|
||
|
|
return fmt.Errorf("invalid fixture in %s", path)
|
||
|
|
}
|
||
|
|
if override := os.Getenv("E2E_BASE_URL"); override != "" {
|
||
|
|
sharedFixture.BaseURL = override
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func refreshTokenPair(baseURL, refreshToken string) (Fixture, error) {
|
||
|
|
body, _ := json.Marshal(map[string]string{"refresh_token": refreshToken})
|
||
|
|
req, err := http.NewRequest(http.MethodPost, baseURL+"/api/v1/auth/token/refresh", bytes.NewReader(body))
|
||
|
|
if err != nil {
|
||
|
|
return Fixture{}, err
|
||
|
|
}
|
||
|
|
req.Header.Set("Content-Type", "application/json")
|
||
|
|
client := &http.Client{Timeout: 15 * time.Second}
|
||
|
|
resp, err := client.Do(req)
|
||
|
|
if err != nil {
|
||
|
|
return Fixture{}, err
|
||
|
|
}
|
||
|
|
defer resp.Body.Close()
|
||
|
|
raw, err := io.ReadAll(resp.Body)
|
||
|
|
if err != nil {
|
||
|
|
return Fixture{}, err
|
||
|
|
}
|
||
|
|
var env Envelope
|
||
|
|
if err := json.Unmarshal(raw, &env); err != nil {
|
||
|
|
return Fixture{}, err
|
||
|
|
}
|
||
|
|
if resp.StatusCode != http.StatusOK || env.Code != successCode {
|
||
|
|
return Fixture{}, fmt.Errorf("refresh failed: status=%d code=%d", resp.StatusCode, env.Code)
|
||
|
|
}
|
||
|
|
var data struct {
|
||
|
|
AccessToken string `json:"access_token"`
|
||
|
|
RefreshToken string `json:"refresh_token"`
|
||
|
|
}
|
||
|
|
if err := json.Unmarshal(env.Data, &data); err != nil {
|
||
|
|
return Fixture{}, err
|
||
|
|
}
|
||
|
|
out := Fixture{AccessToken: data.AccessToken, RefreshToken: data.RefreshToken}
|
||
|
|
if out.AccessToken == "" || out.RefreshToken == "" {
|
||
|
|
return Fixture{}, fmt.Errorf("refresh returned empty tokens")
|
||
|
|
}
|
||
|
|
return out, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func loadFixture() Fixture {
|
||
|
|
return sharedFixture
|
||
|
|
}
|
||
|
|
|
||
|
|
func freshClient(t *testing.T) *Client {
|
||
|
|
t.Helper()
|
||
|
|
fx := loadFixture()
|
||
|
|
base := fx.BaseURL
|
||
|
|
if override := os.Getenv("E2E_BASE_URL"); override != "" {
|
||
|
|
base = override
|
||
|
|
}
|
||
|
|
return &Client{
|
||
|
|
BaseURL: base,
|
||
|
|
HTTP: &http.Client{Timeout: 15 * time.Second},
|
||
|
|
Fixture: fx,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func isolatedAuthClient(t *testing.T) *Client {
|
||
|
|
t.Helper()
|
||
|
|
path := os.Getenv("E2E_STATE_FILE")
|
||
|
|
if path == "" {
|
||
|
|
path = filepath.Join("fixtures", "state.json")
|
||
|
|
}
|
||
|
|
raw, err := os.ReadFile(path)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("read fixture: %v", err)
|
||
|
|
}
|
||
|
|
var fx Fixture
|
||
|
|
if err := json.Unmarshal(raw, &fx); err != nil {
|
||
|
|
t.Fatalf("parse fixture: %v", err)
|
||
|
|
}
|
||
|
|
if override := os.Getenv("E2E_BASE_URL"); override != "" {
|
||
|
|
fx.BaseURL = override
|
||
|
|
}
|
||
|
|
pair, err := refreshTokenPair(fx.BaseURL, fx.RefreshToken)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("isolated refresh: %v", err)
|
||
|
|
}
|
||
|
|
fx.AccessToken = pair.AccessToken
|
||
|
|
fx.RefreshToken = pair.RefreshToken
|
||
|
|
return &Client{
|
||
|
|
BaseURL: fx.BaseURL,
|
||
|
|
HTTP: &http.Client{Timeout: 15 * time.Second},
|
||
|
|
Fixture: fx,
|
||
|
|
}
|
||
|
|
}
|