hash-of-wisdom/internal/service/wisdom_test.go

187 lines
4.3 KiB
Go
Raw Normal View History

2025-08-22 16:38:27 +03:00
package service
import (
"context"
"testing"
"time"
"hash-of-wisdom/internal/pow/challenge"
"hash-of-wisdom/internal/quotes"
"hash-of-wisdom/internal/service/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestWisdomService_GenerateChallenge(t *testing.T) {
tests := []struct {
name string
resource string
wantErr error
}{
{
name: "valid resource",
resource: "quotes",
wantErr: nil,
},
{
name: "empty resource",
resource: "",
wantErr: ErrResourceRequired,
},
{
name: "unsupported resource",
resource: "invalid",
wantErr: ErrUnsupportedResource,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockGen := mocks.NewMockChallengeGenerator(t)
mockVer := mocks.NewMockChallengeVerifier(t)
mockQuote := mocks.NewMockQuoteService(t)
service := NewWisdomService(mockGen, mockVer, mockQuote)
if tt.wantErr == nil {
expectedChallenge := &challenge.Challenge{
Timestamp: time.Now().Unix(),
Difficulty: 4,
Resource: "quotes",
Random: []byte{0x01, 0x02, 0x03},
}
mockGen.EXPECT().GenerateChallenge().Return(expectedChallenge, nil).Once()
}
ctx := context.Background()
ch, err := service.GenerateChallenge(ctx, tt.resource)
if tt.wantErr != nil {
assert.ErrorIs(t, err, tt.wantErr)
assert.Nil(t, ch)
} else {
assert.NoError(t, err)
assert.NotNil(t, ch)
}
})
}
}
func TestWisdomService_VerifySolution(t *testing.T) {
tests := []struct {
name string
solution *challenge.Solution
wantErr error
setupMocks func(*mocks.MockChallengeVerifier)
}{
{
name: "nil solution",
solution: nil,
wantErr: ErrSolutionRequired,
setupMocks: func(mv *mocks.MockChallengeVerifier) {},
},
{
name: "invalid challenge",
solution: &challenge.Solution{
Challenge: challenge.Challenge{},
Nonce: 123,
},
wantErr: ErrInvalidChallenge,
setupMocks: func(mv *mocks.MockChallengeVerifier) {
mv.EXPECT().VerifyChallenge(mock.Anything).Return(challenge.ErrInvalidHMAC).Once()
},
},
{
name: "invalid solution",
solution: createInvalidSolution(t),
wantErr: ErrInvalidSolution,
setupMocks: func(mv *mocks.MockChallengeVerifier) {
mv.EXPECT().VerifyChallenge(mock.Anything).Return(nil).Once()
},
},
{
name: "valid solution",
solution: createValidSolution(t),
wantErr: nil,
setupMocks: func(mv *mocks.MockChallengeVerifier) {
mv.EXPECT().VerifyChallenge(mock.Anything).Return(nil).Once()
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockGen := mocks.NewMockChallengeGenerator(t)
mockVer := mocks.NewMockChallengeVerifier(t)
mockQuote := mocks.NewMockQuoteService(t)
tt.setupMocks(mockVer)
service := NewWisdomService(mockGen, mockVer, mockQuote)
ctx := context.Background()
err := service.VerifySolution(ctx, tt.solution)
if tt.wantErr != nil {
assert.ErrorIs(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
}
})
}
}
func TestWisdomService_GetQuote(t *testing.T) {
mockGen := mocks.NewMockChallengeGenerator(t)
mockVer := mocks.NewMockChallengeVerifier(t)
mockQuote := mocks.NewMockQuoteService(t)
expectedQuote := &quotes.Quote{
Text: "Test quote",
Author: "Test author",
}
mockQuote.EXPECT().GetRandomQuote(mock.Anything).Return(expectedQuote, nil).Once()
service := NewWisdomService(mockGen, mockVer, mockQuote)
ctx := context.Background()
quote, err := service.GetQuote(ctx)
assert.NoError(t, err)
assert.Equal(t, expectedQuote, quote)
}
func createValidSolution(t *testing.T) *challenge.Solution {
config := challenge.TestConfig()
ch := &challenge.Challenge{
Timestamp: time.Now().Unix(),
Difficulty: 0, // Difficulty 0 means any nonce works
Resource: "quotes",
Random: []byte{0x01, 0x02, 0x03},
}
ch.Sign(config.HMACSecret)
return &challenge.Solution{
Challenge: *ch,
Nonce: 0,
}
}
func createInvalidSolution(t *testing.T) *challenge.Solution {
config := challenge.TestConfig()
ch := &challenge.Challenge{
Timestamp: time.Now().Unix(),
Difficulty: 20, // High difficulty, nonce 999 won't work
Resource: "quotes",
Random: []byte{0x01, 0x02, 0x03},
}
ch.Sign(config.HMACSecret)
return &challenge.Solution{
Challenge: *ch,
Nonce: 999, // Wrong nonce for difficulty 20
}
}