Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access log middleware #18

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 34 additions & 42 deletions cmd/main/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"context"
"database/sql"
"fmt"
_ "github.com/lib/pq"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"

"sparkit/internal/handlers/checkauth"
"sparkit/internal/handlers/getuserlist"
"sparkit/internal/handlers/logout"
"sparkit/internal/handlers/middleware"
"sparkit/internal/handlers/middleware/authcheck"
"sparkit/internal/handlers/middleware/corsMiddleware"
"sparkit/internal/handlers/signin"
Expand All @@ -20,44 +23,46 @@ import (
"sparkit/internal/repo/user"
sessionusecase "sparkit/internal/usecase/session"
userusecase "sparkit/internal/usecase/user"
"syscall"
"time"

_ "github.com/lib/pq"
"go.uber.org/zap"
)

func main() {
ctx := context.Background()

connStr := "host=sparkit-postgres port=5432 user=reufee password=sparkit dbname=sparkitDB sslmode=disable"
db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatal(err)
}
defer db.Close()

err = db.Ping()
if err != nil {
if err = db.Ping(); err != nil {
log.Fatal(err)
}
fmt.Println("Successfully connected to PostgreSQL!")

createTableSQL := `CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(100),
password VARCHAR(100),
Age INT NOT NULL,
Gender VARCHAR(100)
);`

_, err = db.Exec(createTableSQL)
if err != nil {
id SERIAL PRIMARY KEY,
username VARCHAR(100),
password VARCHAR(100),
Age INT NOT NULL,
Gender VARCHAR(100)
);`

if _, err = db.Exec(createTableSQL); err != nil {
log.Fatalf("Error creating table: %s", err)
} else {
fmt.Println("Table created successfully!")
}

//userRepo := &pkg.InMemoryUserRepository{DB: db}
//sessionRepo := pkg.InMemorySessionRepository{}
//sessionService := pkg.NewSessionService(sessionRepo)
//userUseCase := userusecase.New(userRepo)
logger, err := zap.NewProduction()
if err != nil {
log.Fatalf("Failed to initialize zap logger: %v", err)
}
defer logger.Sync()
sugar := logger.Sugar()

userStorage := user.New(db)
sessionStorage := session.New()

Expand All @@ -67,11 +72,11 @@ func main() {
signUp := signup.NewHandler(userUsecase, sessionUsecase)
signIn := signin.NewHandler(userUsecase, sessionUsecase)
getUsers := getuserlist.NewHandler(userUsecase)
//checkAuth handler
checkAuth := checkauth.NewHandler(sessionUsecase)
//logOut handler
logOut := logout.NewHandler(sessionUsecase)
authMiddleware := authcheck.New(sessionUsecase)
accessLogMiddleware := middleware.NewAccessLogMiddleware(sugar)

mux := http.NewServeMux()

mux.Handle("/signup", corsMiddleware.CORSMiddleware(http.HandlerFunc(signUp.Handle)))
Expand All @@ -83,42 +88,29 @@ func main() {
fmt.Fprintf(w, "Hello World\n")
})

//c := cors.New(cors.Options{
// AllowedOrigins: []string{"*"},
// AllowedMethods: []string{"GET", "POST"},
// AllowCredentials: true,
//})
//handler := c.Handler(mux)
loggedMux := accessLogMiddleware.Handler(mux)

// Создаем HTTP-сервер
srv := &http.Server{
Addr: ":8080",
Handler: mux,
Handler: loggedMux,
}
// Запускаем сервер в отдельной горутине

go func() {
fmt.Println("starting a server")
fmt.Println("Starting the server")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
fmt.Printf("Ошибка при запуске сервера: %v\n", err)
fmt.Printf("Error starting server: %v\n", err)
}
}()

// Создаем канал для получения сигналов
stop := make(chan os.Signal, 1)
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)

// Ожидаем сигнала завершения
<-stop
fmt.Println("Получен сигнал завершения. Завершение работы...")
fmt.Println("Termination signal received. Shutting down...")

// Устанавливаем контекст с таймаутом для завершения
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// Корректно завершаем работу сервера
if err := srv.Shutdown(ctx); err != nil {
fmt.Printf("Ошибка при завершении работы сервера: %v\n", err)
fmt.Printf("Error shutting down server: %v\n", err)
}

fmt.Println("Сервер завершил работу.")
fmt.Println("Server has shut down.")
}
13 changes: 4 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ module sparkit
go 1.22.5

require (
github.com/golang/mock v1.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/rs/cors v1.11.1 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/tools v0.1.1 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
github.com/golang/mock v1.6.0
github.com/google/uuid v1.6.0
github.com/lib/pq v1.10.9
golang.org/x/crypto v0.27.0
)
7 changes: 0 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
Expand All @@ -23,16 +20,12 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
1 change: 1 addition & 0 deletions internal/handlers/checkauth/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"sparkit/internal/utils/consts"
)

//go:generate mockgen -destination=./mocks/mock_SessionService.go -package=checkauth_mocks . SessionService
type SessionService interface {
CheckSession(ctx context.Context, sessionID string) error
}
Expand Down
94 changes: 94 additions & 0 deletions internal/handlers/checkauth/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package checkauth

import (
"errors"
"net/http"
"net/http/httptest"
"testing"

"github.com/golang/mock/gomock"
checkauth_mocks "sparkit/internal/handlers/checkauth/mocks"
"sparkit/internal/utils/consts"
)

func TestCheckAuthHandler(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

tests := []struct {
name string
method string
cookieValue string
checkSessionError error
expectedStatus int
expectedResponse string
}{
{
name: "successful session check",
method: http.MethodGet,
cookieValue: "valid-session-id",
expectedStatus: http.StatusOK,
expectedResponse: "ok",
checkSessionError: nil,
},
{
name: "wrong method",
method: http.MethodPost,
expectedStatus: http.StatusMethodNotAllowed,
expectedResponse: "method is not allowed\n",
},
{
name: "session cookie not found",
method: http.MethodGet,
expectedStatus: http.StatusUnauthorized,
expectedResponse: "session not found\n",
},
{
name: "invalid session",
method: http.MethodGet,
cookieValue: "invalid-session-id",
expectedStatus: http.StatusUnauthorized,
expectedResponse: "session is not valid\n",
checkSessionError: errors.New("invalid session"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
service := checkauth_mocks.NewMockSessionService(mockCtrl)
handler := NewHandler(service)

if tt.method == http.MethodGet && tt.cookieValue != "" {
req := httptest.NewRequest(tt.method, "/checkauth", nil)
req.AddCookie(&http.Cookie{Name: consts.SessionCookie, Value: tt.cookieValue})
w := httptest.NewRecorder()
if tt.checkSessionError != nil {
service.EXPECT().CheckSession(gomock.Any(), tt.cookieValue).Return(tt.checkSessionError).Times(1)
} else {
service.EXPECT().CheckSession(gomock.Any(), tt.cookieValue).Return(nil).Times(1)
}
handler.Handle(w, req)

if w.Code != tt.expectedStatus {
t.Errorf("handler returned wrong status code: got %v want %v", w.Code, tt.expectedStatus)
}

if w.Body.String() != tt.expectedResponse {
t.Errorf("handler returned unexpected body: got %v want %v", w.Body.String(), tt.expectedResponse)
}
} else {
req := httptest.NewRequest(tt.method, "/checkauth", nil)
w := httptest.NewRecorder()
handler.Handle(w, req)

if w.Code != tt.expectedStatus {
t.Errorf("handler returned wrong status code: got %v want %v", w.Code, tt.expectedStatus)
}

if w.Body.String() != tt.expectedResponse {
t.Errorf("handler returned unexpected body: got %v want %v", w.Body.String(), tt.expectedResponse)
}
}
})
}
}
49 changes: 49 additions & 0 deletions internal/handlers/checkauth/mocks/mock_SessionService.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions internal/handlers/getuserlist/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"sparkit/internal/models"
)

//go:generate mockgen -destination=./mocks/mock_UserUsecase.go -package=getuserlist_mocks . UserUsecase

type UserUsecase interface {
GetUserList(ctx context.Context) ([]models.User, error)
}
Expand Down
Loading