From 07bd4d95a6391551a86b256acf6b5dd766e35ab6 Mon Sep 17 00:00:00 2001 From: Vargha Csongor Date: Sat, 19 Apr 2025 17:21:30 +0200 Subject: [PATCH] fix integration test to work, init integration tests --- apps/db-adapter/integration-tests/admin.go | 16 +++ .../payloads/create_person.json | 9 ++ .../create_person_with_invite_code.json | 12 ++ apps/db-adapter/integration-tests/person.go | 16 +++ .../person_and_relationship.go | 4 + .../integration-tests/person_family_tree.go | 7 ++ .../integration-tests/person_google.go | 114 ++++++++++++++++++ .../integration-tests/person_recipes.go | 4 + .../integration-tests/recipe_relationship.go | 9 ++ apps/db-adapter/integration-tests/recipes.go | 10 ++ .../integration-tests/relationship.go | 13 ++ apps/db-adapter/internal/api/person_google.go | 6 +- .../internal/memgraph/init_database.go | 9 +- .../internal/memgraph/struct_to_map.go | 8 +- .../internal/memgraph/struct_to_map_test.go | 40 +++--- apps/db-adapter/main_test.go | 47 +------- 16 files changed, 251 insertions(+), 73 deletions(-) create mode 100644 apps/db-adapter/integration-tests/admin.go create mode 100644 apps/db-adapter/integration-tests/payloads/create_person.json create mode 100644 apps/db-adapter/integration-tests/payloads/create_person_with_invite_code.json create mode 100644 apps/db-adapter/integration-tests/person.go create mode 100644 apps/db-adapter/integration-tests/person_and_relationship.go create mode 100644 apps/db-adapter/integration-tests/person_family_tree.go create mode 100644 apps/db-adapter/integration-tests/person_google.go create mode 100644 apps/db-adapter/integration-tests/person_recipes.go create mode 100644 apps/db-adapter/integration-tests/recipe_relationship.go create mode 100644 apps/db-adapter/integration-tests/recipes.go create mode 100644 apps/db-adapter/integration-tests/relationship.go diff --git a/apps/db-adapter/integration-tests/admin.go b/apps/db-adapter/integration-tests/admin.go new file mode 100644 index 0000000..b89823b --- /dev/null +++ b/apps/db-adapter/integration-tests/admin.go @@ -0,0 +1,16 @@ +package integration_tests + +func CreateAdminRelationship() { +} + +func DeleteAdminRelationship() { +} + +func GetAdminRelationship() { +} + +func GetProfileAdmins() { +} + +func GetManagedProfiles() { +} diff --git a/apps/db-adapter/integration-tests/payloads/create_person.json b/apps/db-adapter/integration-tests/payloads/create_person.json new file mode 100644 index 0000000..9bada1b --- /dev/null +++ b/apps/db-adapter/integration-tests/payloads/create_person.json @@ -0,0 +1,9 @@ +{ + "first_name": "Alice", + "last_name": "Wonderland", + "born": "1990-06-01", + "limit": 100, + "mothers_first_name": "Mary", + "mothers_last_name": "Smith", + "email": "alice@example.com" +} \ No newline at end of file diff --git a/apps/db-adapter/integration-tests/payloads/create_person_with_invite_code.json b/apps/db-adapter/integration-tests/payloads/create_person_with_invite_code.json new file mode 100644 index 0000000..075179f --- /dev/null +++ b/apps/db-adapter/integration-tests/payloads/create_person_with_invite_code.json @@ -0,0 +1,12 @@ +{ + "invite_code": "INV123456", + "person": { + "first_name": "Bob", + "last_name": "Builder", + "born": "1985-11-25", + "limit": 200, + "mothers_first_name": "Linda", + "mothers_last_name": "Builder", + "email": "bob@example.com" + } +} \ No newline at end of file diff --git a/apps/db-adapter/integration-tests/person.go b/apps/db-adapter/integration-tests/person.go new file mode 100644 index 0000000..aec988a --- /dev/null +++ b/apps/db-adapter/integration-tests/person.go @@ -0,0 +1,16 @@ +package integration_tests + +func CreatePerson() { +} + +func GetPersonById() { +} + +func SoftDeletePerson() { +} + +func UpdatePerson() { +} + +func HardDeletePerson() { +} diff --git a/apps/db-adapter/integration-tests/person_and_relationship.go b/apps/db-adapter/integration-tests/person_and_relationship.go new file mode 100644 index 0000000..8c0dd04 --- /dev/null +++ b/apps/db-adapter/integration-tests/person_and_relationship.go @@ -0,0 +1,4 @@ +package integration_tests + +func CreatePersonAndRelationship() { +} diff --git a/apps/db-adapter/integration-tests/person_family_tree.go b/apps/db-adapter/integration-tests/person_family_tree.go new file mode 100644 index 0000000..e1e8b26 --- /dev/null +++ b/apps/db-adapter/integration-tests/person_family_tree.go @@ -0,0 +1,7 @@ +package integration_tests + +func GetFamilyTreeById() { +} + +func GetFamilyTreeWithSpousesById() { +} diff --git a/apps/db-adapter/integration-tests/person_google.go b/apps/db-adapter/integration-tests/person_google.go new file mode 100644 index 0000000..a0acaac --- /dev/null +++ b/apps/db-adapter/integration-tests/person_google.go @@ -0,0 +1,114 @@ +package integration_tests + +import ( + "bytes" + _ "embed" + "encoding/json" + "net/http" + "testing" + + "github.com/stretchr/testify/require" +) + +// TestPersonGoogle runs integration tests for the Person Google API endpoints. +// It requires a running instance of the db-adapter and a valid dbAdapterUri. +// The tests include creating a person by Google ID, and getting a person by Google ID. +// It does not include creating a person by Google ID with an invite code. +func TestPersonGoogle(dbAdapterUri string) func(t *testing.T) { + return func(t *testing.T) { + client := &http.Client{} + + t.Run("CreatePersonByGoogleId", createPersonByGoogleIdTest(dbAdapterUri, client)) + t.Run("GetPersonByGoogleId", getPersonByGoogleIdTest(dbAdapterUri, client)) + } +} + +func getPersonByGoogleIdTest(dbAdapterUri string, client *http.Client) func(t *testing.T) { + return func(t *testing.T) { + url := dbAdapterUri + "/person/google/test-google-id" + + req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, url, http.NoBody) + require.NoError(t, err) + + // Send the request + resp, err := client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + var responseBody map[string]any + err = json.NewDecoder(resp.Body).Decode(&responseBody) + require.NoError(t, err) + + // Validate the response + require.Equal(t, http.StatusOK, resp.StatusCode) + + _, ok := responseBody["Id"] + require.True(t, ok) + + require.Equal(t, "Alice", responseBody["Props"].(map[string]any)["first_name"]) + require.Equal(t, "Wonderland", responseBody["Props"].(map[string]any)["last_name"]) + } +} + +//go:embed payloads/create_person_with_invite_code.json +var create_person_with_invite_code []byte + +func CreatePersonByGoogleIdAndInviteCodeTest(dbAdapterUri string, client *http.Client) func(t *testing.T) { + return func(t *testing.T) { + url := dbAdapterUri + "/person/google/test-google-id" + + req, err := http.NewRequestWithContext(t.Context(), http.MethodPatch, url, bytes.NewBuffer(create_person_with_invite_code)) + require.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + // Send the request + resp, err := client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + var responseBody map[string]any + err = json.NewDecoder(resp.Body).Decode(&responseBody) + require.NoError(t, err) + + // Validate the response + t.Log("Response Status Code: ", responseBody) + require.Equal(t, http.StatusOK, resp.StatusCode) + + _, ok := responseBody["Id"] + require.True(t, ok) + + require.Equal(t, "John", responseBody["Props"].(map[string]any)["first_name"]) + require.Equal(t, "Doe", responseBody["Props"].(map[string]any)["last_name"]) + } +} + +//go:embed payloads/create_person.json +var create_person []byte + +func createPersonByGoogleIdTest(dbAdapterUri string, client *http.Client) func(t *testing.T) { + return func(t *testing.T) { + url := dbAdapterUri + "/person/google/test-google-id" + + req, err := http.NewRequestWithContext(t.Context(), http.MethodPost, url, bytes.NewBuffer(create_person)) + require.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + // Send the request + resp, err := client.Do(req) + require.NoError(t, err) + defer resp.Body.Close() + + var responseBody map[string]any + err = json.NewDecoder(resp.Body).Decode(&responseBody) + require.NoError(t, err) + + // Validate the response + require.Equal(t, http.StatusOK, resp.StatusCode) + + _, ok := responseBody["Id"] + require.True(t, ok) + + require.Equal(t, "Alice", responseBody["Props"].(map[string]any)["first_name"]) + require.Equal(t, "Wonderland", responseBody["Props"].(map[string]any)["last_name"]) + } +} diff --git a/apps/db-adapter/integration-tests/person_recipes.go b/apps/db-adapter/integration-tests/person_recipes.go new file mode 100644 index 0000000..c8f3aba --- /dev/null +++ b/apps/db-adapter/integration-tests/person_recipes.go @@ -0,0 +1,4 @@ +package integration_tests + +func GetRecipesByPersonId() { +} diff --git a/apps/db-adapter/integration-tests/recipe_relationship.go b/apps/db-adapter/integration-tests/recipe_relationship.go new file mode 100644 index 0000000..a50fa8c --- /dev/null +++ b/apps/db-adapter/integration-tests/recipe_relationship.go @@ -0,0 +1,9 @@ +package integration_tests + +func DeleteRecipeRelationship() { + +} + +func CreateRecipeRelationship() { + +} diff --git a/apps/db-adapter/integration-tests/recipes.go b/apps/db-adapter/integration-tests/recipes.go new file mode 100644 index 0000000..948a579 --- /dev/null +++ b/apps/db-adapter/integration-tests/recipes.go @@ -0,0 +1,10 @@ +package integration_tests + +func SoftDeleteRecipe() { +} + +func UpdateRecipe() { +} + +func HardDeleteRecipe() { +} diff --git a/apps/db-adapter/integration-tests/relationship.go b/apps/db-adapter/integration-tests/relationship.go new file mode 100644 index 0000000..d669743 --- /dev/null +++ b/apps/db-adapter/integration-tests/relationship.go @@ -0,0 +1,13 @@ +package integration_tests + +func CreateRelationship() { +} + +func UpdateRelationship() { +} + +func GetRelationship() { +} + +func DeleteRelationship() { +} diff --git a/apps/db-adapter/internal/api/person_google.go b/apps/db-adapter/internal/api/person_google.go index 6b8869b..c4afafa 100644 --- a/apps/db-adapter/internal/api/person_google.go +++ b/apps/db-adapter/internal/api/person_google.go @@ -24,7 +24,7 @@ func (srv *server) GetPersonByGoogleId(c *gin.Context, googleId string) { return } - c.JSON(http.StatusOK, res) + c.JSON(http.StatusOK, res.(map[string]any)["person"]) } func (srv *server) CreatePersonByGoogleIdAndInviteCode(c *gin.Context, googleId string) { @@ -56,7 +56,7 @@ func (srv *server) CreatePersonByGoogleIdAndInviteCode(c *gin.Context, googleId return } - c.JSON(http.StatusOK, res) + c.JSON(http.StatusOK, res.(map[string]any)["person"]) } func (srv *server) CreatePersonByGoogleId(c *gin.Context, googleId string) { @@ -82,5 +82,5 @@ func (srv *server) CreatePersonByGoogleId(c *gin.Context, googleId string) { return } - c.JSON(http.StatusOK, res) + c.JSON(http.StatusOK, res.(map[string]any)["person"]) } diff --git a/apps/db-adapter/internal/memgraph/init_database.go b/apps/db-adapter/internal/memgraph/init_database.go index e6264b5..f124c42 100644 --- a/apps/db-adapter/internal/memgraph/init_database.go +++ b/apps/db-adapter/internal/memgraph/init_database.go @@ -8,6 +8,11 @@ import ( "go.uber.org/zap" ) +const ( + databaseReconnectTimeout = 5 * time.Second + databaseReconnectAttempts = 5 +) + func InitDatabase(logger *zap.Logger, dbURI, dbUser, dbPassword string) neo4j.DriverWithContext { driver, err := neo4j.NewDriverWithContext(dbURI, neo4j.BasicAuth(dbUser, dbPassword, "")) if err != nil { @@ -15,7 +20,7 @@ func InitDatabase(logger *zap.Logger, dbURI, dbUser, dbPassword string) neo4j.Dr } ctx := context.Background() - for attempt := 1; attempt <= 5; attempt++ { + for attempt := 1; attempt <= databaseReconnectAttempts; attempt++ { err = driver.VerifyConnectivity(ctx) if err == nil { break @@ -27,7 +32,7 @@ func InitDatabase(logger *zap.Logger, dbURI, dbUser, dbPassword string) neo4j.Dr zap.String("dbURI", dbURI), zap.Int("attempt", attempt), ) - time.Sleep(time.Duration(attempt*5) * time.Second) + time.Sleep(time.Duration(attempt) * databaseReconnectTimeout) } if err != nil { diff --git a/apps/db-adapter/internal/memgraph/struct_to_map.go b/apps/db-adapter/internal/memgraph/struct_to_map.go index f818827..57cc48e 100644 --- a/apps/db-adapter/internal/memgraph/struct_to_map.go +++ b/apps/db-adapter/internal/memgraph/struct_to_map.go @@ -9,8 +9,8 @@ import ( // StructToMap recursively converts a struct to a map using JSON tags. // Nil pointers and unexported fields are excluded. -func StructToMap(input interface{}) map[string]interface{} { - result := make(map[string]interface{}) +func StructToMap(input any) map[string]any { + result := make(map[string]any) value := reflect.ValueOf(input) if value.Kind() == reflect.Ptr { @@ -22,7 +22,7 @@ func StructToMap(input interface{}) map[string]interface{} { typ := value.Type() - for i := 0; i < value.NumField(); i++ { + for i := range value.NumField() { field := typ.Field(i) fieldValue := value.Field(i) @@ -89,7 +89,7 @@ func indexComma(tag string) int { } // Checks if a value is one of the preserved types that shouldn't be expanded recursively -func isPreservedType(v interface{}) bool { +func isPreservedType(v any) bool { switch v.(type) { case dbtype.Point2D, *dbtype.Point2D, dbtype.Point3D, *dbtype.Point3D, diff --git a/apps/db-adapter/internal/memgraph/struct_to_map_test.go b/apps/db-adapter/internal/memgraph/struct_to_map_test.go index 97b116c..b486da5 100644 --- a/apps/db-adapter/internal/memgraph/struct_to_map_test.go +++ b/apps/db-adapter/internal/memgraph/struct_to_map_test.go @@ -13,12 +13,12 @@ type NestedStruct struct { } type TestStruct struct { - ExportedField string `json:"exported_field"` - unexportedField string // Should be ignored - IgnoredField string `json:"-"` + ExportedField string `json:"exported_field"` + IgnoredField string `json:"-"` + unexportedField string PointerField *string `json:"pointer_field"` - Nested NestedStruct `json:"nested"` NilPointer *string `json:"nil_pointer"` + Nested NestedStruct `json:"nested"` } func TestStructToMap(t *testing.T) { @@ -35,10 +35,10 @@ func TestStructToMap(t *testing.T) { NilPointer: nil, } - expected := map[string]interface{}{ + expected := map[string]any{ "exported_field": "exported value", "pointer_field": "pointer value", - "nested": map[string]interface{}{ + "nested": map[string]any{ "nested_field": "nested value", }, } @@ -70,23 +70,23 @@ func TestStructToMap_EmptyStruct(t *testing.T) { func TestIsPreservedType(t *testing.T) { // Test cases for preserved types tests := []struct { + input any name string - input interface{} expected bool }{ - {"Point2D", dbtype.Point2D{}, true}, - {"Pointer to Point2D", &dbtype.Point2D{}, true}, - {"Point3D", dbtype.Point3D{}, true}, - {"Pointer to Point3D", &dbtype.Point3D{}, true}, - {"Time", time.Time{}, true}, - {"LocalDateTime", dbtype.LocalDateTime{}, true}, - {"Date", dbtype.Date{}, true}, - {"Time", dbtype.Time{}, true}, - {"LocalTime", dbtype.LocalTime{}, true}, - {"Duration", dbtype.Duration{}, true}, - {"String", "not preserved", false}, - {"Integer", 123, false}, - {"Struct", struct{}{}, false}, + {dbtype.Point2D{}, "Point2D", true}, + {&dbtype.Point2D{}, "Pointer to Point2D", true}, + {dbtype.Point3D{}, "Point3D", true}, + {&dbtype.Point3D{}, "Pointer to Point3D", true}, + {time.Time{}, "Time", true}, + {dbtype.LocalDateTime{}, "LocalDateTime", true}, + {dbtype.Date{}, "Date", true}, + {dbtype.Time{}, "Time", true}, + {dbtype.LocalTime{}, "LocalTime", true}, + {dbtype.Duration{}, "Duration", true}, + {"not preserved", "String", false}, + {123, "Integer", false}, + {struct{}{}, "Struct", false}, } for _, tt := range tests { diff --git a/apps/db-adapter/main_test.go b/apps/db-adapter/main_test.go index f399b1f..a4f8aef 100644 --- a/apps/db-adapter/main_test.go +++ b/apps/db-adapter/main_test.go @@ -1,15 +1,13 @@ package main import ( - "bytes" - "encoding/json" - "net/http" "testing" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/network" "github.com/testcontainers/testcontainers-go/wait" + integration_tests "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/integration-tests" ) func TestIntegration(t *testing.T) { @@ -73,7 +71,7 @@ func TestIntegration(t *testing.T) { "HTTP_PORT": ":8080", }, Networks: []string{net.Name}, - WaitingFor: wait.ForLog("Starting server"), + WaitingFor: wait.ForListeningPort("8080/tcp"), } dbAdapterC, err := testcontainers.GenericContainer(t.Context(), testcontainers.GenericContainerRequest{ @@ -99,44 +97,5 @@ func TestIntegration(t *testing.T) { require.NoError(t, err) dbAdapterURI := "http://" + dbAdapterHost + ":" + dbAdapterPort.Port() - testClient := &http.Client{} - t.Run("TestCreatePersonByGoogleId", CreatePersonByGoogleIdTest(dbAdapterURI, testClient)) -} - -func CreatePersonByGoogleIdTest(dbAdapterUri string, client *http.Client) func(t *testing.T) { - return func(t *testing.T) { - url := dbAdapterUri + "/person/google/test-google-id" - requestBody := map[string]any{ - "first_name": "John", - "last_name": "Doe", - "born": "1990-01-01", - "limit": 10, - "mothers_first_name": "Jane", - "mothers_last_name": "Doe", - } - - body, err := json.Marshal(requestBody) - require.NoError(t, err) - - req, err := http.NewRequestWithContext(t.Context(), http.MethodPost, url, bytes.NewBuffer(body)) - require.NoError(t, err) - req.Header.Set("Content-Type", "application/json") - - // Send the request - resp, err := client.Do(req) - require.NoError(t, err) - defer resp.Body.Close() - - var responseBody map[string]any - err = json.NewDecoder(resp.Body).Decode(&responseBody) - require.NoError(t, err) - - // Validate the response - t.Log("Response Status Code: ", responseBody) - require.Equal(t, http.StatusOK, resp.StatusCode) - - require.Equal(t, int(1), responseBody["id"]) - require.Equal(t, "John", responseBody["first_name"]) - require.Equal(t, "Doe", responseBody["last_name"]) - } + t.Run("TestCreatePersonByGoogleIdAndGetById", integration_tests.TestPersonGoogle(dbAdapterURI)) }