turash/bugulma/backend/internal/handler/resource_flow_handler_test.go
Damir Mukimov 13e814acda
Some checks failed
CI/CD Pipeline / backend-build (push) Blocked by required conditions
CI/CD Pipeline / e2e-test (push) Blocked by required conditions
CI/CD Pipeline / frontend-lint (push) Successful in 1m40s
CI/CD Pipeline / frontend-build (push) Failing after 36s
CI/CD Pipeline / backend-lint (push) Has been cancelled
Update test setup to use SetupTestDBWithTestcontainersForGinkgo for improved compatibility
- Replace instances of SetupTestDBWithTestcontainers with SetupTestDBWithTestcontainersForGinkgo in test files for better integration with Ginkgo
- Ensure consistent test database setup across various handlers to enhance test isolation and reliability
2025-12-26 15:46:28 +01:00

263 lines
10 KiB
Go

package handler_test
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"bugulma/backend/internal/testutils"
"github.com/gin-gonic/gin"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"gorm.io/datatypes"
"gorm.io/gorm"
"bugulma/backend/internal/domain"
"bugulma/backend/internal/handler"
"bugulma/backend/internal/repository"
"bugulma/backend/internal/service"
)
var _ = Describe("ResourceFlowHandler", func() {
var (
resourceHandler *handler.ResourceFlowHandler
resourceService *service.ResourceFlowService
resourceRepo domain.ResourceFlowRepository
organizationRepo domain.OrganizationRepository
siteRepo domain.SiteRepository
router *gin.Engine
db *gorm.DB
)
BeforeEach(func() {
gin.SetMode(gin.TestMode)
// Setup PostgreSQL test database using pgtestdb
db = testutils.SetupTestDBWithTestcontainersForGinkgo(GinkgoT())
resourceRepo = repository.NewResourceFlowRepository(db)
organizationRepo = repository.NewOrganizationRepository(db)
siteRepo = repository.NewSiteRepository(db)
resourceService = service.NewResourceFlowService(resourceRepo, nil)
resourceHandler = handler.NewResourceFlowHandler(resourceService)
router = gin.New()
router.POST("/resources", resourceHandler.Create)
router.GET("/resources/:id", resourceHandler.GetByID)
router.PUT("/resources/:id", resourceHandler.Update)
router.GET("/sites/:siteId/resources", resourceHandler.GetBySite)
router.GET("/organizations/:organizationId/resources", resourceHandler.GetByOrganization)
router.DELETE("/resources/:id", resourceHandler.Delete)
})
AfterEach(func() {
// pgtestdb automatically cleans up the database after each test
})
Describe("Create", func() {
It("should create a resource flow", func() {
// Create organization and site first (required for foreign keys)
org := &domain.Organization{ID: "org-1", Name: "Org 1"}
site := &domain.Site{ID: "site-1", Name: "Site 1", Latitude: 52.52, Longitude: 13.405, OwnerOrganizationID: "org-1"}
Expect(organizationRepo.Create(context.TODO(), org)).To(Succeed())
Expect(siteRepo.Create(context.TODO(), site)).To(Succeed())
reqBody := handler.CreateResourceFlowRequest{
OrganizationID: "org-1",
SiteID: "site-1",
Direction: domain.DirectionOutput,
Type: domain.TypeHeat,
Quantity: domain.Quantity{
Amount: 100,
Unit: "kWh",
},
}
body, _ := json.Marshal(reqBody)
req, _ := http.NewRequest("POST", "/resources", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expect(w.Code).To(Equal(http.StatusCreated))
var resp domain.ResourceFlow
err := json.Unmarshal(w.Body.Bytes(), &resp)
Expect(err).NotTo(HaveOccurred())
Expect(resp.OrganizationID).To(Equal("org-1"))
Expect(resp.ID).NotTo(BeEmpty())
})
})
Describe("GetByID", func() {
It("should return resource flow by ID", func() {
// Create organization and site first
org := &domain.Organization{ID: "org-1", Name: "Org 1"}
site := &domain.Site{ID: "site-1", Name: "Site 1", Latitude: 52.52, Longitude: 13.405, OwnerOrganizationID: "org-1"}
Expect(organizationRepo.Create(context.TODO(), org)).To(Succeed())
Expect(siteRepo.Create(context.TODO(), site)).To(Succeed())
rf := &domain.ResourceFlow{
ID: "rf-1",
OrganizationID: "org-1",
SiteID: "site-1",
Direction: domain.DirectionOutput,
Type: domain.TypeHeat,
Quantity: datatypes.JSON(`{"amount": 100, "unit": "kWh"}`),
}
Expect(resourceRepo.Create(context.TODO(), rf)).To(Succeed())
req, _ := http.NewRequest("GET", "/resources/rf-1", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expect(w.Code).To(Equal(http.StatusOK))
var resp domain.ResourceFlow
err := json.Unmarshal(w.Body.Bytes(), &resp)
Expect(err).NotTo(HaveOccurred())
Expect(resp.ID).To(Equal("rf-1"))
})
})
Describe("GetBySite", func() {
It("should return resources for a site", func() {
// Create organizations and sites first
org1 := &domain.Organization{ID: "org-1", Name: "Org 1"}
org2 := &domain.Organization{ID: "org-2", Name: "Org 2"}
site1 := &domain.Site{ID: "site-1", Name: "Site 1", Latitude: 52.52, Longitude: 13.405, OwnerOrganizationID: "org-1"}
site2 := &domain.Site{ID: "site-2", Name: "Site 2", Latitude: 52.53, Longitude: 13.406, OwnerOrganizationID: "org-2"}
Expect(organizationRepo.Create(context.TODO(), org1)).To(Succeed())
Expect(organizationRepo.Create(context.TODO(), org2)).To(Succeed())
Expect(siteRepo.Create(context.TODO(), site1)).To(Succeed())
Expect(siteRepo.Create(context.TODO(), site2)).To(Succeed())
Expect(resourceRepo.Create(context.TODO(), &domain.ResourceFlow{ID: "rf-1", OrganizationID: "org-1", SiteID: "site-1", Direction: domain.DirectionOutput, Type: domain.TypeHeat, Quantity: datatypes.JSON(`{"amount": 100, "unit": "kWh"}`)})).To(Succeed())
Expect(resourceRepo.Create(context.TODO(), &domain.ResourceFlow{ID: "rf-2", OrganizationID: "org-1", SiteID: "site-1", Direction: domain.DirectionOutput, Type: domain.TypeWater, Quantity: datatypes.JSON(`{"amount": 50, "unit": "liters"}`)})).To(Succeed())
Expect(resourceRepo.Create(context.TODO(), &domain.ResourceFlow{ID: "rf-3", OrganizationID: "org-2", SiteID: "site-2", Direction: domain.DirectionOutput, Type: domain.TypeHeat, Quantity: datatypes.JSON(`{"amount": 200, "unit": "kWh"}`)})).To(Succeed())
req, _ := http.NewRequest("GET", "/sites/site-1/resources", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expect(w.Code).To(Equal(http.StatusOK))
var resp []domain.ResourceFlow
err := json.Unmarshal(w.Body.Bytes(), &resp)
Expect(err).NotTo(HaveOccurred())
Expect(resp).To(HaveLen(2))
})
})
Describe("Update", func() {
It("should update a resource flow", func() {
// Create organization and site first
org := &domain.Organization{ID: "org-1", Name: "Org 1"}
site := &domain.Site{ID: "site-1", Name: "Site 1", Latitude: 52.52, Longitude: 13.405, OwnerOrganizationID: "org-1"}
Expect(organizationRepo.Create(context.TODO(), org)).To(Succeed())
Expect(siteRepo.Create(context.TODO(), site)).To(Succeed())
rf := &domain.ResourceFlow{
ID: "rf-1",
OrganizationID: "org-1",
SiteID: "site-1",
Direction: domain.DirectionOutput,
Type: domain.TypeHeat,
Quantity: datatypes.JSON(`{"amount": 100, "unit": "kWh"}`),
}
Expect(resourceRepo.Create(context.TODO(), rf)).To(Succeed())
updateReq := handler.CreateResourceFlowRequest{
OrganizationID: "org-1",
SiteID: "site-1",
Direction: domain.DirectionOutput,
Type: domain.TypeHeat,
Quantity: domain.Quantity{
Amount: 150,
Unit: "kWh",
},
}
jsonData, _ := json.Marshal(updateReq)
req, _ := http.NewRequest("PUT", "/resources/rf-1", bytes.NewBuffer(jsonData))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expect(w.Code).To(Equal(http.StatusOK))
// Verify update
updated, err := resourceRepo.GetByID(context.Background(), "rf-1")
Expect(err).NotTo(HaveOccurred())
Expect(updated.Quantity).NotTo(BeNil())
})
})
Describe("GetByOrganization", func() {
It("should return resources for an organization", func() {
// Create organizations and sites first
org1 := &domain.Organization{ID: "org-1", Name: "Org 1"}
org2 := &domain.Organization{ID: "org-2", Name: "Org 2"}
site1 := &domain.Site{ID: "site-1", Name: "Site 1", Latitude: 52.52, Longitude: 13.405, OwnerOrganizationID: "org-1"}
site2 := &domain.Site{ID: "site-2", Name: "Site 2", Latitude: 52.53, Longitude: 13.406, OwnerOrganizationID: "org-1"}
Expect(organizationRepo.Create(context.TODO(), org1)).To(Succeed())
Expect(organizationRepo.Create(context.TODO(), org2)).To(Succeed())
Expect(siteRepo.Create(context.TODO(), site1)).To(Succeed())
Expect(siteRepo.Create(context.TODO(), site2)).To(Succeed())
Expect(resourceRepo.Create(context.TODO(), &domain.ResourceFlow{ID: "rf-1", OrganizationID: "org-1", SiteID: "site-1", Direction: domain.DirectionOutput, Type: domain.TypeHeat, Quantity: datatypes.JSON(`{"amount": 100, "unit": "kWh"}`)})).To(Succeed())
Expect(resourceRepo.Create(context.TODO(), &domain.ResourceFlow{ID: "rf-2", OrganizationID: "org-1", SiteID: "site-2", Direction: domain.DirectionOutput, Type: domain.TypeWater, Quantity: datatypes.JSON(`{"amount": 50, "unit": "liters"}`)})).To(Succeed())
Expect(resourceRepo.Create(context.TODO(), &domain.ResourceFlow{ID: "rf-3", OrganizationID: "org-2", SiteID: "site-1", Direction: domain.DirectionOutput, Type: domain.TypeHeat, Quantity: datatypes.JSON(`{"amount": 200, "unit": "kWh"}`)})).To(Succeed())
req, _ := http.NewRequest("GET", "/organizations/org-1/resources", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expect(w.Code).To(Equal(http.StatusOK))
var resp []domain.ResourceFlow
err := json.Unmarshal(w.Body.Bytes(), &resp)
Expect(err).NotTo(HaveOccurred())
Expect(resp).To(HaveLen(2))
})
})
Describe("Delete", func() {
It("should delete a resource flow", func() {
// Create organization and site first
org := &domain.Organization{ID: "org-1", Name: "Org 1"}
site := &domain.Site{ID: "site-1", Name: "Site 1", Latitude: 52.52, Longitude: 13.405, OwnerOrganizationID: "org-1"}
Expect(organizationRepo.Create(context.TODO(), org)).To(Succeed())
Expect(siteRepo.Create(context.TODO(), site)).To(Succeed())
rf := &domain.ResourceFlow{
ID: "rf-1",
OrganizationID: "org-1",
SiteID: "site-1",
Direction: domain.DirectionOutput,
Type: domain.TypeHeat,
Quantity: datatypes.JSON(`{"amount": 100, "unit": "kWh"}`),
}
Expect(resourceRepo.Create(context.TODO(), rf)).To(Succeed())
req, _ := http.NewRequest("DELETE", "/resources/rf-1", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
Expect(w.Code).To(Equal(http.StatusNoContent))
// Verify it's gone
_, err := resourceRepo.GetByID(context.Background(), "rf-1")
Expect(err).To(HaveOccurred())
})
})
})