@@ -3,24 +3,28 @@ package app
33import (
44 "encoding/json"
55 "fmt"
6+ "kubecloud/internal"
7+ "kubecloud/models"
68 "net/http"
79 "net/http/httptest"
10+ "os"
11+ "path/filepath"
812 "testing"
913 "time"
1014
1115 "github.com/stretchr/testify/assert"
1216 "github.com/stretchr/testify/require"
13-
14- "kubecloud/models"
1517)
1618
1719func TestListAllInvoicesHandler (t * testing.T ) {
1820 app , err := SetUp (t )
1921 require .NoError (t , err )
2022 router := app .router
2123
22- adminUser := CreateTestUser (
t ,
app ,
"[email protected] " ,
"Admin User" , []
byte (
"securepassword" ),
true ,
true ,
false ,
0 ,
time .
Now ())
23- nonAdminUser := CreateTestUser (
t ,
app ,
"[email protected] " ,
"Normal User" , []
byte (
"securepassword" ),
true ,
false ,
false ,
0 ,
time .
Now ())
24+ require .NotNil (t , app .handlers .fileStorage )
25+
26+ adminUser := CreateTestUser (
t ,
app ,
"[email protected] " ,
"Admin User" , []
byte (
"securepassword" ),
true ,
true ,
true ,
0 ,
time .
Now ())
27+ nonAdminUser := CreateTestUser (
t ,
app ,
"[email protected] " ,
"Normal User" , []
byte (
"securepassword" ),
true ,
false ,
true ,
0 ,
time .
Now ())
2428
2529 t .Run ("Test List all invoices with empty list" , func (t * testing.T ) {
2630 token := GetAuthToken (t , app , adminUser .ID , adminUser .Email , adminUser .Username , true )
@@ -62,6 +66,16 @@ func TestListAllInvoicesHandler(t *testing.T) {
6266 err = app .handlers .db .CreateInvoice (invoice2 )
6367 require .NoError (t , err )
6468
69+ pdf1 , err := internal .CreateInvoicePDF (* invoice1 , * adminUser , app .config .Invoice )
70+ require .NoError (t , err )
71+ pdf2 , err := internal .CreateInvoicePDF (* invoice2 , * nonAdminUser , app .config .Invoice )
72+ require .NoError (t , err )
73+
74+ _ , err = app .handlers .fileStorage .WriteInvoiceFile (adminUser .ID , invoice1 .ID , pdf1 )
75+ require .NoError (t , err )
76+ _ , err = app .handlers .fileStorage .WriteInvoiceFile (nonAdminUser .ID , invoice2 .ID , pdf2 )
77+ require .NoError (t , err )
78+
6579 t .Run ("Test List all invoices successfully" , func (t * testing.T ) {
6680 token := GetAuthToken (t , app , adminUser .ID , adminUser .Email , adminUser .Username , true )
6781 req , _ := http .NewRequest ("GET" , "/api/v1/invoices" , nil )
@@ -95,6 +109,18 @@ func TestListAllInvoicesHandler(t *testing.T) {
95109 }
96110 assert .True (t , found1 , "Admin's invoice should be in the list" )
97111 assert .True (t , found2 , "Normal user's invoice should be in the list" )
112+
113+ storedPDF1 , err := app .handlers .fileStorage .ReadInvoiceFile (adminUser .ID , invoice1 .ID )
114+ require .NoError (t , err )
115+ assert .Equal (t , pdf1 , storedPDF1 )
116+ assert .Greater (t , len (storedPDF1 ), 100 )
117+
118+ storedPDF2 , err := app .handlers .fileStorage .ReadInvoiceFile (nonAdminUser .ID , invoice2 .ID )
119+ require .NoError (t , err )
120+ assert .Equal (t , pdf2 , storedPDF2 )
121+ assert .Greater (t , len (storedPDF2 ), 100 )
122+
123+ assert .NotEqual (t , storedPDF1 , storedPDF2 )
98124 })
99125
100126 t .Run ("Test List all invoices with no token" , func (t * testing.T ) {
@@ -119,7 +145,7 @@ func TestListUserInvoicesHandler(t *testing.T) {
119145 require .NoError (t , err )
120146 router := app .router
121147
122- user := CreateTestUser (
t ,
app ,
"[email protected] " ,
"Test User" , []
byte (
"securepassword" ),
true ,
false ,
false ,
0 ,
time .
Now ())
148+ user := CreateTestUser (
t ,
app ,
"[email protected] " ,
"Test User" , []
byte (
"securepassword" ),
true ,
false ,
true ,
0 ,
time .
Now ())
123149
124150 t .Run ("Test List user invoices with empty list" , func (t * testing.T ) {
125151 token := GetAuthToken (t , app , user .ID , user .Email , user .Username , false )
@@ -153,6 +179,13 @@ func TestListUserInvoicesHandler(t *testing.T) {
153179 err = app .handlers .db .CreateInvoice (invoice1 )
154180 require .NoError (t , err )
155181
182+ pdfContent , err := internal .CreateInvoicePDF (* invoice1 , * user , app .config .Invoice )
183+ require .NoError (t , err )
184+ require .NotEmpty (t , pdfContent )
185+
186+ _ , err = app .handlers .fileStorage .WriteInvoiceFile (user .ID , invoice1 .ID , pdfContent )
187+ require .NoError (t , err )
188+
156189 t .Run ("Test List user invoices successfully" , func (t * testing.T ) {
157190 token := GetAuthToken (t , app , user .ID , user .Email , user .Username , false )
158191 req , _ := http .NewRequest ("GET" , "/api/v1/user/invoice" , nil )
@@ -164,6 +197,15 @@ func TestListUserInvoicesHandler(t *testing.T) {
164197 err := json .Unmarshal (resp .Body .Bytes (), & result )
165198 assert .NoError (t , err )
166199 assert .Equal (t , "Invoices are retrieved successfully" , result ["message" ])
200+
201+ data := result ["data" ].(map [string ]interface {})
202+ invoicesRaw := data ["invoices" ].([]interface {})
203+ assert .Len (t , invoicesRaw , 1 )
204+
205+ storedPDF , err := app .handlers .fileStorage .ReadInvoiceFile (user .ID , invoice1 .ID )
206+ require .NoError (t , err )
207+ assert .Equal (t , pdfContent , storedPDF )
208+ assert .Greater (t , len (storedPDF ), 100 )
167209 })
168210
169211 t .Run ("Test List user invoices with no token" , func (t * testing.T ) {
@@ -180,6 +222,8 @@ func TestDownloadInvoiceHandler(t *testing.T) {
180222 require .NoError (t , err )
181223 router := app .router
182224
225+ require .NotNil (t , app .handlers .fileStorage )
226+
183227 user1 := CreateTestUser (
t ,
app ,
"[email protected] " ,
"User One" , []
byte (
"securepassword" ),
true ,
false ,
false ,
0 ,
time .
Now ())
184228
185229 invoice := & models.Invoice {
@@ -193,14 +237,44 @@ func TestDownloadInvoiceHandler(t *testing.T) {
193237 require .NoError (t , err )
194238
195239 t .Run ("Download an invoice successfully" , func (t * testing.T ) {
240+ pdfContent , err := internal .CreateInvoicePDF (* invoice , * user1 , app .config .Invoice )
241+ require .NoError (t , err )
242+ require .NotEmpty (t , pdfContent )
243+ require .Greater (t , len (pdfContent ), 100 )
244+
245+ fileName , err := app .handlers .fileStorage .WriteInvoiceFile (user1 .ID , invoice .ID , pdfContent )
246+ require .NoError (t , err )
247+ assert .Contains (t , fileName , fmt .Sprintf ("user-%d" , user1 .ID ))
248+ assert .Contains (t , fileName , fmt .Sprintf ("invoice-%d" , invoice .ID ))
249+
250+ filePath := filepath .Join (app .config .FileStoragePath , "invoices" , fileName )
251+ assert .FileExists (t , filePath )
252+
253+ fileInfo , err := os .Stat (filePath )
254+ require .NoError (t , err )
255+ assert .Equal (t , os .FileMode (0o600 ), fileInfo .Mode ().Perm ())
256+
196257 token := GetAuthToken (t , app , user1 .ID , user1 .Email , user1 .Username , false )
197258 req , _ := http .NewRequest ("GET" , fmt .Sprintf ("/api/v1/user/invoice/%d" , invoice .ID ), nil )
198259 req .Header .Set ("Authorization" , "Bearer " + token )
199260 resp := httptest .NewRecorder ()
200261 router .ServeHTTP (resp , req )
262+
201263 assert .Equal (t , http .StatusOK , resp .Code )
202264 assert .Equal (t , "application/pdf" , resp .Header ().Get ("Content-Type" ))
203- assert .True (t , len (resp .Body .Bytes ()) > 0 )
265+
266+ responseBody := resp .Body .Bytes ()
267+ assert .NotEmpty (t , responseBody )
268+ assert .Greater (t , len (responseBody ), 100 )
269+ assert .Equal (t , pdfContent , responseBody )
270+
271+ if len (responseBody ) >= 4 {
272+ assert .Equal (t , "%PDF" , string (responseBody [:4 ]))
273+ }
274+
275+ contentDisposition := resp .Header ().Get ("Content-Disposition" )
276+ assert .Contains (t , contentDisposition , "attachment" )
277+ assert .Contains (t , contentDisposition , fileName )
204278 })
205279
206280 t .Run ("Download invoice with no token" , func (t * testing.T ) {
@@ -228,4 +302,65 @@ func TestDownloadInvoiceHandler(t *testing.T) {
228302 router .ServeHTTP (resp , req )
229303 assert .Equal (t , http .StatusBadRequest , resp .Code )
230304 })
305+
306+ t .Run ("Download invoice missing from file storage generates on-demand" , func (t * testing.T ) {
307+ user2 := CreateTestUser (
t ,
app ,
"[email protected] " ,
"User Two" , []
byte (
"password" ),
true ,
false ,
true ,
0 ,
time .
Now ())
308+
309+ invoice2 := & models.Invoice {
310+ UserID : user2 .ID ,
311+ Total : 99.99 ,
312+ Tax : 9.99 ,
313+ CreatedAt : time .Now (),
314+ }
315+ err := app .db .CreateInvoice (invoice2 )
316+ require .NoError (t , err )
317+
318+ token := GetAuthToken (t , app , user2 .ID , user2 .Email , user2 .Username , false )
319+ req , _ := http .NewRequest ("GET" , fmt .Sprintf ("/api/v1/user/invoice/%d" , invoice2 .ID ), nil )
320+ req .Header .Set ("Authorization" , "Bearer " + token )
321+ resp := httptest .NewRecorder ()
322+ router .ServeHTTP (resp , req )
323+
324+ assert .Equal (t , http .StatusOK , resp .Code )
325+ assert .Equal (t , "application/pdf" , resp .Header ().Get ("Content-Type" ))
326+
327+ responseBody := resp .Body .Bytes ()
328+ assert .NotEmpty (t , responseBody )
329+ assert .Greater (t , len (responseBody ), 100 )
330+
331+ if len (responseBody ) >= 4 {
332+ assert .Equal (t , "%PDF" , string (responseBody [:4 ]))
333+ }
334+
335+ storedContent , err := app .handlers .fileStorage .ReadInvoiceFile (user2 .ID , invoice2 .ID )
336+ require .NoError (t , err )
337+ assert .Equal (t , responseBody , storedContent )
338+ })
339+
340+ t .Run ("User cannot download another user's invoice" , func (t * testing.T ) {
341+ user3 := CreateTestUser (
t ,
app ,
"[email protected] " ,
"User Three" , []
byte (
"password" ),
true ,
false ,
true ,
0 ,
time .
Now ())
342+
343+ invoice3 := & models.Invoice {
344+ UserID : user1 .ID ,
345+ Total : 250.00 ,
346+ Tax : 25.00 ,
347+ CreatedAt : time .Now (),
348+ }
349+ err := app .db .CreateInvoice (invoice3 )
350+ require .NoError (t , err )
351+
352+ pdfContent , err := internal .CreateInvoicePDF (* invoice3 , * user1 , app .config .Invoice )
353+ require .NoError (t , err )
354+ _ , err = app .handlers .fileStorage .WriteInvoiceFile (user1 .ID , invoice3 .ID , pdfContent )
355+ require .NoError (t , err )
356+
357+ token := GetAuthToken (t , app , user3 .ID , user3 .Email , user3 .Username , false )
358+ req , _ := http .NewRequest ("GET" , fmt .Sprintf ("/api/v1/user/invoice/%d" , invoice3 .ID ), nil )
359+ req .Header .Set ("Authorization" , "Bearer " + token )
360+ resp := httptest .NewRecorder ()
361+ router .ServeHTTP (resp , req )
362+
363+ assert .Equal (t , http .StatusForbidden , resp .Code )
364+ assert .NotEqual (t , "application/pdf" , resp .Header ().Get ("Content-Type" ))
365+ })
231366}
0 commit comments