Skip to content

Commit

Permalink
test: smoke tests with testscript (#305)
Browse files Browse the repository at this point in the history
* test: playing with testscript

* fix: multiple servers

* fix: -update flag

* test: user management tests

* test: fix config

* fix: ensure perms after clone

* fix: race condition

* fix: shutdown

* test: set-username

* test: repo collab

* test: repo mirror and other ops

* test: import repo

* test: repo create

* test: disable hooks on testscript

* test: random port: prevent port reuse

* test: wait for server

* fix: git with no user info

* test: no idea whats going on on windows

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* test: create keys on runtime

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* chore: organizing repo

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: remove if for windows

* Revert "fix: remove if for windows"

This reverts commit 5776fde.

* chore: trying something out

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* refactor: use crypto/ssh instead of ssh binary

* fix: neg only the actual cmd

* fix: unix2dos on windows tests

* fix: unix2dos

* fix: skip hooks on tests

* fix: trainling whitespace

* chore: editorconfig and gitattributes

* test: maybe its not really needed?

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* Revert "test: maybe its not really needed?"

This reverts commit a704c5f.

* fix: improve \r\n handling

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: crlf

* chore: trigger

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: disable unix2docs

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* test: validate repo

* chore: debug

* fix(test): convert dos crlf to lf (#311)

* fix(test): convert dos crlf to lf

* use temp files

* chore: log

* fix: ssh config

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: config

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix(ci): use build workflow from main

* fix: editorconfig

* fix: editorconfig

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* feat(test): add SanitizeRepo tests

* fix(test): sanitizerepo test

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
Co-authored-by: Ayman Bagabas <ayman.bagabas@gmail.com>
  • Loading branch information
caarlos0 and aymanbagabas committed May 25, 2023
1 parent 1c781fe commit 6d6e112
Show file tree
Hide file tree
Showing 21 changed files with 744 additions and 23 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
@@ -0,0 +1,13 @@
root = true

[*]
charset=utf-8
end_of_line=lf
insert_final_newline=true
trim_trailing_whitespace=true
indent_size=2
indent_style=space

[*.go]
indent_size=4
indent_style=tab
2 changes: 2 additions & 0 deletions .gitattributes
@@ -0,0 +1,2 @@
# To prevent CRLF breakages on Windows for fragile files, like testdata.
* -text
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Expand Up @@ -25,4 +25,4 @@ jobs:
run: go test -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.txt ./... -timeout 5m
- uses: codecov/codecov-action@v3
with:
file: ./coverage.txt
file: ./coverage.txt
4 changes: 2 additions & 2 deletions go.mod
Expand Up @@ -31,6 +31,7 @@ require (
github.com/muesli/roff v0.1.0
github.com/prometheus/client_golang v1.15.1
github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97
github.com/spf13/cobra v1.7.0
go.uber.org/automaxprocs v1.5.2
goji.io v2.0.2+incompatible
Expand Down Expand Up @@ -73,12 +74,11 @@ require (
github.com/prometheus/procfs v0.9.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/term v0.8.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Expand Up @@ -153,8 +153,8 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY=
github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
Expand Down Expand Up @@ -185,8 +185,8 @@ goji.io v2.0.2+incompatible/go.mod h1:sbqFwrtqZACxLBTQcdgVjFh54yGVCvwq8+w49MVMMI
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
Expand Down
3 changes: 2 additions & 1 deletion server/backend/sqlite/user.go
Expand Up @@ -42,7 +42,8 @@ func (u *User) PublicKeys() []ssh.PublicKey {
if err := tx.Select(&keyStrings, `SELECT public_key
FROM public_key
INNER JOIN user ON user.id = public_key.user_id
WHERE user.username = ?;`, u.username); err != nil {
WHERE user.username = ?
ORDER BY public_key.id asc;`, u.username); err != nil {
return err
}

Expand Down
14 changes: 11 additions & 3 deletions server/cmd/repo.go
@@ -1,6 +1,11 @@
package cmd

import "github.com/spf13/cobra"
import (
"fmt"
"strings"

"github.com/spf13/cobra"
)

func repoCommand() *cobra.Command {
cmd := &cobra.Command{
Expand Down Expand Up @@ -53,9 +58,12 @@ func repoCommand() *cobra.Command {

branches, _ := r.Branches()
tags, _ := r.Tags()
cmd.Println("Project Name:", rr.ProjectName())

// project name and description are optional, handle trailing
// whitespace to avoid breaking tests.
cmd.Println(strings.TrimSpace(fmt.Sprint("Project Name: ", rr.ProjectName())))
cmd.Println("Repository:", rr.Name())
cmd.Println("Description:", rr.Description())
cmd.Println(strings.TrimSpace(fmt.Sprint("Description: ", rr.Description())))
cmd.Println("Private:", rr.IsPrivate())
cmd.Println("Hidden:", rr.IsHidden())
cmd.Println("Mirror:", rr.IsMirror())
Expand Down
18 changes: 11 additions & 7 deletions server/hooks/hooks.go
Expand Up @@ -3,6 +3,7 @@ package hooks
import (
"bytes"
"context"
"flag"
"fmt"
"os"
"path/filepath"
Expand All @@ -28,8 +29,13 @@ const (
// - post-update
//
// This function should be called by the backend when a repository is created.
// TODO: support context
func GenerateHooks(ctx context.Context, cfg *config.Config, repo string) error {
// TODO: support context.
func GenerateHooks(_ context.Context, cfg *config.Config, repo string) error {
// TODO: support git hook tests.
if flag.Lookup("test.v") != nil {
log.WithPrefix("backend.hooks").Warn("refusing to set up hooks when in test")
return nil
}
repo = utils.SanitizeRepo(repo) + ".git"
hooksPath := filepath.Join(cfg.DataPath, "repos", repo, "hooks")
if err := os.MkdirAll(hooksPath, os.ModePerm); err != nil {
Expand Down Expand Up @@ -136,10 +142,9 @@ done
`
)

var (
// hooksTmpl is the soft-serve hook that will be run by the git hooks
// inside the hooks directory.
hooksTmpl = template.Must(template.New("hooks").Parse(`#!/usr/bin/env bash
// hooksTmpl is the soft-serve hook that will be run by the git hooks
// inside the hooks directory.
var hooksTmpl = template.Must(template.New("hooks").Parse(`#!/usr/bin/env bash
# AUTO GENERATED BY SOFT SERVE, DO NOT MODIFY
if [ -z "$SOFT_SERVE_REPO_NAME" ]; then
echo "Warning: SOFT_SERVE_REPO_NAME not defined. Skipping hooks."
Expand All @@ -149,4 +154,3 @@ fi
{{ $env }} \{{ end }}
{{ .Executable }} hook --config "{{ .Config }}" {{ .Hook }} {{ .Args }}
`))
)
1 change: 0 additions & 1 deletion server/jobs.go
Expand Up @@ -51,7 +51,6 @@ func (s *Server) mirrorJob() func() {
if _, err := cmd.RunInDir(r.Path); err != nil {
logger.Error("error running git remote update", "repo", name, "err", err)
}

})
}
}
Expand Down
7 changes: 7 additions & 0 deletions server/server.go
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"io"
"net/http"

"github.com/charmbracelet/log"
Expand Down Expand Up @@ -158,6 +159,9 @@ func (s *Server) Shutdown(ctx context.Context) error {
s.Cron.Stop()
return nil
})
if closer, ok := s.Backend.(io.Closer); ok {
defer closer.Close() // nolint: errcheck
}
return errg.Wait()
}

Expand All @@ -172,5 +176,8 @@ func (s *Server) Close() error {
s.Cron.Stop()
return nil
})
if closer, ok := s.Backend.(io.Closer); ok {
defer closer.Close() // nolint: errcheck
}
return errg.Wait()
}
22 changes: 20 additions & 2 deletions server/test/test.go
@@ -1,11 +1,29 @@
package test

import "net"
import (
"net"
"sync"
)

var (
used = map[int]struct{}{}
lock sync.Mutex
)

// RandomPort returns a random port number.
// This is mainly used for testing.
func RandomPort() int {
addr, _ := net.Listen("tcp", ":0") //nolint:gosec
_ = addr.Close()
return addr.Addr().(*net.TCPAddr).Port
port := addr.Addr().(*net.TCPAddr).Port
lock.Lock()

if _, ok := used[port]; ok {
lock.Unlock()
return RandomPort()
}

used[port] = struct{}{}
lock.Unlock()
return port
}
6 changes: 4 additions & 2 deletions server/utils/utils.go
Expand Up @@ -2,15 +2,17 @@ package utils

import (
"fmt"
"path/filepath"
"path"
"strings"
"unicode"
)

// SanitizeRepo returns a sanitized version of the given repository name.
func SanitizeRepo(repo string) string {
repo = strings.TrimPrefix(repo, "/")
repo = filepath.Clean(repo)
// We're using path instead of filepath here because this is not OS dependent
// looking at you Windows
repo = path.Clean(repo)
repo = strings.TrimSuffix(repo, ".git")
return repo
}
Expand Down
56 changes: 56 additions & 0 deletions server/utils/utils_test.go
@@ -0,0 +1,56 @@
package utils

import "testing"

func TestValidateRepo(t *testing.T) {
t.Run("valid", func(t *testing.T) {
for _, repo := range []string{
"lower",
"Upper",
"with-dash",
"with/slash",
"withnumb3r5",
"with.dot",
"with_underline",
} {
t.Run(repo, func(t *testing.T) {
if err := ValidateRepo(repo); err != nil {
t.Errorf("expected no error, got %v", err)
}
})
}
})
t.Run("invalid", func(t *testing.T) {
for _, repo := range []string{
"with$",
"with@",
"with!",
} {
t.Run(repo, func(t *testing.T) {
if err := ValidateRepo(repo); err == nil {
t.Error("expected an error, got nil")
}
})
}
})
}

func TestSanitizeRepo(t *testing.T) {
cases := []struct {
in, out string
}{
{"lower", "lower"},
{"Upper", "Upper"},
{"with/slash", "with/slash"},
{"with.dot", "with.dot"},
{"/with_forward_slash", "with_forward_slash"},
{"withgitsuffix.git", "withgitsuffix"},
}
for _, c := range cases {
t.Run(c.in, func(t *testing.T) {
if got := SanitizeRepo(c.in); got != c.out {
t.Errorf("expected %q, got %q", c.out, got)
}
})
}
}

0 comments on commit 6d6e112

Please sign in to comment.