From d98122756a971f9b80b414a7a6bedc27206bbfae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Sun, 28 Sep 2025 15:56:40 +0200 Subject: [PATCH] update cart --- klarna-client.go | 5 +- main.go | 44 +++++--- main_test.go | 286 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+), 19 deletions(-) create mode 100644 main_test.go diff --git a/klarna-client.go b/klarna-client.go index 1e5f2ff..74bd837 100644 --- a/klarna-client.go +++ b/klarna-client.go @@ -3,10 +3,11 @@ package main import ( "encoding/json" "fmt" - "github.com/google/uuid" "io" "log" "net/http" + + "github.com/google/uuid" ) type KlarnaClient struct { @@ -60,7 +61,7 @@ func (k *KlarnaClient) getOrderResponse(res *http.Response) (*CheckoutOrder, err log.Println(string(body)) } - return nil, fmt.Errorf(res.Status) + return nil, fmt.Errorf("%s", res.Status) } func (k *KlarnaClient) CreateOrder(reader io.Reader) (*CheckoutOrder, error) { diff --git a/main.go b/main.go index 8eee3cb..36823c5 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "net/http/pprof" "os" "os/signal" + "strings" "syscall" "time" @@ -127,16 +128,33 @@ var tpl = ` ` -func main() { - baseUrl := os.Getenv("BASE_URL") +func getCountryFromHost(host string) string { + if strings.Contains(strings.ToLower(host), "-no") { + return "no" + } + return "se" +} + +func getCheckoutOrder(host string, cartId CartId) *messages.CreateCheckoutOrder { + baseUrl := fmt.Sprintf("https://%s", host) cartBaseUrl := os.Getenv("CART_BASE_URL") if cartBaseUrl == "" { cartBaseUrl = "https://cart.tornberg.me" } - if baseUrl == "" { - baseUrl = "https://slask-finder.tornberg.me" + country := getCountryFromHost(host) + + return &messages.CreateCheckoutOrder{ + Terms: fmt.Sprintf("%s/terms", baseUrl), + Checkout: fmt.Sprintf("%s/checkout?order_id={checkout.order.id}", baseUrl), + Confirmation: fmt.Sprintf("%s/confirmation/{checkout.order.id}", baseUrl), + Validation: fmt.Sprintf("%s/validation", cartBaseUrl), + Push: fmt.Sprintf("%s/push?order_id={checkout.order.id}", cartBaseUrl), + Country: country, } - // Create a new instance of the server +} + +func main() { + storage, err := NewDiskStorage(fmt.Sprintf("data/%s_state.gob", name)) if err != nil { log.Printf("Error loading state: %v\n", err) @@ -206,12 +224,11 @@ func main() { w.WriteHeader(http.StatusOK) w.Write([]byte("ok")) }) + mux.HandleFunc("/checkout", func(w http.ResponseWriter, r *http.Request) { orderId := r.URL.Query().Get("order_id") order := &CheckoutOrder{} - country := "se" - log.Printf("host: %s, referer: %s", r.Host, r.Referer()) - log.Printf("Checkout for country %s, method: %s, order_id: %s", country, r.Method, orderId) + if orderId == "" { cookie, err := r.Cookie("cartid") if err != nil { @@ -226,15 +243,8 @@ func main() { } cartId := ToCartId(cookie.Value) reply, err := syncedServer.pool.Process(cartId, Message{ - Type: CreateCheckoutOrderType, - Content: &messages.CreateCheckoutOrder{ - Terms: fmt.Sprintf("%s/terms", baseUrl), - Checkout: fmt.Sprintf("%s/checkout?order_id={checkout.order.id}", baseUrl), - Confirmation: fmt.Sprintf("%s/confirmation/{checkout.order.id}", baseUrl), - Validation: fmt.Sprintf("%s/validation", cartBaseUrl), - Push: fmt.Sprintf("%s/push?order_id={checkout.order.id}", cartBaseUrl), - Country: country, - }, + Type: CreateCheckoutOrderType, + Content: getCheckoutOrder(r.Host, cartId), }) if err != nil { w.WriteHeader(http.StatusInternalServerError) diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..1479969 --- /dev/null +++ b/main_test.go @@ -0,0 +1,286 @@ +package main + +import ( + "os" + "testing" +) + +func TestGetCountryFromHost(t *testing.T) { + tests := []struct { + name string + host string + expected string + }{ + { + name: "Norwegian host", + host: "s10n-no.tornberg.me", + expected: "no", + }, + { + name: "Swedish host", + host: "s10n-se.tornberg.me", + expected: "se", + }, + { + name: "Host with -no in the middle", + host: "api-no-staging.tornberg.me", + expected: "no", + }, + { + name: "Host without country suffix", + host: "s10n.tornberg.me", + expected: "se", + }, + { + name: "Host with different domain", + host: "example-no.com", + expected: "no", + }, + { + name: "Empty host", + host: "", + expected: "se", + }, + { + name: "Host with uppercase", + host: "S10N-NO.TORNBERG.ME", + expected: "no", + }, + { + name: "Host with mixed case", + host: "S10n-No.Tornberg.Me", + expected: "no", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := getCountryFromHost(tt.host) + if result != tt.expected { + t.Errorf("getCountryFromHost(%q) = %q, want %q", tt.host, result, tt.expected) + } + }) + } +} + +func TestGetCheckoutOrder(t *testing.T) { + // Save original environment variable and restore after test + originalCartBaseUrl := os.Getenv("CART_BASE_URL") + defer func() { + if originalCartBaseUrl == "" { + os.Unsetenv("CART_BASE_URL") + } else { + os.Setenv("CART_BASE_URL", originalCartBaseUrl) + } + }() + + tests := []struct { + name string + host string + cartId CartId + cartBaseUrl string + expectedUrls struct { + terms string + checkout string + confirmation string + validation string + push string + country string + } + }{ + { + name: "Norwegian host with default cart base URL", + host: "s10n-no.tornberg.me", + cartId: ToCartId("test-cart-123"), + cartBaseUrl: "", // Use default + expectedUrls: struct { + terms string + checkout string + confirmation string + validation string + push string + country string + }{ + terms: "https://s10n-no.tornberg.me/terms", + checkout: "https://s10n-no.tornberg.me/checkout?order_id={checkout.order.id}", + confirmation: "https://s10n-no.tornberg.me/confirmation/{checkout.order.id}", + validation: "https://cart.tornberg.me/validation", + push: "https://cart.tornberg.me/push?order_id={checkout.order.id}", + country: "no", + }, + }, + { + name: "Swedish host with default cart base URL", + host: "s10n-se.tornberg.me", + cartId: ToCartId("test-cart-456"), + cartBaseUrl: "", // Use default + expectedUrls: struct { + terms string + checkout string + confirmation string + validation string + push string + country string + }{ + terms: "https://s10n-se.tornberg.me/terms", + checkout: "https://s10n-se.tornberg.me/checkout?order_id={checkout.order.id}", + confirmation: "https://s10n-se.tornberg.me/confirmation/{checkout.order.id}", + validation: "https://cart.tornberg.me/validation", + push: "https://cart.tornberg.me/push?order_id={checkout.order.id}", + country: "se", + }, + }, + { + name: "Norwegian host with custom cart base URL", + host: "s10n-no.tornberg.me", + cartId: ToCartId("test-cart-789"), + cartBaseUrl: "https://custom-cart.example.com", + expectedUrls: struct { + terms string + checkout string + confirmation string + validation string + push string + country string + }{ + terms: "https://s10n-no.tornberg.me/terms", + checkout: "https://s10n-no.tornberg.me/checkout?order_id={checkout.order.id}", + confirmation: "https://s10n-no.tornberg.me/confirmation/{checkout.order.id}", + validation: "https://custom-cart.example.com/validation", + push: "https://custom-cart.example.com/push?order_id={checkout.order.id}", + country: "no", + }, + }, + { + name: "Host without country code defaults to Swedish", + host: "s10n.tornberg.me", + cartId: ToCartId("test-cart-default"), + cartBaseUrl: "", + expectedUrls: struct { + terms string + checkout string + confirmation string + validation string + push string + country string + }{ + terms: "https://s10n.tornberg.me/terms", + checkout: "https://s10n.tornberg.me/checkout?order_id={checkout.order.id}", + confirmation: "https://s10n.tornberg.me/confirmation/{checkout.order.id}", + validation: "https://cart.tornberg.me/validation", + push: "https://cart.tornberg.me/push?order_id={checkout.order.id}", + country: "se", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set up environment variable for this test + if tt.cartBaseUrl == "" { + os.Unsetenv("CART_BASE_URL") + } else { + os.Setenv("CART_BASE_URL", tt.cartBaseUrl) + } + + result := getCheckoutOrder(tt.host, tt.cartId) + + // Verify the result is not nil + if result == nil { + t.Fatal("getCheckoutOrder returned nil") + } + + // Check each URL field + if result.Terms != tt.expectedUrls.terms { + t.Errorf("Terms URL: got %q, want %q", result.Terms, tt.expectedUrls.terms) + } + + if result.Checkout != tt.expectedUrls.checkout { + t.Errorf("Checkout URL: got %q, want %q", result.Checkout, tt.expectedUrls.checkout) + } + + if result.Confirmation != tt.expectedUrls.confirmation { + t.Errorf("Confirmation URL: got %q, want %q", result.Confirmation, tt.expectedUrls.confirmation) + } + + if result.Validation != tt.expectedUrls.validation { + t.Errorf("Validation URL: got %q, want %q", result.Validation, tt.expectedUrls.validation) + } + + if result.Push != tt.expectedUrls.push { + t.Errorf("Push URL: got %q, want %q", result.Push, tt.expectedUrls.push) + } + + if result.Country != tt.expectedUrls.country { + t.Errorf("Country: got %q, want %q", result.Country, tt.expectedUrls.country) + } + }) + } +} + +func TestGetCheckoutOrderIntegration(t *testing.T) { + // Test that both functions work together correctly + hosts := []string{"s10n-no.tornberg.me", "s10n-se.tornberg.me"} + cartId := ToCartId("integration-test-cart") + + for _, host := range hosts { + t.Run(host, func(t *testing.T) { + // Get country from host + country := getCountryFromHost(host) + + // Get checkout order + order := getCheckoutOrder(host, cartId) + + // Verify that the country in the order matches what getCountryFromHost returns + if order.Country != country { + t.Errorf("Country mismatch: getCountryFromHost(%q) = %q, but order.Country = %q", + host, country, order.Country) + } + + // Verify that all URLs contain the correct host + expectedBaseUrl := "https://" + host + + if !containsPrefix(order.Terms, expectedBaseUrl) { + t.Errorf("Terms URL should start with %q, got %q", expectedBaseUrl, order.Terms) + } + + if !containsPrefix(order.Checkout, expectedBaseUrl) { + t.Errorf("Checkout URL should start with %q, got %q", expectedBaseUrl, order.Checkout) + } + + if !containsPrefix(order.Confirmation, expectedBaseUrl) { + t.Errorf("Confirmation URL should start with %q, got %q", expectedBaseUrl, order.Confirmation) + } + }) + } +} + +// Helper function to check if a string starts with a prefix +func containsPrefix(s, prefix string) bool { + return len(s) >= len(prefix) && s[:len(prefix)] == prefix +} + +// Benchmark tests to measure performance +func BenchmarkGetCountryFromHost(b *testing.B) { + hosts := []string{ + "s10n-no.tornberg.me", + "s10n-se.tornberg.me", + "api-no-staging.tornberg.me", + "s10n.tornberg.me", + } + + for i := 0; i < b.N; i++ { + for _, host := range hosts { + getCountryFromHost(host) + } + } +} + +func BenchmarkGetCheckoutOrder(b *testing.B) { + host := "s10n-no.tornberg.me" + cartId := ToCartId("benchmark-cart") + + for i := 0; i < b.N; i++ { + getCheckoutOrder(host, cartId) + } +}