Skip to content

Commit bccbf7a

Browse files
author
Maxence COEUR
committed
change sqlserver to postgre sql
1 parent 1a4c2ce commit bccbf7a

23 files changed

Lines changed: 698 additions & 601 deletions

‎POSTGRESQL_API_TESTS.md‎

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Recap des tests API PostgreSQL
2+
3+
Ce document resume les tests effectues apres la migration de l'API de SQL Server vers PostgreSQL.
4+
5+
## Environnement teste
6+
7+
- API ASP.NET Core `net10.0`
8+
- Base PostgreSQL via Docker Compose
9+
- Provider ADO.NET : `Npgsql`
10+
- Migrations automatiques : DbUp avec `dbup-postgresql`
11+
- Acces data : Dapper
12+
13+
La base PostgreSQL utilisee pendant les tests etait celle du service Docker `postgres`.
14+
Les secrets locaux, le contenu du `.env` et le fichier Firebase n'ont pas ete affiches ni documentes.
15+
16+
## Demarrage valide
17+
18+
Les points suivants ont ete verifies :
19+
20+
- Le conteneur PostgreSQL demarre et passe en etat `healthy`.
21+
- Docker Compose est valide avec `docker compose config --quiet`.
22+
- L'API demarre avec une connection string PostgreSQL.
23+
- DbUp se lance au demarrage de l'API.
24+
- DbUp detecte les scripts deja executes et ne rejoue pas les migrations inutilement.
25+
26+
Les scripts DbUp PostgreSQL valides sont :
27+
28+
- `TableMasterApi/sql-scripts/001_InitialSchema.sql`
29+
- `TableMasterApi/sql-scripts/002_UpdateReservationStatus.sql`
30+
- `TableMasterApi/sql-scripts/003_AddDeviceTokens.sql`
31+
32+
## Scenarios HTTP testes
33+
34+
Un scenario complet a ete execute en HTTP contre l'API locale, avec creation d'un compte de test, recuperation d'un token JWT, puis appels authentifies.
35+
36+
Routes d'authentification et utilisateur :
37+
38+
- `POST /api/User` : creation de compte
39+
- `POST /api/Auth` : login
40+
- `POST /api/Auth/refresh` : renouvellement du refresh token
41+
- `GET /api/User/{id}` : lecture utilisateur
42+
- `PUT /api/User` : mise a jour utilisateur
43+
- `PUT /api/User/Password` : changement de mot de passe
44+
- `DELETE /api/User` : suppression de compte
45+
46+
Routes restaurant :
47+
48+
- `POST /api/Restaurant` : creation restaurant
49+
- `GET /api/Restaurant/{id}` : lecture restaurant
50+
- `GET /api/Restaurant` : recherche restaurants avec pagination et distance
51+
- `PUT /api/Restaurant/{id}` : modification restaurant
52+
- `DELETE /api/Restaurant/{id}` : suppression restaurant
53+
54+
Routes tables :
55+
56+
- `POST /api/Table/Restaurant/{id}` : creation table
57+
- `GET /api/Table/Restaurant/{id}` : lecture tables d'un restaurant
58+
- `PUT /api/Table/{id}` : modification table
59+
- `POST /api/Table/Restaurant/{id}/Bulk` : remplacement des tables
60+
- `DELETE /api/Table/{id}` : suppression table
61+
62+
Routes menu :
63+
64+
- `POST /api/Menu` : creation menu
65+
- `GET /api/Menu/restaurant/{restaurantId}` : lecture menus d'un restaurant
66+
- `DELETE /api/Menu/{id}` : suppression menu
67+
68+
Routes horaires :
69+
70+
- `POST /api/DailyActivity` : creation horaire
71+
- `GET /api/DailyActivity/restaurant/{restaurantId}` : lecture horaires
72+
- `PUT /api/DailyActivity/{id}` : modification horaire
73+
- `DELETE /api/DailyActivity/{id}` : suppression horaire
74+
75+
Routes jours de fermeture :
76+
77+
- `POST /api/ClosedDayException` : creation fermeture
78+
- `GET /api/ClosedDayException/restaurant/{restaurantId}` : lecture fermetures
79+
- `PUT /api/ClosedDayException/{id}` : modification fermeture
80+
- `DELETE /api/ClosedDayException/{id}` : suppression fermeture
81+
82+
Routes avis :
83+
84+
- `POST /api/Review` : creation avis
85+
- `GET /api/Review/Restaurant/{id}` : lecture avis restaurant
86+
- `GET /api/Review/My` : lecture de mes avis
87+
- `PUT /api/Review/{id}` : modification avis
88+
- `DELETE /api/Review/{id}` : suppression avis
89+
90+
Routes reservations :
91+
92+
- `POST /api/Reservation` : creation reservation
93+
- `GET /api/Reservation` : lecture reservations
94+
- `GET /api/Reservation/My` : lecture de mes reservations
95+
- `PUT /api/Reservation/{id}/Status` : changement de statut
96+
- `DELETE /api/Reservation/{id}` : suppression reservation
97+
98+
Routes device tokens :
99+
100+
- `POST /api/DeviceToken` : enregistrement token appareil
101+
- `DELETE /api/DeviceToken` : suppression token appareil
102+
103+
## Bug trouve et corrige
104+
105+
Pendant le test de `POST /api/DailyActivity`, l'API retournait une erreur 500.
106+
107+
Cause :
108+
109+
- PostgreSQL renvoie les colonnes SQL `TIME` via `Npgsql` sous forme de `TimeOnly`.
110+
- Les modeles de l'API utilisent `TimeSpan` pour `StartTime` et `EndTime`.
111+
- Dapper ne convertissait pas automatiquement `TimeOnly` vers `TimeSpan`.
112+
113+
Correction ajoutee :
114+
115+
- Ajout de `TableMasterApi/DAL/Handlers/PostgresTimeSpanHandler.cs`
116+
- Enregistrement du handler Dapper dans `Program.cs`
117+
118+
Ce handler convertit :
119+
120+
- `TimeOnly` vers `TimeSpan` en lecture
121+
- `TimeSpan` vers parametre SQL en ecriture
122+
123+
Apres correction, les routes `DailyActivity` passent.
124+
125+
## Nettoyage des donnees de test
126+
127+
Les donnees creees par les scenarios de test ont ete ciblees avec des prefixes dedies :
128+
129+
- emails `codex.route.*@example.com`
130+
- emails `codex.password.*@example.com`
131+
- restaurants `Codex Test Restaurant ...`
132+
- device tokens `test-device-*`
133+
134+
Les donnees de test `codex.route.*` ont ete nettoyees apres la passe complete.
135+
Le compte temporaire utilise pour tester le changement de mot de passe a ete supprime via `DELETE /api/User`.
136+
137+
## Commandes de verification executees
138+
139+
```bash
140+
docker compose config --quiet
141+
dotnet build TableMasterApi.sln --no-restore
142+
dotnet test --no-build
143+
```
144+
145+
Resultat final :
146+
147+
- Build OK
148+
- Tests xUnit OK : 31/31
149+
- Scenario HTTP complet OK
150+
- Aucune trace restante de `SqlConnection`, `SqlException`, `DbUp.SqlServer`, `SqlDatabase`, `OUTPUT INSERTED`, `GETDATE()` ou syntaxe SQL Server critique dans `TableMasterApi/`
151+
152+
## Notes
153+
154+
- Les warnings de nullabilite existants ne bloquent pas la migration PostgreSQL.
155+
- Le package `Microsoft.AspNetCore.SignalR` remonte un warning NuGet indiquant qu'il est probablement inutile, mais ce point n'a pas ete modifie car il est hors scope de la migration.
156+
- Les tests ont valide le comportement avec une base PostgreSQL locale Docker. Ils ne constituent pas encore une suite automatisee versionnee dans `TableMasterApi.Tests`.

