Add git, auth and gists tests (#97)

This commit is contained in:
Thomas Miceli
2023-09-17 00:59:47 +02:00
committed by GitHub
parent 46dea89b41
commit fe674ac88b
11 changed files with 831 additions and 35 deletions

View File

@ -17,7 +17,6 @@ import (
"html/template"
"io"
"net/http"
"os"
"path/filepath"
"regexp"
"strconv"
@ -25,7 +24,7 @@ import (
"time"
)
var dev = os.Getenv("OG_DEV") == "1"
var dev bool
var store *sessions.CookieStore
var re = regexp.MustCompile("[^a-z0-9]+")
var fm = template.FuncMap{
@ -116,7 +115,13 @@ func (t *Template) Render(w io.Writer, name string, data interface{}, _ echo.Con
return t.templates.ExecuteTemplate(w, name, data)
}
func Start() {
type Server struct {
echo *echo.Echo
dev bool
}
func NewServer(isDev bool) *Server {
dev = isDev
store = sessions.NewCookieStore([]byte("opengist"))
gothic.Store = store
@ -172,13 +177,15 @@ func Start() {
// Web based routes
g1 := e.Group("")
{
g1.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
TokenLookup: "form:_csrf",
CookiePath: "/",
CookieHTTPOnly: true,
CookieSameSite: http.SameSiteStrictMode,
}))
g1.Use(csrfInit)
if !dev {
g1.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
TokenLookup: "form:_csrf",
CookiePath: "/",
CookieHTTPOnly: true,
CookieSameSite: http.SameSiteStrictMode,
}))
g1.Use(csrfInit)
}
g1.GET("/", create, logged)
g1.POST("/", processCreate, logged)
@ -242,30 +249,35 @@ func Start() {
}
}
debugStr := ""
// Git HTTP routes
if config.C.HttpGit {
e.Any("/:user/:gistname/*", gitHttp, gistSoftInit)
debugStr = " (with Git over HTTP)"
}
e.Any("/*", noRouteFound)
return &Server{echo: e, dev: dev}
}
func (s *Server) Start() {
addr := config.C.HttpHost + ":" + config.C.HttpPort
if config.C.HttpTLSEnabled {
log.Info().Msg("Starting HTTPS server on https://" + addr + debugStr)
if err := e.StartTLS(addr, config.C.HttpCertFile, config.C.HttpKeyFile); err != nil {
log.Fatal().Err(err).Msg("Failed to start HTTPS server")
}
} else {
log.Info().Msg("Starting HTTP server on http://" + addr + debugStr)
if err := e.Start(addr); err != nil {
log.Fatal().Err(err).Msg("Failed to start HTTP server")
}
log.Info().Msg("Starting HTTP server on http://" + addr)
if err := s.echo.Start(addr); err != nil && err != http.ErrServerClosed {
log.Fatal().Err(err).Msg("Failed to start HTTP server")
}
}
func (s *Server) Stop() {
if err := s.echo.Close(); err != nil {
log.Fatal().Err(err).Msg("Failed to stop HTTP server")
}
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.echo.ServeHTTP(w, r)
}
func dataInit(next echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
ctxValue := context.WithValue(ctx.Request().Context(), dataKey, echo.Map{})

View File

@ -0,0 +1,91 @@
package test
import (
"github.com/stretchr/testify/require"
"github.com/thomiceli/opengist/internal/db"
"testing"
)
func TestRegister(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
defer teardown(t, s)
err = s.request("GET", "/", nil, 302)
require.NoError(t, err)
err = s.request("GET", "/register", nil, 200)
require.NoError(t, err)
user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
register(t, s, user1)
user1db, err := db.GetUserById(1)
require.NoError(t, err)
require.Equal(t, user1.Username, user1db.Username)
require.True(t, user1db.IsAdmin)
err = s.request("GET", "/", nil, 200)
require.NoError(t, err)
s.sessionCookie = ""
user2 := db.UserDTO{Username: "thomas", Password: "azeaze"}
err = s.request("POST", "/register", user2, 200)
require.Error(t, err)
user3 := db.UserDTO{Username: "kaguya", Password: "kaguya"}
register(t, s, user3)
user3db, err := db.GetUserById(2)
require.NoError(t, err)
require.False(t, user3db.IsAdmin)
s.sessionCookie = ""
count, err := db.CountAll(db.User{})
require.NoError(t, err)
require.Equal(t, int64(2), count)
}
func TestLogin(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
defer teardown(t, s)
err = s.request("GET", "/login", nil, 200)
require.NoError(t, err)
user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
register(t, s, user1)
s.sessionCookie = ""
login(t, s, user1)
require.NotEmpty(t, s.sessionCookie)
s.sessionCookie = ""
user2 := db.UserDTO{Username: "thomas", Password: "azeaze"}
user3 := db.UserDTO{Username: "azeaze", Password: ""}
err = s.request("POST", "/login", user2, 302)
require.Empty(t, s.sessionCookie)
require.Error(t, err)
err = s.request("POST", "/login", user3, 302)
require.Empty(t, s.sessionCookie)
require.Error(t, err)
}
func register(t *testing.T, s *testServer, user db.UserDTO) {
err := s.request("POST", "/register", user, 302)
require.NoError(t, err)
}
func login(t *testing.T, s *testServer, user db.UserDTO) {
err := s.request("POST", "/login", user, 302)
require.NoError(t, err)
}

View File

@ -0,0 +1,200 @@
package test
import (
"github.com/stretchr/testify/require"
"github.com/thomiceli/opengist/internal/db"
"github.com/thomiceli/opengist/internal/git"
"testing"
)
func TestGists(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
defer teardown(t, s)
err = s.request("GET", "/", nil, 302)
require.NoError(t, err)
user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
register(t, s, user1)
err = s.request("GET", "/all", nil, 200)
require.NoError(t, err)
err = s.request("POST", "/", nil, 200)
require.NoError(t, err)
gist1 := db.GistDTO{
Title: "gist1",
Description: "my first gist",
Private: 0,
Name: []string{"gist1.txt", "gist2.txt", "gist3.txt"},
Content: []string{"yeah", "yeah\ncool", "yeah\ncool gist actually"},
}
err = s.request("POST", "/", gist1, 302)
require.NoError(t, err)
gist1db, err := db.GetGistByID("1")
require.NoError(t, err)
require.Equal(t, uint(1), gist1db.ID)
require.Equal(t, gist1.Title, gist1db.Title)
require.Equal(t, gist1.Description, gist1db.Description)
require.Regexp(t, "[a-f0-9]{32}", gist1db.Uuid)
require.Equal(t, user1.Username, gist1db.User.Username)
err = s.request("GET", "/"+gist1db.User.Username+"/"+gist1db.Uuid, nil, 200)
require.NoError(t, err)
gist1files, err := git.GetFilesOfRepository(gist1db.User.Username, gist1db.Uuid, "HEAD")
require.NoError(t, err)
require.Equal(t, 3, len(gist1files))
gist1fileContent, _, err := git.GetFileContent(gist1db.User.Username, gist1db.Uuid, "HEAD", gist1.Name[0], false)
require.NoError(t, err)
require.Equal(t, gist1.Content[0], gist1fileContent)
gist2 := db.GistDTO{
Title: "gist2",
Description: "my second gist",
Private: 0,
Name: []string{"", "gist2.txt", "gist3.txt"},
Content: []string{"", "yeah\ncool", "yeah\ncool gist actually"},
}
err = s.request("POST", "/", gist2, 200)
require.NoError(t, err)
gist3 := db.GistDTO{
Title: "gist3",
Description: "my third gist",
Private: 0,
Name: []string{""},
Content: []string{"yeah"},
}
err = s.request("POST", "/", gist3, 302)
require.NoError(t, err)
gist3db, err := db.GetGistByID("2")
require.NoError(t, err)
gist3files, err := git.GetFilesOfRepository(gist3db.User.Username, gist3db.Uuid, "HEAD")
require.NoError(t, err)
require.Equal(t, "gistfile1.txt", gist3files[0])
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/edit", nil, 200)
require.NoError(t, err)
gist1.Name = []string{"gist1.txt"}
gist1.Content = []string{"only want one gist"}
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/edit", gist1, 302)
require.NoError(t, err)
gist1files, err = git.GetFilesOfRepository(gist1db.User.Username, gist1db.Uuid, "HEAD")
require.NoError(t, err)
require.Equal(t, 1, len(gist1files))
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/delete", nil, 302)
require.NoError(t, err)
}
func TestVisibility(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
defer teardown(t, s)
user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
register(t, s, user1)
gist1 := db.GistDTO{
Title: "gist1",
Description: "my first gist",
Private: 1,
Name: []string{""},
Content: []string{"yeah"},
}
err = s.request("POST", "/", gist1, 302)
require.NoError(t, err)
gist1db, err := db.GetGistByID("1")
require.NoError(t, err)
require.Equal(t, 1, gist1db.Private)
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", nil, 302)
require.NoError(t, err)
gist1db, err = db.GetGistByID("1")
require.NoError(t, err)
require.Equal(t, 2, gist1db.Private)
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", nil, 302)
require.NoError(t, err)
gist1db, err = db.GetGistByID("1")
require.NoError(t, err)
require.Equal(t, 0, gist1db.Private)
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/visibility", nil, 302)
require.NoError(t, err)
gist1db, err = db.GetGistByID("1")
require.NoError(t, err)
require.Equal(t, 1, gist1db.Private)
}
func TestLikeFork(t *testing.T) {
setup(t)
s, err := newTestServer()
require.NoError(t, err, "Failed to create test server")
defer teardown(t, s)
user1 := db.UserDTO{Username: "thomas", Password: "thomas"}
register(t, s, user1)
gist1 := db.GistDTO{
Title: "gist1",
Description: "my first gist",
Private: 1,
Name: []string{""},
Content: []string{"yeah"},
}
err = s.request("POST", "/", gist1, 302)
require.NoError(t, err)
s.sessionCookie = ""
user2 := db.UserDTO{Username: "kaguya", Password: "kaguya"}
register(t, s, user2)
gist1db, err := db.GetGistByID("1")
require.NoError(t, err)
require.Equal(t, 0, gist1db.NbLikes)
likeCount, err := db.CountAll(db.Like{})
require.NoError(t, err)
require.Equal(t, int64(0), likeCount)
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/like", nil, 302)
require.NoError(t, err)
gist1db, err = db.GetGistByID("1")
require.NoError(t, err)
require.Equal(t, 1, gist1db.NbLikes)
likeCount, err = db.CountAll(db.Like{})
require.NoError(t, err)
require.Equal(t, int64(1), likeCount)
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/like", nil, 302)
require.NoError(t, err)
gist1db, err = db.GetGistByID("1")
require.NoError(t, err)
require.Equal(t, 0, gist1db.NbLikes)
likeCount, err = db.CountAll(db.Like{})
require.NoError(t, err)
require.Equal(t, int64(0), likeCount)
err = s.request("POST", "/"+gist1db.User.Username+"/"+gist1db.Uuid+"/fork", nil, 302)
require.NoError(t, err)
gist2db, err := db.GetGistByID("2")
require.NoError(t, err)
require.Equal(t, gist1db.Title, gist2db.Title)
require.Equal(t, gist1db.Description, gist2db.Description)
require.Equal(t, gist1db.Private, gist2db.Private)
require.Equal(t, user2.Username, gist2db.User.Username)
}

162
internal/web/test/server.go Normal file
View File

@ -0,0 +1,162 @@
package test
import (
"errors"
"fmt"
"github.com/rs/zerolog/log"
"github.com/stretchr/testify/require"
"github.com/thomiceli/opengist/internal/config"
"github.com/thomiceli/opengist/internal/db"
"github.com/thomiceli/opengist/internal/git"
"github.com/thomiceli/opengist/internal/memdb"
"github.com/thomiceli/opengist/internal/web"
"io"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"path/filepath"
"reflect"
"strconv"
"strings"
"testing"
)
type testServer struct {
server *web.Server
sessionCookie string
}
func newTestServer() (*testServer, error) {
s := &testServer{
server: web.NewServer(true),
}
go s.start()
return s, nil
}
func (s *testServer) start() {
s.server.Start()
}
func (s *testServer) stop() {
s.server.Stop()
}
func (s *testServer) request(method, uri string, data interface{}, expectedCode int) error {
var bodyReader io.Reader
if method == http.MethodPost || method == http.MethodPut {
values := structToURLValues(data)
bodyReader = strings.NewReader(values.Encode())
}
req := httptest.NewRequest(method, "http://localhost:6157"+uri, bodyReader)
w := httptest.NewRecorder()
if method == http.MethodPost || method == http.MethodPut {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
if s.sessionCookie != "" {
req.AddCookie(&http.Cookie{Name: "session", Value: s.sessionCookie})
}
s.server.ServeHTTP(w, req)
if w.Code != expectedCode {
return fmt.Errorf("unexpected status code %d, expected %d", w.Code, expectedCode)
}
if method == http.MethodPost {
if strings.Contains(uri, "/login") || strings.Contains(uri, "/register") {
cookie := ""
h := w.Header().Get("Set-Cookie")
parts := strings.Split(h, "; ")
for _, p := range parts {
if strings.HasPrefix(p, "session=") {
cookie = p
break
}
}
if cookie == "" {
return errors.New("unable to find access session token in response headers")
}
s.sessionCookie = strings.TrimPrefix(cookie, "session=")
} else if strings.Contains(uri, "/logout") {
s.sessionCookie = ""
}
}
return nil
}
func structToURLValues(s interface{}) url.Values {
v := url.Values{}
if s == nil {
return v
}
rValue := reflect.ValueOf(s)
if rValue.Kind() != reflect.Struct {
return v
}
for i := 0; i < rValue.NumField(); i++ {
field := rValue.Type().Field(i)
tag := field.Tag.Get("form")
if tag != "" {
if field.Type.Kind() == reflect.Int {
fieldValue := rValue.Field(i).Int()
v.Add(tag, strconv.FormatInt(fieldValue, 10))
} else if field.Type.Kind() == reflect.Slice {
fieldValue := rValue.Field(i).Interface().([]string)
for _, va := range fieldValue {
v.Add(tag, va)
}
} else {
fieldValue := rValue.Field(i).String()
v.Add(tag, fieldValue)
}
}
}
return v
}
func setup(t *testing.T) {
err := config.InitConfig("")
require.NoError(t, err, "Could not init config")
err = os.MkdirAll(filepath.Join(config.GetHomeDir()), 0755)
require.NoError(t, err, "Could not create Opengist home directory")
git.ReposDirectory = path.Join("tests")
config.InitLog()
homePath := config.GetHomeDir()
log.Info().Msg("Data directory: " + homePath)
err = os.MkdirAll(filepath.Join(homePath, "repos"), 0755)
require.NoError(t, err, "Could not create repos directory")
err = os.MkdirAll(filepath.Join(homePath, "tmp", "repos"), 0755)
require.NoError(t, err, "Could not create tmp repos directory")
err = db.Setup("file::memory:", true)
require.NoError(t, err, "Could not initialize database")
err = memdb.Setup()
require.NoError(t, err, "Could not initialize in memory database")
}
func teardown(t *testing.T, s *testServer) {
s.stop()
err := db.Close()
require.NoError(t, err, "Could not close database")
err = os.RemoveAll(path.Join(config.C.OpengistHome, "tests"))
require.NoError(t, err, "Could not remove repos directory")
}