Skip to content

Commit d70a1b1

Browse files
Merge pull request #11 from github/stolee/bundle-create-tests
Unit test GetRepositories()
2 parents 49b7e1d + de58f24 commit d70a1b1

File tree

12 files changed

+352
-179
lines changed

12 files changed

+352
-179
lines changed

cmd/git-bundle-server/cron.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@ import (
55
"os"
66
"strings"
77

8+
"github.com/github/git-bundle-server/internal/common"
89
"github.com/github/git-bundle-server/internal/core"
910
)
1011

1112
func SetCronSchedule() error {
13+
user, err := common.NewUserProvider().CurrentUser()
14+
if err != nil {
15+
return err
16+
}
17+
1218
pathToExec, err := os.Executable()
1319
if err != nil {
1420
return fmt.Errorf("failed to get executable: %w", err)
@@ -33,7 +39,7 @@ func SetCronSchedule() error {
3339
}
3440

3541
scheduleBytes = append(scheduleBytes, []byte(dailySchedule)...)
36-
scheduleFile := core.CrontabFile()
42+
scheduleFile := core.CrontabFile(user)
3743

3844
err = os.WriteFile(scheduleFile, scheduleBytes, 0o600)
3945
if err != nil {

cmd/git-bundle-server/update-all.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os/exec"
77

88
"github.com/github/git-bundle-server/internal/argparse"
9+
"github.com/github/git-bundle-server/internal/common"
910
"github.com/github/git-bundle-server/internal/core"
1011
)
1112

@@ -21,6 +22,12 @@ For every configured route, run 'git-bundle-server update <options> <route>'.`
2122
}
2223

2324
func (UpdateAll) Run(args []string) error {
25+
user, err := common.NewUserProvider().CurrentUser()
26+
if err != nil {
27+
return err
28+
}
29+
fs := common.NewFileSystem()
30+
2431
parser := argparse.NewArgParser("git-bundle-server update-all")
2532
parser.Parse(args)
2633

@@ -29,7 +36,7 @@ func (UpdateAll) Run(args []string) error {
2936
return fmt.Errorf("failed to get path to execuable: %w", err)
3037
}
3138

32-
repos, err := core.GetRepositories()
39+
repos, err := core.GetRepositories(user, fs)
3340
if err != nil {
3441
return err
3542
}

cmd/git-bundle-web-server/main.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/github/git-bundle-server/cmd/utils"
1616
"github.com/github/git-bundle-server/internal/argparse"
17+
"github.com/github/git-bundle-server/internal/common"
1718
"github.com/github/git-bundle-server/internal/core"
1819
)
1920

@@ -34,6 +35,11 @@ func parseRoute(path string) (string, string, string, error) {
3435
}
3536

3637
func serve(w http.ResponseWriter, r *http.Request) {
38+
user, err := common.NewUserProvider().CurrentUser()
39+
if err != nil {
40+
return
41+
}
42+
fs := common.NewFileSystem()
3743
path := r.URL.Path
3844

3945
owner, repo, file, err := parseRoute(path)
@@ -45,7 +51,7 @@ func serve(w http.ResponseWriter, r *http.Request) {
4551

4652
route := owner + "/" + repo
4753

48-
repos, err := core.GetRepositories()
54+
repos, err := core.GetRepositories(user, fs)
4955
if err != nil {
5056
w.WriteHeader(http.StatusInternalServerError)
5157
fmt.Printf("Failed to load routes\n")

internal/common/filesystem.go

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package common
22

33
import (
4+
"bufio"
45
"errors"
56
"fmt"
67
"os"
@@ -10,6 +11,7 @@ import (
1011
type FileSystem interface {
1112
FileExists(filename string) (bool, error)
1213
WriteFile(filename string, content []byte) error
14+
ReadFileLines(filename string) ([]string, error)
1315
}
1416

1517
type fileSystem struct{}
@@ -32,14 +34,30 @@ func (f *fileSystem) FileExists(filename string) (bool, error) {
3234
func (f *fileSystem) WriteFile(filename string, content []byte) error {
3335
// Get filename parent path
3436
parentDir := path.Dir(filename)
35-
err := os.MkdirAll(parentDir, 0755)
37+
err := os.MkdirAll(parentDir, 0o755)
3638
if err != nil {
3739
return fmt.Errorf("error creating parent directories: %w", err)
3840
}
3941

40-
err = os.WriteFile(filename, content, 0644)
42+
err = os.WriteFile(filename, content, 0o644)
4143
if err != nil {
4244
return fmt.Errorf("could not write file: %w", err)
4345
}
4446
return nil
4547
}
48+
49+
func (f *fileSystem) ReadFileLines(filename string) ([]string, error) {
50+
file, err := os.OpenFile(filename, os.O_RDONLY|os.O_CREATE, 0o600)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
var l []string
56+
reader := bufio.NewReader(file)
57+
scanner := bufio.NewScanner(reader)
58+
for scanner.Scan() {
59+
l = append(l, scanner.Text())
60+
}
61+
62+
return l, nil
63+
}

internal/core/paths.go

+11-15
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
11
package core
22

3-
import "os"
3+
import (
4+
"os/user"
5+
)
46

5-
func bundleroot() string {
6-
dirname, err := os.UserHomeDir()
7-
if err != nil {
8-
// TODO: respond better. For now, try creating in "/var"
9-
dirname = "/var"
10-
}
11-
12-
return dirname + "/git-bundle-server/"
7+
func bundleroot(user *user.User) string {
8+
return user.HomeDir + "/git-bundle-server/"
139
}
1410

15-
func webroot() string {
16-
return bundleroot() + "www/"
11+
func webroot(user *user.User) string {
12+
return bundleroot(user) + "www/"
1713
}
1814

19-
func reporoot() string {
20-
return bundleroot() + "git/"
15+
func reporoot(user *user.User) string {
16+
return bundleroot(user) + "git/"
2117
}
2218

23-
func CrontabFile() string {
24-
return bundleroot() + "cron-schedule"
19+
func CrontabFile(user *user.User) string {
20+
return bundleroot(user) + "cron-schedule"
2521
}

internal/core/repo.go

+31-23
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package core
22

33
import (
4-
"bufio"
54
"fmt"
6-
"io"
75
"log"
86
"os"
7+
"os/user"
8+
9+
"github.com/github/git-bundle-server/internal/common"
910
)
1011

1112
type Repository struct {
@@ -15,7 +16,12 @@ type Repository struct {
1516
}
1617

1718
func CreateRepository(route string) (*Repository, error) {
18-
repos, err := GetRepositories()
19+
user, err := common.NewUserProvider().CurrentUser()
20+
if err != nil {
21+
return nil, err
22+
}
23+
fs := common.NewFileSystem()
24+
repos, err := GetRepositories(user, fs)
1925
if err != nil {
2026
return nil, fmt.Errorf("failed to parse routes file")
2127
}
@@ -25,8 +31,8 @@ func CreateRepository(route string) (*Repository, error) {
2531
return &repo, nil
2632
}
2733

28-
repodir := reporoot() + route
29-
web := webroot() + route
34+
repodir := reporoot(user) + route
35+
web := webroot(user) + route
3036

3137
mkdirErr := os.MkdirAll(web, os.ModePerm)
3238
if mkdirErr != nil {
@@ -50,7 +56,12 @@ func CreateRepository(route string) (*Repository, error) {
5056
}
5157

5258
func RemoveRoute(route string) error {
53-
repos, err := GetRepositories()
59+
user, err := common.NewUserProvider().CurrentUser()
60+
if err != nil {
61+
return err
62+
}
63+
fs := common.NewFileSystem()
64+
repos, err := GetRepositories(user, fs)
5465
if err != nil {
5566
return fmt.Errorf("failed to parse routes file")
5667
}
@@ -66,7 +77,11 @@ func RemoveRoute(route string) error {
6677
}
6778

6879
func WriteRouteFile(repos map[string]Repository) error {
69-
dir := bundleroot()
80+
user, err := common.NewUserProvider().CurrentUser()
81+
if err != nil {
82+
return err
83+
}
84+
dir := bundleroot(user)
7085
routefile := dir + "/routes"
7186

7287
contents := ""
@@ -78,32 +93,25 @@ func WriteRouteFile(repos map[string]Repository) error {
7893
return os.WriteFile(routefile, []byte(contents), 0o600)
7994
}
8095

81-
func GetRepositories() (map[string]Repository, error) {
96+
func GetRepositories(user *user.User, fs common.FileSystem) (map[string]Repository, error) {
8297
repos := make(map[string]Repository)
8398

84-
dir := bundleroot()
99+
dir := bundleroot(user)
85100
routefile := dir + "/routes"
86101

87-
file, err := os.OpenFile(routefile, os.O_RDONLY|os.O_CREATE, 0o600)
102+
lines, err := fs.ReadFileLines(routefile)
88103
if err != nil {
89-
// Assume that the file doesn't exist?
90-
return repos, nil
104+
return nil, err
91105
}
92-
93-
reader := bufio.NewReader(file)
94-
for {
95-
line, err := reader.ReadString('\n')
96-
if line == "" || line[0] == '\n' ||
97-
(err != nil && err != io.EOF) {
98-
break
106+
for _, route := range lines {
107+
if route == "" {
108+
continue
99109
}
100110

101-
route := line[0 : len(line)-1]
102-
103111
repo := Repository{
104112
Route: route,
105-
RepoDir: reporoot() + route,
106-
WebDir: webroot() + route,
113+
RepoDir: reporoot(user) + route,
114+
WebDir: webroot(user) + route,
107115
}
108116
repos[route] = repo
109117
}

internal/core/repo_test.go

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package core_test
2+
3+
import (
4+
"errors"
5+
"os/user"
6+
"testing"
7+
8+
"github.com/github/git-bundle-server/internal/core"
9+
. "github.com/github/git-bundle-server/internal/testhelpers"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/mock"
12+
)
13+
14+
var getRepositoriesTests = []struct {
15+
title string
16+
17+
// Expected values
18+
readFileLines Pair[[]string, error]
19+
20+
// Expected output
21+
expectedRepos []core.Repository
22+
expectedErr bool
23+
}{
24+
{
25+
"empty file, empty list",
26+
NewPair[[]string, error]([]string{}, nil),
27+
[]core.Repository{},
28+
false,
29+
},
30+
{
31+
"error from filesystem",
32+
NewPair([]string{}, errors.New("error")),
33+
[]core.Repository{},
34+
true,
35+
},
36+
{
37+
"one repository",
38+
NewPair[[]string, error]([]string{
39+
"git/git",
40+
}, nil),
41+
[]core.Repository{
42+
{
43+
Route: "git/git",
44+
RepoDir: "/my/test/dir/git-bundle-server/git/git/git",
45+
WebDir: "/my/test/dir/git-bundle-server/www/git/git",
46+
},
47+
},
48+
false,
49+
},
50+
{
51+
"multiple repositories",
52+
NewPair[[]string, error]([]string{
53+
"git/git",
54+
"github/github",
55+
"org with spaces/repo with spaces",
56+
"", // Skips empty lines.
57+
"three/deep/repo",
58+
}, nil),
59+
[]core.Repository{
60+
{
61+
Route: "git/git",
62+
RepoDir: "/my/test/dir/git-bundle-server/git/git/git",
63+
WebDir: "/my/test/dir/git-bundle-server/www/git/git",
64+
},
65+
{
66+
Route: "github/github",
67+
RepoDir: "/my/test/dir/git-bundle-server/git/github/github",
68+
WebDir: "/my/test/dir/git-bundle-server/www/github/github",
69+
},
70+
{
71+
Route: "org with spaces/repo with spaces",
72+
RepoDir: "/my/test/dir/git-bundle-server/git/org with spaces/repo with spaces",
73+
WebDir: "/my/test/dir/git-bundle-server/www/org with spaces/repo with spaces",
74+
},
75+
{
76+
Route: "three/deep/repo",
77+
RepoDir: "/my/test/dir/git-bundle-server/git/three/deep/repo",
78+
WebDir: "/my/test/dir/git-bundle-server/www/three/deep/repo",
79+
},
80+
},
81+
false,
82+
},
83+
}
84+
85+
func TestRepos_GetRepositories(t *testing.T) {
86+
testFileSystem := &MockFileSystem{}
87+
testUser := &user.User{
88+
Uid: "123",
89+
Username: "testuser",
90+
HomeDir: "/my/test/dir",
91+
}
92+
93+
for _, tt := range getRepositoriesTests {
94+
t.Run(tt.title, func(t *testing.T) {
95+
testFileSystem.On("UserHomeDir").Return("/my/test/dir", nil)
96+
testFileSystem.On("ReadFileLines",
97+
mock.AnythingOfType("string"),
98+
).Return(tt.readFileLines.First, tt.readFileLines.Second).Once()
99+
100+
actual, err := core.GetRepositories(testUser, testFileSystem)
101+
102+
if tt.expectedErr {
103+
assert.NotNil(t, err, "Expected error")
104+
assert.Nil(t, actual, "Expected nil list")
105+
} else {
106+
assert.Nil(t, err, "Expected success")
107+
assert.NotNil(t, actual, "Expected non-nil list")
108+
assert.Equal(t, len(tt.expectedRepos), len(actual), "Length mismatch")
109+
for _, repo := range tt.expectedRepos {
110+
a := actual[repo.Route]
111+
112+
assert.Equal(t, repo.Route, a.Route)
113+
assert.Equal(t, repo.RepoDir, a.RepoDir)
114+
assert.Equal(t, repo.WebDir, a.WebDir)
115+
}
116+
}
117+
})
118+
}
119+
}

0 commit comments

Comments
 (0)