mirror of
				https://github.com/binwiederhier/ntfy.git
				synced 2025-10-31 04:52:23 +01:00 
			
		
		
		
	More tests
This commit is contained in:
		
							parent
							
								
									00af52411c
								
							
						
					
					
						commit
						c12ecb9f21
					
				
					 4 changed files with 144 additions and 10 deletions
				
			
		|  | @ -9,7 +9,12 @@ import ( | |||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/emersion/go-smtp" | ||||
| 	"github.com/gorilla/websocket" | ||||
| 	"golang.org/x/sync/errgroup" | ||||
| 	"heckel.io/ntfy/log" | ||||
| 	"heckel.io/ntfy/user" | ||||
| 	"heckel.io/ntfy/util" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
|  | @ -25,13 +30,6 @@ import ( | |||
| 	"sync" | ||||
| 	"time" | ||||
| 	"unicode/utf8" | ||||
| 
 | ||||
| 	"heckel.io/ntfy/log" | ||||
| 
 | ||||
| 	"github.com/emersion/go-smtp" | ||||
| 	"github.com/gorilla/websocket" | ||||
| 	"golang.org/x/sync/errgroup" | ||||
| 	"heckel.io/ntfy/util" | ||||
| ) | ||||
| 
 | ||||
| /* | ||||
|  | @ -43,7 +41,6 @@ import ( | |||
| - MEDIUM: Reservation (UI): Show "This topic is reserved" error message when trying to reserve a reserved topic (Thorben) | ||||
| - MEDIUM: Reservation (UI): Ask for confirmation when removing reservation (deadcade) | ||||
| - MEDIUM: Reservation table delete button: dialog "keep or delete messages?" | ||||
| - MEDIUM: Tests for remaining payment endpoints | ||||
| - LOW: UI: Flickering upgrade banner when logging in | ||||
| - LOW: JS constants | ||||
| - LOW: Payments reconciliation process | ||||
|  |  | |||
|  | @ -524,6 +524,70 @@ func TestPayments_Webhook_Subscription_Updated_Downgrade_From_PastDue_To_Active( | |||
| 	require.NoFileExists(t, filepath.Join(s.config.AttachmentCacheDir, z2.ID)) | ||||
| } | ||||
| 
 | ||||
| func TestPayments_Webhook_Subscription_Deleted(t *testing.T) { | ||||
| 	// This tests incoming webhooks from Stripe to delete a subscription. It verifies that the database is | ||||
| 	// updated (all Stripe fields are deleted, and the tier is removed). | ||||
| 	// | ||||
| 	// It doesn't fully test the message/attachment deletion. That is tested above in the subscription update call. | ||||
| 
 | ||||
| 	stripeMock := &testStripeAPI{} | ||||
| 	defer stripeMock.AssertExpectations(t) | ||||
| 
 | ||||
| 	c := newTestConfigWithAuthFile(t) | ||||
| 	c.StripeSecretKey = "secret key" | ||||
| 	c.StripeWebhookKey = "webhook key" | ||||
| 	s := newTestServer(t, c) | ||||
| 	s.stripe = stripeMock | ||||
| 
 | ||||
| 	// Define how the mock should react | ||||
| 	stripeMock. | ||||
| 		On("ConstructWebhookEvent", mock.Anything, "stripe signature", "webhook key"). | ||||
| 		Return(jsonToStripeEvent(t, subscriptionDeletedEventJSON), nil) | ||||
| 
 | ||||
| 	// Create a user with a Stripe subscription and 3 reservations | ||||
| 	require.Nil(t, s.userManager.CreateTier(&user.Tier{ | ||||
| 		ID:               "ti_1", | ||||
| 		Code:             "pro", | ||||
| 		StripePriceID:    "price_1234", | ||||
| 		ReservationLimit: 1, | ||||
| 	})) | ||||
| 	require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser)) | ||||
| 	require.Nil(t, s.userManager.ChangeTier("phil", "pro")) | ||||
| 	require.Nil(t, s.userManager.AddReservation("phil", "atopic", user.PermissionDenyAll)) | ||||
| 
 | ||||
| 	// Add billing details | ||||
| 	u, err := s.userManager.User("phil") | ||||
| 	require.Nil(t, err) | ||||
| 	require.Nil(t, s.userManager.ChangeBilling(u.Name, &user.Billing{ | ||||
| 		StripeCustomerID:            "acct_5555", | ||||
| 		StripeSubscriptionID:        "sub_1234", | ||||
| 		StripeSubscriptionStatus:    stripe.SubscriptionStatusPastDue, | ||||
| 		StripeSubscriptionPaidUntil: time.Unix(123, 0), | ||||
| 		StripeSubscriptionCancelAt:  time.Unix(0, 0), | ||||
| 	})) | ||||
| 
 | ||||
| 	// Call the webhook: This does all the magic | ||||
| 	rr := request(t, s, "POST", "/v1/account/billing/webhook", "dummy", map[string]string{ | ||||
| 		"Stripe-Signature": "stripe signature", | ||||
| 	}) | ||||
| 	require.Equal(t, 200, rr.Code) | ||||
| 
 | ||||
| 	// Verify that database columns were updated | ||||
| 	u, err = s.userManager.User("phil") | ||||
| 	require.Nil(t, err) | ||||
| 	require.Nil(t, u.Tier) | ||||
| 	require.Equal(t, "acct_5555", u.Billing.StripeCustomerID) | ||||
| 	require.Equal(t, "", u.Billing.StripeSubscriptionID) | ||||
| 	require.Equal(t, stripe.SubscriptionStatus(""), u.Billing.StripeSubscriptionStatus) | ||||
| 	require.Equal(t, int64(0), u.Billing.StripeSubscriptionPaidUntil.Unix()) | ||||
| 	require.Equal(t, int64(0), u.Billing.StripeSubscriptionCancelAt.Unix()) | ||||
| 
 | ||||
| 	// Verify that reservations were deleted | ||||
| 	r, err := s.userManager.Reservations("phil") | ||||
| 	require.Nil(t, err) | ||||
| 	require.Equal(t, 0, len(r)) | ||||
| } | ||||
| 
 | ||||
| func TestPayments_Subscription_Update_Different_Tier(t *testing.T) { | ||||
| 	stripeMock := &testStripeAPI{} | ||||
| 	defer stripeMock.AssertExpectations(t) | ||||
|  | @ -739,3 +803,26 @@ const subscriptionUpdatedEventJSON = ` | |||
| 		} | ||||
| 	} | ||||
| }` | ||||
| 
 | ||||
| const subscriptionDeletedEventJSON = ` | ||||
| { | ||||
| 	"type": "customer.subscription.deleted", | ||||
| 	"data": { | ||||
| 		"object": { | ||||
| 			"id": "sub_1234", | ||||
| 			"customer": "acct_5555", | ||||
| 			"status": "active", | ||||
| 			"current_period_end": 1674268231, | ||||
| 			"cancel_at": 1674299999, | ||||
| 			"items": { | ||||
| 				"data": [ | ||||
| 					{ | ||||
| 						"price": { | ||||
| 							"id": "price_1234" | ||||
| 						} | ||||
| 					} | ||||
| 				] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| }` | ||||
|  |  | |||
|  | @ -1872,11 +1872,11 @@ func subscribe(t *testing.T, s *Server, url string, rr *httptest.ResponseRecorde | |||
| 		done <- true | ||||
| 	}() | ||||
| 	cancelAndWaitForDone := func() { | ||||
| 		time.Sleep(100 * time.Millisecond) | ||||
| 		time.Sleep(200 * time.Millisecond) | ||||
| 		cancel() | ||||
| 		<-done | ||||
| 	} | ||||
| 	time.Sleep(100 * time.Millisecond) | ||||
| 	time.Sleep(200 * time.Millisecond) | ||||
| 	return cancelAndWaitForDone | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,12 +1,14 @@ | |||
| package util | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"net/netip" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
|  | @ -212,3 +214,51 @@ func TestReadJSONWithLimit_NoAllowEmpty(t *testing.T) { | |||
| 	_, err := UnmarshalJSONWithLimit[testJSON](io.NopCloser(strings.NewReader(` `)), 10, false) | ||||
| 	require.Equal(t, ErrUnmarshalJSON, err) | ||||
| } | ||||
| 
 | ||||
| func TestRetry_Succeeds(t *testing.T) { | ||||
| 	start := time.Now() | ||||
| 	delays, i := []time.Duration{10 * time.Millisecond, 50 * time.Millisecond, 100 * time.Millisecond, time.Second}, 0 | ||||
| 	fn := func() (*int, error) { | ||||
| 		i++ | ||||
| 		if i < len(delays) { | ||||
| 			return nil, errors.New("error") | ||||
| 		} | ||||
| 		return Int(99), nil | ||||
| 	} | ||||
| 	result, err := Retry[int](fn, delays...) | ||||
| 	require.Nil(t, err) | ||||
| 	require.Equal(t, 99, *result) | ||||
| 	require.True(t, time.Since(start).Milliseconds() > 150) | ||||
| } | ||||
| 
 | ||||
| func TestRetry_Fails(t *testing.T) { | ||||
| 	fn := func() (*int, error) { | ||||
| 		return nil, errors.New("fails") | ||||
| 	} | ||||
| 	_, err := Retry[int](fn, 10*time.Millisecond) | ||||
| 	require.Error(t, err) | ||||
| } | ||||
| 
 | ||||
| func TestMinMax(t *testing.T) { | ||||
| 	require.Equal(t, 10, MinMax(9, 10, 99)) | ||||
| 	require.Equal(t, 99, MinMax(100, 10, 99)) | ||||
| 	require.Equal(t, 50, MinMax(50, 10, 99)) | ||||
| } | ||||
| 
 | ||||
| func TestPointerFunctions(t *testing.T) { | ||||
| 	i, s, ti := Int(99), String("abc"), Time(time.Unix(99, 0)) | ||||
| 	require.Equal(t, 99, *i) | ||||
| 	require.Equal(t, "abc", *s) | ||||
| 	require.Equal(t, time.Unix(99, 0), *ti) | ||||
| } | ||||
| 
 | ||||
| func TestMaybeMarshalJSON(t *testing.T) { | ||||
| 	require.Equal(t, `"aa"`, MaybeMarshalJSON("aa")) | ||||
| 	require.Equal(t, `[ | ||||
|   "aa", | ||||
|   "bb" | ||||
| ]`, MaybeMarshalJSON([]string{"aa", "bb"})) | ||||
| 	require.Equal(t, "<cannot serialize>", MaybeMarshalJSON(func() {})) | ||||
| 	require.Equal(t, `"`+strings.Repeat("x", 4999), MaybeMarshalJSON(strings.Repeat("x", 6000))) | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 binwiederhier
						binwiederhier