tests: add functionnal tests (e2e if you will)
This commit is contained in:
parent
f3cc8bdb10
commit
9174e537b6
4 changed files with 414 additions and 1 deletions
|
|
@ -52,5 +52,37 @@ jobs:
|
|||
go-version: '1.21'
|
||||
cache: true
|
||||
|
||||
- name: Run tests
|
||||
- name: Run unit tests
|
||||
run: go test -v -race ./...
|
||||
|
||||
functional:
|
||||
runs-on: codeberg-small
|
||||
if: github.ref == 'refs/heads/main' || github.event_name == 'pull_request'
|
||||
needs: [build, test]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: https://github.com/actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: https://github.com/actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
cache: true
|
||||
|
||||
- name: Build production binary
|
||||
run: |
|
||||
make build
|
||||
echo "Binary built at: $(pwd)/bin/fgj"
|
||||
|
||||
- name: Run functional tests
|
||||
if: vars.CODEBERG_TEST_OWNER != ''
|
||||
run: go test -v -race -tags=functional ./tests/functional/...
|
||||
env:
|
||||
CODEBERG_TEST_TOKEN: ${{ secrets.CODEBERG_TEST_TOKEN }}
|
||||
CODEBERG_TEST_OWNER: ${{ vars.CODEBERG_TEST_OWNER }}
|
||||
CODEBERG_TEST_REPO: ${{ vars.CODEBERG_TEST_REPO }}
|
||||
CODEBERG_TEST_HOSTNAME: ${{ vars.CODEBERG_TEST_HOSTNAME || 'codeberg.org' }}
|
||||
|
||||
- name: Skip functional tests
|
||||
if: vars.CODEBERG_TEST_OWNER == ''
|
||||
run: echo "Skipping functional tests - CODEBERG_TEST_OWNER not configured. See SETUP_FUNCTIONAL_TESTS.md for setup instructions."
|
||||
|
|
|
|||
38
tests/functional/README.md
Normal file
38
tests/functional/README.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Functional Tests
|
||||
|
||||
End-to-end tests that make real API calls to a Codeberg instance.
|
||||
|
||||
## Running Tests
|
||||
|
||||
These tests require special setup and credentials. See [SETUP_FUNCTIONAL_TESTS.md](../../SETUP_FUNCTIONAL_TESTS.md) for complete instructions.
|
||||
|
||||
### Quick Start
|
||||
|
||||
```bash
|
||||
export CODEBERG_TEST_TOKEN="your_token"
|
||||
export CODEBERG_TEST_OWNER="test-account-username"
|
||||
export CODEBERG_TEST_REPO="test-repo-name"
|
||||
|
||||
go test -v -race -tags=functional ./...
|
||||
```
|
||||
|
||||
### What They Test
|
||||
|
||||
- ✅ API authentication and connectivity
|
||||
- ✅ Repository listing and details
|
||||
- ✅ Issue creation, listing, retrieval
|
||||
- ✅ Issue comments
|
||||
- ✅ API error handling
|
||||
- ✅ Repository secrets and actions (if available)
|
||||
|
||||
### CI Integration
|
||||
|
||||
These tests run automatically in CI when configured:
|
||||
- Only on `main` branch and pull requests
|
||||
- Requires `CODEBERG_TEST_TOKEN` secret and configuration variables
|
||||
- Uses a dedicated test account (not your personal account)
|
||||
|
||||
### Files
|
||||
|
||||
- `functional_test.go` - Test suite with all test cases
|
||||
- `fixtures.go` - Helper functions and test environment setup
|
||||
135
tests/functional/fixtures.go
Normal file
135
tests/functional/fixtures.go
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
// +build functional
|
||||
|
||||
package functional
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
// TestEnv holds the functional test environment
|
||||
type TestEnv struct {
|
||||
Token string
|
||||
Hostname string
|
||||
Owner string
|
||||
RepoName string
|
||||
Client *gitea.Client
|
||||
T *testing.T
|
||||
}
|
||||
|
||||
// NewTestEnv creates a new functional test environment from environment variables
|
||||
func NewTestEnv(t *testing.T) *TestEnv {
|
||||
token := os.Getenv("CODEBERG_TEST_TOKEN")
|
||||
if token == "" {
|
||||
t.Skip("CODEBERG_TEST_TOKEN not set, skipping functional tests")
|
||||
}
|
||||
|
||||
hostname := os.Getenv("CODEBERG_TEST_HOSTNAME")
|
||||
if hostname == "" {
|
||||
hostname = "codeberg.org"
|
||||
}
|
||||
|
||||
owner := os.Getenv("CODEBERG_TEST_OWNER")
|
||||
if owner == "" {
|
||||
t.Fatal("CODEBERG_TEST_OWNER environment variable not set")
|
||||
}
|
||||
|
||||
repoName := os.Getenv("CODEBERG_TEST_REPO")
|
||||
if repoName == "" {
|
||||
t.Fatal("CODEBERG_TEST_REPO environment variable not set")
|
||||
}
|
||||
|
||||
// Create Gitea client
|
||||
client, err := gitea.NewClient(
|
||||
fmt.Sprintf("https://%s", hostname),
|
||||
gitea.SetToken(token),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create Gitea client: %v", err)
|
||||
}
|
||||
|
||||
env := &TestEnv{
|
||||
Token: token,
|
||||
Hostname: hostname,
|
||||
Owner: owner,
|
||||
RepoName: repoName,
|
||||
Client: client,
|
||||
T: t,
|
||||
}
|
||||
|
||||
// Verify authentication by getting user info
|
||||
user, _, err := client.GetMyUserInfo()
|
||||
if err != nil {
|
||||
t.Fatalf("authentication failed: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("Authenticated as user: %s on %s", user.UserName, hostname)
|
||||
return env
|
||||
}
|
||||
|
||||
// CreateTestIssue creates a test issue and returns its number
|
||||
func (env *TestEnv) CreateTestIssue(title, body string) int64 {
|
||||
opts := gitea.CreateIssueOption{
|
||||
Title: title,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
issue, _, err := env.Client.CreateIssue(env.Owner, env.RepoName, opts)
|
||||
if err != nil {
|
||||
env.T.Fatalf("failed to create test issue: %v", err)
|
||||
}
|
||||
|
||||
env.T.Logf("Created test issue #%d", issue.Index)
|
||||
return issue.Index
|
||||
}
|
||||
|
||||
// CleanupIssue closes and deletes a test issue
|
||||
func (env *TestEnv) CleanupIssue(issueNumber int64) {
|
||||
closeState := gitea.StateClosed
|
||||
_, _, err := env.Client.EditIssue(env.Owner, env.RepoName, issueNumber, gitea.EditIssueOption{
|
||||
State: &closeState,
|
||||
})
|
||||
if err != nil {
|
||||
env.T.Logf("warning: failed to close issue #%d: %v", issueNumber, err)
|
||||
}
|
||||
}
|
||||
|
||||
// CreateTestPullRequest creates a test PR (requires a branch to exist)
|
||||
func (env *TestEnv) CreateTestPullRequest(title, body, head, base string) int64 {
|
||||
opts := gitea.CreatePullRequestOption{
|
||||
Head: head,
|
||||
Base: base,
|
||||
Title: title,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
pr, _, err := env.Client.CreatePullRequest(env.Owner, env.RepoName, opts)
|
||||
if err != nil {
|
||||
env.T.Fatalf("failed to create test PR: %v", err)
|
||||
}
|
||||
|
||||
env.T.Logf("Created test PR #%d", pr.Index)
|
||||
return pr.Index
|
||||
}
|
||||
|
||||
// CleanupPullRequest closes a test PR
|
||||
func (env *TestEnv) CleanupPullRequest(prNumber int64) {
|
||||
closed := gitea.StateClosed
|
||||
_, _, err := env.Client.EditPullRequest(env.Owner, env.RepoName, prNumber, gitea.EditPullRequestOption{
|
||||
State: &closed,
|
||||
})
|
||||
if err != nil {
|
||||
env.T.Logf("warning: failed to close PR #%d: %v", prNumber, err)
|
||||
}
|
||||
}
|
||||
|
||||
// VerifyAPIConnection verifies the test environment can connect to the API
|
||||
func (env *TestEnv) VerifyAPIConnection() {
|
||||
_, _, err := env.Client.GetMyUserInfo()
|
||||
if err != nil {
|
||||
env.T.Fatalf("failed to verify API connection: %v", err)
|
||||
}
|
||||
}
|
||||
208
tests/functional/functional_test.go
Normal file
208
tests/functional/functional_test.go
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
// +build functional
|
||||
|
||||
package functional
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
// TestAPIConnection verifies we can connect to the Codeberg API with the test account
|
||||
func TestAPIConnection(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
env.VerifyAPIConnection()
|
||||
}
|
||||
|
||||
// TestListRepositories verifies we can list repositories
|
||||
func TestListRepositories(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
repos, _, err := env.Client.ListUserRepos(env.Owner, gitea.ListReposOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list repositories: %v", err)
|
||||
}
|
||||
|
||||
if len(repos) == 0 {
|
||||
t.Fatalf("expected at least one repository, got none")
|
||||
}
|
||||
|
||||
t.Logf("Found %d repositories", len(repos))
|
||||
|
||||
// Verify we can find our test repo
|
||||
found := false
|
||||
for _, repo := range repos {
|
||||
if repo.Name == env.RepoName {
|
||||
found = true
|
||||
t.Logf("Found test repository: %s", repo.FullName)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatalf("test repository %s not found in user's repositories", env.RepoName)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetRepository verifies we can get repository details
|
||||
func TestGetRepository(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
repo, _, err := env.Client.GetRepo(env.Owner, env.RepoName)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get repository: %v", err)
|
||||
}
|
||||
|
||||
if repo.Name != env.RepoName {
|
||||
t.Fatalf("expected repo name %s, got %s", env.RepoName, repo.Name)
|
||||
}
|
||||
|
||||
if repo.Owner.UserName != env.Owner {
|
||||
t.Fatalf("expected owner %s, got %s", env.Owner, repo.Owner.UserName)
|
||||
}
|
||||
|
||||
t.Logf("Repository: %s (%s)", repo.FullName, repo.Description)
|
||||
}
|
||||
|
||||
// TestCreateAndListIssues verifies we can create and list issues
|
||||
func TestCreateAndListIssues(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
// Create a test issue
|
||||
issueNum := env.CreateTestIssue(
|
||||
"[FGJ E2E Test] Test Issue",
|
||||
"This is a functional test issue for fgj",
|
||||
)
|
||||
|
||||
defer env.CleanupIssue(issueNum)
|
||||
|
||||
// List issues
|
||||
issues, _, err := env.Client.ListRepoIssues(env.Owner, env.RepoName, gitea.ListIssueOption{})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list issues: %v", err)
|
||||
}
|
||||
|
||||
// Verify our created issue is in the list
|
||||
found := false
|
||||
for _, issue := range issues {
|
||||
if issue.Index == issueNum {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatalf("created issue #%d not found in issue list", issueNum)
|
||||
}
|
||||
|
||||
t.Logf("Successfully created and listed issue #%d", issueNum)
|
||||
}
|
||||
|
||||
// TestGetIssue verifies we can get issue details
|
||||
func TestGetIssue(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
// Create a test issue
|
||||
issueNum := env.CreateTestIssue(
|
||||
"[FGJ E2E Test] Get Issue Test",
|
||||
"Testing get issue functionality",
|
||||
)
|
||||
|
||||
defer env.CleanupIssue(issueNum)
|
||||
|
||||
// Get the issue
|
||||
issue, _, err := env.Client.GetIssue(env.Owner, env.RepoName, issueNum)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get issue: %v", err)
|
||||
}
|
||||
|
||||
if issue.Index != issueNum {
|
||||
t.Fatalf("expected issue number %d, got %d", issueNum, issue.Index)
|
||||
}
|
||||
|
||||
if issue.Title != "[FGJ E2E Test] Get Issue Test" {
|
||||
t.Fatalf("issue title mismatch")
|
||||
}
|
||||
|
||||
t.Logf("Retrieved issue #%d: %s", issueNum, issue.Title)
|
||||
}
|
||||
|
||||
// TestCommentOnIssue verifies we can comment on issues
|
||||
func TestCommentOnIssue(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
// Create a test issue
|
||||
issueNum := env.CreateTestIssue(
|
||||
"[FGJ E2E Test] Comment Test",
|
||||
"Testing comment functionality",
|
||||
)
|
||||
|
||||
defer env.CleanupIssue(issueNum)
|
||||
|
||||
// Add a comment
|
||||
comment, _, err := env.Client.CreateIssueComment(
|
||||
env.Owner,
|
||||
env.RepoName,
|
||||
issueNum,
|
||||
gitea.CreateIssueCommentOption{
|
||||
Body: "This is an automated test comment from fgj functional tests",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create issue comment: %v", err)
|
||||
}
|
||||
|
||||
if comment.Body != "This is an automated test comment from fgj functional tests" {
|
||||
t.Fatalf("comment body mismatch")
|
||||
}
|
||||
|
||||
t.Logf("Successfully added comment to issue #%d", issueNum)
|
||||
}
|
||||
|
||||
// TestGetRepositoryWithCollaborators verifies we can get repo and check collaborators
|
||||
func TestGetRepositoryWithCollaborators(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
// Get repository with full details
|
||||
repo, _, err := env.Client.GetRepo(env.Owner, env.RepoName)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get repository: %v", err)
|
||||
}
|
||||
|
||||
// Verify basic repo properties
|
||||
if repo.FullName != env.Owner+"/"+env.RepoName {
|
||||
t.Fatalf("expected repo full name %s/%s, got %s", env.Owner, env.RepoName, repo.FullName)
|
||||
}
|
||||
|
||||
t.Logf("Repository %s has %d watchers, %d stars, %d forks",
|
||||
repo.FullName, repo.Watchers, repo.Stars, repo.Forks)
|
||||
}
|
||||
|
||||
// TestAPIErrorHandling verifies proper error handling for invalid requests
|
||||
func TestAPIErrorHandling(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
// Try to get a non-existent issue
|
||||
_, _, err := env.Client.GetIssue(env.Owner, env.RepoName, 999999)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for non-existent issue, got none")
|
||||
}
|
||||
|
||||
t.Logf("Properly handled error: %v", err)
|
||||
}
|
||||
|
||||
// TestRepositoryExists verifies the test repository exists and is accessible
|
||||
func TestRepositoryExists(t *testing.T) {
|
||||
env := NewTestEnv(t)
|
||||
|
||||
repo, _, err := env.Client.GetRepo(env.Owner, env.RepoName)
|
||||
if err != nil {
|
||||
t.Fatalf("test repository does not exist or is not accessible: %v", err)
|
||||
}
|
||||
|
||||
if repo.Private {
|
||||
t.Logf("Test repository is private: %s", repo.FullName)
|
||||
} else {
|
||||
t.Logf("Test repository is public: %s", repo.FullName)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue