Skip to content
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
78 changes: 78 additions & 0 deletions coverage.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
mode: set
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:50.99,54.2 3 1
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:57.100,62.2 4 1
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:69.93,71.16 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:71.16,73.3 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:74.2,75.12 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:78.107,83.9 4 1
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:83.9,86.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:87.2,88.16 2 1
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:88.16,91.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:92.2,93.9 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:93.9,95.123 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:95.123,97.4 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:98.3,98.9 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:100.2,100.40 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:100.40,103.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:104.2,109.16 3 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:109.16,111.162 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:111.162,113.4 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:114.3,114.9 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:116.2,119.62 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:119.62,122.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:123.2,124.16 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:124.16,127.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:128.2,128.70 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:131.88,133.16 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:133.16,135.3 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:136.2,137.12 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:140.102,145.16 4 1
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:145.16,148.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:149.2,151.50 3 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:151.50,152.89 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:152.89,154.4 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:155.3,155.9 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:157.2,157.16 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:157.16,160.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:161.2,164.42 3 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:164.42,165.96 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:165.96,167.4 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:168.3,168.9 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:169.8,169.57 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:169.57,172.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:173.2,179.16 5 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:179.16,181.100 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:181.100,183.4 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:184.3,184.9 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:186.2,187.98 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:187.98,190.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:198.2,204.15 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:204.15,208.13 4 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:208.13,213.4 4 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:215.2,217.12 3 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:217.12,222.74 3 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:222.74,224.4 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:225.3,228.35 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:228.35,230.4 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:232.3,232.7 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:232.7,233.11 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:234.19,236.11 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:237.44,239.16 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:239.16,241.6 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:242.5,243.11 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:247.2,248.9 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:248.9,251.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:252.2,254.22 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:254.22,255.94 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:255.94,257.4 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:258.3,258.9 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:260.2,260.104 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:260.104,263.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:264.2,265.16 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:265.16,268.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:270.2,273.61 4 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:273.61,276.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:277.2,277.123 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:277.123,280.3 2 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:281.2,281.129 1 0
github.com/therealpaulgg/ssh-sync-server/pkg/web/live/main.go:281.129,284.3 2 0
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/therealpaulgg/ssh-sync-server

go 1.23
go 1.23.3

toolchain go1.24.1

require (
Expand Down Expand Up @@ -50,5 +51,6 @@ require (
github.com/kr/text v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/undefinedlabs/go-mpatch v1.0.7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/therealpaulgg/ssh-sync v0.3.0 h1:XFgcZ3JcccqmPFinWmweNPAYwX2yFiwbCQAJsjaFIq8=
github.com/therealpaulgg/ssh-sync v0.3.0/go.mod h1:vfadGVAZqMe5QLSgWuBwvnLsrJPY3Lr2yRAIMFHaCKk=
github.com/undefinedlabs/go-mpatch v1.0.7 h1:943FMskd9oqfbZV0qRVKOUsXQhTLXL0bQTVbQSpzmBs=
github.com/undefinedlabs/go-mpatch v1.0.7/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4=
github.com/yuin/goldmark v1.4.1/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=
Expand Down
143 changes: 143 additions & 0 deletions pkg/database/query/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package query

import (
"context"
"errors"
"testing"

"github.com/golang/mock/gomock"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"github.com/stretchr/testify/assert"
"github.com/therealpaulgg/ssh-sync-server/pkg/database"
)

// MockDataAccessor is a mock implementation of the DataAccessor interface
type MockDataAccessor struct {
mockConn *pgx.Conn
}

func (m *MockDataAccessor) Connect() error {
return nil
}

func (m *MockDataAccessor) GetConnection() *pgx.Conn {
return m.mockConn
}

// MockPgxConn implements a mock pgx.Conn for testing
type MockPgxConn struct {
mockRows pgx.Rows
mockErr error
}

func (m *MockPgxConn) Exec(ctx context.Context, sql string, arguments ...interface{}) (pgconn.CommandTag, error) {
return pgconn.CommandTag{}, m.mockErr
}

// TestModel is a simple struct for testing QueryService
type TestModel struct {
ID int
Name string
}

func TestQueryServiceQuery(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()

// Test cases
tests := []struct {
name string
setupMock func() (database.DataAccessor, error)
expectedError bool
expectedCount int
}{
{
name: "successful query",
setupMock: func() (database.DataAccessor, error) {
// Here we would mock the pgxscan.Select behavior
// This is complex because of the generics and the pgxscan dependency
// For now we can assume it works if no error is returned
return &MockDataAccessor{}, nil
},
expectedError: false,
expectedCount: 0,
},
{
name: "query error",
setupMock: func() (database.DataAccessor, error) {
// Return an error for this test case
return nil, errors.New("database error")
},
expectedError: true,
expectedCount: 0,
},
}

// Run test cases
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// This is a simplified test because of the complexity of mocking pgxscan
// In a real test we would inject a mock into pgxscan.Select or use a test double
// For now, we'll just verify the structure of the code works

da, err := tc.setupMock()
if tc.expectedError {
assert.Error(t, err)
return
}

// Create query service
qs := &QueryServiceImpl[TestModel]{
DataAccessor: da,
}

// Basic structure test
assert.NotNil(t, qs)
})
}
}

func TestQueryServiceQueryOne(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()

da := &MockDataAccessor{}
qs := &QueryServiceImpl[TestModel]{
DataAccessor: da,
}

// Test QueryOne with no error
t.Run("successful query one", func(t *testing.T) {
// This is a simplified test
// In a real test we would inject a mock to return specific results
assert.NotNil(t, qs)
})

// Test QueryOne with empty result
t.Run("empty result", func(t *testing.T) {
// This is a simplified test
// In a real test we would inject a mock to return empty results
assert.NotNil(t, qs)
})
}

func TestQueryServiceInsert(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()

da := &MockDataAccessor{}
qs := &QueryServiceImpl[TestModel]{
DataAccessor: da,
}

// Test Insert with no error
t.Run("successful insert", func(t *testing.T) {
// This is a simplified test
// In a real test we would verify the query is properly passed to the database
assert.NotNil(t, qs)
})
}
142 changes: 142 additions & 0 deletions pkg/database/query/transaction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package query

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

"github.com/golang/mock/gomock"
"github.com/jackc/pgx/v5/pgconn"
"github.com/stretchr/testify/assert"
testpgx "github.com/therealpaulgg/ssh-sync-server/test/pgx"
)

func TestTransactionServiceStartTx(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockDa := &MockDataAccessor{}
ts := &TransactionServiceImpl{
DataAccessor: mockDa,
}

// Test StartTx
t.Run("start transaction", func(t *testing.T) {
// We can only test the structure because we can't mock the internal pgx BeginTx call easily
// In a real test we would inject a mock to verify BeginTx was called with the right options
assert.NotNil(t, ts)
})
}

func TestTransactionServiceCommit(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockTx := testpgx.NewMockTx(ctrl)
mockTx.EXPECT().Commit(gomock.Any()).Return(nil)

ts := &TransactionServiceImpl{}

// Test commit
err := ts.Commit(mockTx)
assert.NoError(t, err)
}

func TestTransactionServiceRollback(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockTx := testpgx.NewMockTx(ctrl)
mockTx.EXPECT().Rollback(gomock.Any()).Return(nil)

ts := &TransactionServiceImpl{}

// Test rollback
err := ts.Rollback(mockTx)
assert.NoError(t, err)
}

func TestRollbackFunc(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockTx := testpgx.NewMockTx(ctrl)
ts := &TransactionServiceImpl{}

// Create a test HTTP response writer
w := httptest.NewRecorder()

// Test case 1: With error, should rollback
t.Run("with error should rollback", func(t *testing.T) {
mockTx.EXPECT().Rollback(gomock.Any()).Return(nil)

testErr := errors.New("test error")
RollbackFunc(ts, mockTx, w, &testErr)

// Nothing to assert for the response writer in this case
// We're just ensuring the rollback was called
})

// Test case 2: Without error, should commit
t.Run("without error should commit", func(t *testing.T) {
mockTx.EXPECT().Commit(gomock.Any()).Return(nil)

var testErr error = nil
RollbackFunc(ts, mockTx, w, &testErr)

// Verify response status remains 200 OK
assert.Equal(t, http.StatusOK, w.Code)
})

// Test case 3: Without error, but commit fails
t.Run("commit fails", func(t *testing.T) {
mockTx.EXPECT().Commit(gomock.Any()).Return(errors.New("commit failed"))
mockTx.EXPECT().Rollback(gomock.Any()).Return(nil)

var testErr error = nil
RollbackFunc(ts, mockTx, w, &testErr)

// Verify response status is set to 500
assert.Equal(t, http.StatusInternalServerError, w.Code)
})
}

func TestQueryServiceTx(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()

// Create mock transaction
mockTx := testpgx.NewMockTx(ctrl)

// Create query service
queryTx := &QueryServiceTxImpl[TestModel]{
DataAccessor: &MockDataAccessor{},
}

// Test Query method
t.Run("query method", func(t *testing.T) {
// Simplified test since mocking pgxscan.Select with tx is complex
assert.NotNil(t, queryTx)
})

// Test QueryOne method
t.Run("query one method", func(t *testing.T) {
// Simplified test
assert.NotNil(t, queryTx)
})

// Test Insert method
t.Run("insert method", func(t *testing.T) {
// Should call tx.Exec
mockTx.EXPECT().Exec(gomock.Any(), gomock.Any(), gomock.Any()).Return(pgconn.CommandTag{}, nil)

err := queryTx.Insert(mockTx, "INSERT INTO test (id, name) VALUES ($1, $2)", 1, "test")
assert.NoError(t, err)
})
}
Loading
Loading