Skip to content

Commit 9d22953

Browse files
committed
add more testing
1 parent 82d6398 commit 9d22953

File tree

8 files changed

+247
-55
lines changed

8 files changed

+247
-55
lines changed

api-products/api/service/product_service_impl_test.go

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -111,51 +111,3 @@ func TestPoductService_GetByID(t *testing.T) {
111111
assert.Equal(t, response.ProductResponse{}, product, "Expected product to be empty")
112112
})
113113
}
114-
115-
// func TestProductService_UpdateData(t *testing.T) {
116-
// mockRepo := new(MockProductRepository)
117-
// mockScraper := new(MockScraper)
118-
// productService := NewProductServiceImpl(mockRepo, mockScraper)
119-
120-
// mockRepo.On("DeleteAll").Return(nil)
121-
122-
// utils.Categories = []utils.CategoryInfo{
123-
// {MaxPage: 10, Category: "bebidas-alcoholicas"},
124-
// {MaxPage: 5, Category: "alimentos-basicos"},
125-
// }
126-
127-
// mockScraper.On("ScrapeData", "cugat.cl/categoria-producto", 10, "bebidas-alcoholicas").Return([]models.Product{
128-
// {
129-
// Name: "Product 1",
130-
// Category: "bebidas-alcoholicas",
131-
// OriginalPrice: 100,
132-
// DiscountedPrice: 90,
133-
// },
134-
// }, nil)
135-
136-
// mockScraper.On("ScrapeData", "cugat.cl/categoria-producto", 5, "alimentos-basicos").Return([]models.Product{
137-
// {
138-
// Name: "Product 2",
139-
// Category: "alimentos-basicos",
140-
// OriginalPrice: 200,
141-
// DiscountedPrice: 180,
142-
// },
143-
// }, nil)
144-
145-
// mockRepo.On("Create", mock.MatchedBy(func(product models.Product) bool {
146-
// return product.Name == "Product 1" && product.Category == "bebidas-alcoholicas" ||
147-
// product.Name == "Product 2" && product.Category == "alimentos-basicos"
148-
// })).Return(models.Product{}, nil)
149-
150-
// updateDataRequest := request.UpdateDataRequest{
151-
// UpdateData: true,
152-
// }
153-
154-
// success, err := productService.UpdateData(updateDataRequest)
155-
156-
// assert.NoError(t, err, "Expected no error, UpdateData() returned an error")
157-
// assert.True(t, success, "Expected success to be true")
158-
159-
// mockRepo.AssertExpectations(t)
160-
// mockScraper.AssertExpectations(t)
161-
// }

scraper/src/repository/scraper_repository_impl.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ func (s *ScraperRepositoryImpl) DeleteAll() error {
6969
return nil
7070
}
7171

72+
var deleteErrors []error
73+
7274
// Iterar sobre los elementos escaneados y eliminarlos
7375
for _, item := range result.Items {
7476
deleteInput := &dynamodb.DeleteItemInput{
@@ -80,11 +82,17 @@ func (s *ScraperRepositoryImpl) DeleteAll() error {
8082

8183
_, err := s.db.DeleteItem(deleteInput)
8284
if err != nil {
83-
logrus.WithError(err).Error("[ProductRepositoryImpl.DeleteAll] error deleting products")
84-
return errors.New("error deleting products")
85+
logrus.WithError(err).Error("[ProductRepositoryImpl.DeleteAll] error deleting product")
86+
deleteErrors = append(deleteErrors, err)
8587
}
8688
}
8789

90+
// Si hubo errores, retornarlos combinados
91+
if len(deleteErrors) > 0 {
92+
logrus.WithError(err).Error("[ProductRepositoryImpl.DeleteAll] one or more errors occurred while deleting products")
93+
return errors.New("one or more errors occurred while deleting products")
94+
}
95+
8896
return nil
8997
}
9098

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package repository
2+
3+
import (
4+
"testing"
5+
6+
"github.com/aws/aws-sdk-go/aws"
7+
"github.com/aws/aws-sdk-go/service/dynamodb"
8+
"github.com/dieg0code/shared/mocks"
9+
"github.com/dieg0code/shared/models"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/mock"
12+
)
13+
14+
func TestScraperRepository_Create(t *testing.T) {
15+
t.Run("Create_Success", func(t *testing.T) {
16+
mockDB := new(mocks.MockDynamoDB)
17+
repo := NewScraperRepositoryImpl(mockDB, "test-table")
18+
19+
product := models.Product{
20+
ProductID: "test-id",
21+
Name: "Test Product",
22+
Category: "Test Category",
23+
OriginalPrice: 100,
24+
DiscountedPrice: 90,
25+
LastUpdated: "02-02-1996",
26+
}
27+
28+
mockDB.On("PutItem", mock.Anything).Return(&dynamodb.PutItemOutput{}, nil)
29+
30+
result, err := repo.Create(product)
31+
assert.NoError(t, err, "Expected no error creating product")
32+
33+
assert.Equal(t, product, result, "Expected product to be the same")
34+
35+
mockDB.AssertExpectations(t)
36+
})
37+
38+
t.Run("Create_Error", func(t *testing.T) {
39+
mockDB := new(mocks.MockDynamoDB)
40+
repo := NewScraperRepositoryImpl(mockDB, "test-table")
41+
42+
product := models.Product{
43+
ProductID: "test-id",
44+
Name: "Test Product",
45+
Category: "Test Category",
46+
OriginalPrice: 100,
47+
DiscountedPrice: 90,
48+
LastUpdated: "02-02-1996",
49+
}
50+
51+
mockDB.On("PutItem", mock.Anything).Return(&dynamodb.PutItemOutput{}, assert.AnError)
52+
53+
result, err := repo.Create(product)
54+
assert.Error(t, err, "Expected error creating product")
55+
assert.Equal(t, models.Product{}, result, "Expected empty product")
56+
57+
mockDB.AssertExpectations(t)
58+
})
59+
}
60+
61+
func TestScraperRepository_DeleteAll(t *testing.T) {
62+
t.Run("DeleteAll_Success", func(t *testing.T) {
63+
mockDB := new(mocks.MockDynamoDB)
64+
repo := NewScraperRepositoryImpl(mockDB, "test-table")
65+
66+
// Mock scan result with items
67+
mockScanOutput := &dynamodb.ScanOutput{
68+
Items: []map[string]*dynamodb.AttributeValue{
69+
{"ProductID": {S: aws.String("1")}},
70+
{"ProductID": {S: aws.String("2")}},
71+
},
72+
}
73+
74+
mockDB.On("Scan", mock.Anything).Return(mockScanOutput, nil)
75+
mockDB.On("DeleteItem", mock.Anything).Return(&dynamodb.DeleteItemOutput{}, nil)
76+
77+
err := repo.DeleteAll()
78+
assert.NoError(t, err, "Expected no error deleting all products")
79+
80+
// Ensure DeleteItem is called for each item
81+
mockDB.AssertNumberOfCalls(t, "DeleteItem", len(mockScanOutput.Items))
82+
mockDB.AssertExpectations(t)
83+
})
84+
85+
t.Run("DeleteAll_NoProducts", func(t *testing.T) {
86+
mockDB := new(mocks.MockDynamoDB)
87+
repo := NewScraperRepositoryImpl(mockDB, "test-table")
88+
89+
// Mock scan result with no items
90+
mockScanOutput := &dynamodb.ScanOutput{
91+
Items: []map[string]*dynamodb.AttributeValue{},
92+
}
93+
94+
mockDB.On("Scan", mock.Anything).Return(mockScanOutput, nil)
95+
96+
err := repo.DeleteAll()
97+
assert.NoError(t, err, "Expected no error deleting all products")
98+
99+
mockDB.AssertExpectations(t)
100+
})
101+
102+
t.Run("DeleteAll_ErrorScanning", func(t *testing.T) {
103+
mockDB := new(mocks.MockDynamoDB)
104+
repo := NewScraperRepositoryImpl(mockDB, "test-table")
105+
106+
mockDB.On("Scan", mock.Anything).Return(&dynamodb.ScanOutput{}, assert.AnError)
107+
108+
err := repo.DeleteAll()
109+
assert.Error(t, err, "Expected error deleting all products")
110+
111+
mockDB.AssertExpectations(t)
112+
})
113+
114+
t.Run("DeleteAll_ErrorDeleting", func(t *testing.T) {
115+
mockDB := new(mocks.MockDynamoDB)
116+
repo := NewScraperRepositoryImpl(mockDB, "test-table")
117+
118+
// Mock scan result with items
119+
mockScanOutput := &dynamodb.ScanOutput{
120+
Items: []map[string]*dynamodb.AttributeValue{
121+
{"ProductID": {S: aws.String("1")}},
122+
{"ProductID": {S: aws.String("2")}},
123+
},
124+
}
125+
126+
mockDB.On("Scan", mock.Anything).Return(mockScanOutput, nil)
127+
mockDB.On("DeleteItem", mock.Anything).Return(&dynamodb.DeleteItemOutput{}, assert.AnError).Twice() // Se esperan dos llamadas
128+
129+
err := repo.DeleteAll()
130+
assert.Error(t, err, "Expected error deleting all products")
131+
132+
mockDB.AssertExpectations(t)
133+
})
134+
135+
}

scraper/src/scraper/scraper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ package scraper
33
import "github.com/dieg0code/shared/models"
44

55
type Scraper interface {
6-
ScrapeData(baseURL string, maxPage int, category string) ([]models.Product, error)
6+
ScrapeData(protocol string, baseURL string, maxPage int, category string) ([]models.Product, error)
77
CleanPrice(price string) ([]int, error)
88
}

scraper/src/scraper/scraper_impl.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,11 @@ func (s *ScraperImpl) CleanPrice(price string) ([]int, error) {
4242
prices = append(prices, price)
4343
}
4444

45-
// Retornar los precios como un slice de int
4645
return prices, nil
4746
}
4847

4948
// ScrapeData implements Scraper.
50-
func (s *ScraperImpl) ScrapeData(baseURL string, maxPage int, category string) ([]models.Product, error) {
49+
func (s *ScraperImpl) ScrapeData(protocol string, baseURL string, maxPage int, category string) ([]models.Product, error) {
5150
var products []models.Product
5251

5352
s.Collector.OnHTML(".product-small.box", func(e *colly.HTMLElement) {
@@ -89,7 +88,7 @@ func (s *ScraperImpl) ScrapeData(baseURL string, maxPage int, category string) (
8988
})
9089

9190
for i := 1; i <= maxPage; i++ {
92-
url := fmt.Sprintf("https://%s/%s/page/%d/", baseURL, category, i)
91+
url := fmt.Sprintf("%s://%s/%s/page/%d/", protocol, baseURL, category, i)
9392
err := s.Collector.Visit(url)
9493
if err != nil {
9594
logrus.WithError(err).Errorf("Failed to visit page %d at URL %s", i, url)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package scraper
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"strings"
7+
"testing"
8+
9+
"github.com/dieg0code/shared/models"
10+
"github.com/gocolly/colly"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestCleanPrice(t *testing.T) {
15+
scraper := &ScraperImpl{}
16+
17+
tests := []struct {
18+
input string
19+
expected []int
20+
expectedError bool
21+
}{
22+
{"123", []int{123}, false},
23+
{"1.234", []int{1234}, false},
24+
{"12.345.678", []int{12345678}, false},
25+
{"invalid price", nil, true},
26+
{"", nil, true},
27+
}
28+
29+
for _, test := range tests {
30+
t.Run(test.input, func(t *testing.T) {
31+
prices, err := scraper.CleanPrice(test.input)
32+
33+
if test.expectedError {
34+
assert.Error(t, err, "Expected error cleaning price")
35+
assert.Nil(t, prices, "Expected nil prices")
36+
} else {
37+
assert.NoError(t, err, "Expected no error cleaning price")
38+
assert.Equal(t, test.expected, prices, "Expected cleaned prices to match")
39+
}
40+
})
41+
}
42+
}
43+
44+
func TestScrapeData(t *testing.T) {
45+
t.Run("Scrape_Success", func(t *testing.T) {
46+
// Crear un servidor de prueba que devuelva un HTML estático
47+
ts := createTestServer()
48+
defer ts.Close()
49+
50+
// Crear un nuevo scraper
51+
collector := colly.NewCollector()
52+
scraper := NewScraperImpl(collector)
53+
54+
baseURL := strings.TrimPrefix(ts.URL, "http://")
55+
56+
// Usa http:// para el servidor de prueba
57+
products, err := scraper.ScrapeData("http", baseURL, 1, "category")
58+
59+
assert.NoError(t, err, "Expected no error scraping data")
60+
assert.Len(t, products, 1, "Expected 1 product")
61+
62+
expectedProduct := models.Product{
63+
Name: "Test Product",
64+
Category: "category",
65+
OriginalPrice: 123456,
66+
DiscountedPrice: 7890,
67+
}
68+
69+
assert.Equal(t, expectedProduct, products[0], "Expected product to match")
70+
})
71+
}
72+
73+
// TestServer to simualte a real page to scrape
74+
func createTestServer() *httptest.Server {
75+
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
76+
w.Header().Set("Content-Type", "text/html")
77+
w.Write([]byte(`
78+
<div class="product-small box">
79+
<div class="name product-title"><a href="#">Test Product</a></div>
80+
<div class="category">category</div>
81+
<div class="price">
82+
<del><span class="woocommerce-Price-amount amount">123.456</span></del>
83+
<ins><span class="woocommerce-Price-amount amount">7.890</span></ins>
84+
</div>
85+
</div>
86+
`))
87+
})
88+
89+
ts := httptest.NewServer(handler)
90+
return ts
91+
}

scraper/src/service/scraper_service_impl.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ func (s *ScraperServiceImpl) GetProducts() (bool, error) {
2727

2828
logrus.Info("[ProductServiceImpl.UpdateData] Scraping data started")
2929

30+
protocol := "https"
31+
3032
for _, categoryInfo := range scraper.Categories {
31-
products, err := s.Scraper.ScrapeData(baseURL, categoryInfo.MaxPage, categoryInfo.Category)
33+
products, err := s.Scraper.ScrapeData(protocol, baseURL, categoryInfo.MaxPage, categoryInfo.Category)
3234
if err != nil {
3335
logrus.WithError(err).Error("[ProductServiceImpl.UpdateData] Error scraping data")
3436
return false, err

shared/mocks/mock_dynamodb.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,8 @@ func (m *MockDynamoDB) GetItem(input *dynamodb.GetItemInput) (*dynamodb.GetItemO
3030
args := m.Called(input)
3131
return args.Get(0).(*dynamodb.GetItemOutput), args.Error(1)
3232
}
33+
34+
func (m *MockDynamoDB) DeleteItem(input *dynamodb.DeleteItemInput) (*dynamodb.DeleteItemOutput, error) {
35+
args := m.Called(input)
36+
return args.Get(0).(*dynamodb.DeleteItemOutput), args.Error(1)
37+
}

0 commit comments

Comments
 (0)