‎TableMasterApi/Controllers/ClosedDayExceptionController.cs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Asp.Versioning;
22
using Microsoft.AspNetCore.Authorization;
33
using Microsoft.AspNetCore.Mvc;
4-
using Microsoft.Data.SqlClient;
4+
using Npgsql;
55
using TableMasterApi.DAL.Interfaces;
66
using TableMasterApi.Model;
77
using TableMasterApi.Service;
@@ -34,7 +34,7 @@ public async Task<ActionResult<IEnumerable<ClosedDayExceptionOut>>> GetByRestaur
3434
var result = await _dal.GetByRestaurantAsync(restaurantId);
3535
return Ok(result);
3636
}
37-
catch (SqlException e)
37+
catch (PostgresException e)
3838
{
3939
return StatusCode(500, e.Message);
4040
}
@@ -55,7 +55,7 @@ public async Task<ActionResult<ClosedDayExceptionOut>> Post([FromBody] ClosedDay
5555
var result = await _dal.InsertAsync(input);
5656
return Ok(result);
5757
}
58-
catch (SqlException e)
58+
catch (PostgresException e)
5959
{
6060
return StatusCode(500, e.Message);
6161
}
@@ -90,7 +90,7 @@ public async Task<ActionResult<ClosedDayExceptionOut>> Put(long id, [FromBody] C
9090
if (result == null) return NotFound();
9191
return Ok(result);
9292
}
93-
catch (SqlException e)
93+
catch (PostgresException e)
9494
{
9595
return StatusCode(500, e.Message);
9696
}
@@ -120,7 +120,7 @@ public async Task<ActionResult> Delete(long id)
120120
var success = await _dal.DeleteAsync(id);
121121
return success ? Ok() : NotFound();
122122
}
123-
catch (SqlException e)
123+
catch (PostgresException e)
124124
{
125125
return StatusCode(500, e.Message);
126126
}

‎TableMasterApi/Controllers/DailyActivityController.cs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Asp.Versioning;
22
using Microsoft.AspNetCore.Authorization;
33
using Microsoft.AspNetCore.Mvc;
4-
using Microsoft.Data.SqlClient;
4+
using Npgsql;
55
using TableMasterApi.DAL.Interfaces;
66
using TableMasterApi.Model;
77
using TableMasterApi.Service;
@@ -34,7 +34,7 @@ public async Task<ActionResult<IEnumerable<DailyActivityOut>>> GetByRestaurant(l
3434
var activities = await _dal.GetByRestaurantAsync(restaurantId);
3535
return Ok(activities);
3636
}
37-
catch (SqlException e)
37+
catch (PostgresException e)
3838
{
3939
return StatusCode(500, e.Message);
4040
}
@@ -55,7 +55,7 @@ public async Task<ActionResult> Post([FromBody] DailyActivityIn input)
5555
var result = await _dal.InsertAsync(input);
5656
return Ok(result);
5757
}
58-
catch (SqlException e)
58+
catch (PostgresException e)
5959
{
6060
return StatusCode(500, e.Message);
6161
}
@@ -89,7 +89,7 @@ public async Task<ActionResult> Put(long id, [FromBody] DailyActivityIn input)
8989
var result = await _dal.UpdateAsync(id, input);
9090
return Ok(result);
9191
}
92-
catch (SqlException e)
92+
catch (PostgresException e)
9393
{
9494
return StatusCode(500, e.Message);
9595
}
@@ -119,7 +119,7 @@ public async Task<ActionResult> Delete(long id)
119119
var success = await _dal.DeleteAsync(id);
120120
return success ? Ok() : NotFound();
121121
}
122-
catch (SqlException e)
122+
catch (PostgresException e)
123123
{
124124
return StatusCode(500, e.Message);
125125
}

‎TableMasterApi/Controllers/MenuController.cs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Asp.Versioning;
22
using Microsoft.AspNetCore.Authorization;
33
using Microsoft.AspNetCore.Mvc;
4-
using Microsoft.Data.SqlClient;
4+
using Npgsql;
55
using TableMasterApi.DAL.Interfaces;
66
using TableMasterApi.Model;
77
using TableMasterApi.Service;
@@ -33,7 +33,7 @@ public async Task<ActionResult<IEnumerable<MenuOut>>> GetByRestaurant(long resta
3333
var menus = await _dal.GetByRestaurantAsync(restaurantId);
3434
return Ok(menus);
3535
}
36-
catch (SqlException e)
36+
catch (PostgresException e)
3737
{
3838
return StatusCode(500, e.Message);
3939
}
@@ -51,7 +51,7 @@ public async Task<ActionResult> Post([FromBody] MenuIn input)
5151
var result = await _dal.InsertAsync(input);
5252
return Ok(result);
5353
}
54-
catch (SqlException e)
54+
catch (PostgresException e)
5555
{
5656
return StatusCode(500, e.Message);
5757
}
@@ -79,7 +79,7 @@ public async Task<ActionResult> Delete(long id)
7979
var success = await _dal.DeleteAsync(id);
8080
return success ? Ok() : NotFound();
8181
}
82-
catch (SqlException e)
82+
catch (PostgresException e)
8383
{
8484
return StatusCode(500, e.Message);
8585
}

‎TableMasterApi/Controllers/UserController.cs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Microsoft.AspNetCore.Authorization;
22
using Microsoft.AspNetCore.Mvc;
3-
using Microsoft.Data.SqlClient;
3+
using Npgsql;
44
using Microsoft.Extensions.Options;
55
using System.Collections.Generic;
66
using System.Security.Cryptography;
@@ -79,9 +79,9 @@ public async Task<ActionResult<UserOut>> PutUser([FromBody] UserIn user)
7979

8080
return Ok(userPut);
8181
}
82-
catch (SqlException e)
82+
catch (PostgresException e)
8383
{
84-
if (e.Number == 2627)
84+
if (e.SqlState == PostgresErrorCodes.UniqueViolation)
8585
{
8686
return StatusCode(403, "L'Email existe deja dans la base");
8787
}
@@ -163,9 +163,9 @@ public async Task<ActionResult<LoginUserOut>> AddUser([FromBody] UserIn user)
163163

164164
return Ok(loginUserOut);
165165
}
166-
catch (SqlException e)
166+
catch (PostgresException e)
167167
{
168-
if (e.Number == 2627)
168+
if (e.SqlState == PostgresErrorCodes.UniqueViolation)
169169
{
170170
return StatusCode(403, "L'Email existe deja dans la base");
171171
}
@@ -190,7 +190,7 @@ public async Task<ActionResult<UserOut>> DeleteUser()
190190

191191
return Ok(deleted);
192192
}
193-
catch (SqlException e)
193+
catch (PostgresException e)
194194
{
195195
return StatusCode(500, e.Message);
196196
}

0 commit comments

Comments
 (0)