@@ -5,9 +5,11 @@ import (
5
5
"encoding/json"
6
6
"errors"
7
7
"io"
8
+ "net"
8
9
"net/http"
9
10
"net/http/httptest"
10
11
"testing"
12
+ "time"
11
13
12
14
"github.com/hasura/go-graphql-client"
13
15
)
@@ -619,3 +621,147 @@ func mustWrite(w io.Writer, s string) {
619
621
panic (err )
620
622
}
621
623
}
624
+
625
+ func TestClientOption_WithRetry_succeed (t * testing.T ) {
626
+ var (
627
+ attempts int
628
+ maxAttempts = 3
629
+ )
630
+ mux := http .NewServeMux ()
631
+ mux .HandleFunc ("/graphql" , func (w http.ResponseWriter , req * http.Request ) {
632
+ attempts ++
633
+ // Simulate a temporary network error except for the last attempt
634
+ if attempts <= maxAttempts - 1 {
635
+ http .Error (w , "temporary error" , http .StatusServiceUnavailable )
636
+ return
637
+ }
638
+ // Succeed on the last attempt
639
+ w .Header ().Set ("Content-Type" , "application/json" )
640
+ mustWrite (w , `{"data": {"user": {"name": "Gopher"}}}` )
641
+ })
642
+
643
+ client := graphql .NewClient ("/graphql" ,
644
+ & http.Client {
645
+ Transport : localRoundTripper {
646
+ handler : mux ,
647
+ },
648
+ },
649
+ graphql .WithRetry (maxAttempts - 1 ),
650
+ )
651
+
652
+ var q struct {
653
+ User struct {
654
+ Name string
655
+ }
656
+ }
657
+
658
+ err := client .Query (context .Background (), & q , nil )
659
+ if err != nil {
660
+ t .Fatalf ("got error: %v, want nil" , err )
661
+ }
662
+
663
+ if attempts != maxAttempts {
664
+ t .Errorf ("got %d attempts, want %d" , attempts , maxAttempts )
665
+ }
666
+
667
+ if q .User .Name != "Gopher" {
668
+ t .Errorf ("got q.User.Name: %q, want Gopher" , q .User .Name )
669
+ }
670
+ }
671
+
672
+ func TestClientOption_WithRetry_maxRetriesExceeded (t * testing.T ) {
673
+ var (
674
+ attempts int
675
+ maxAttempts = 2
676
+ )
677
+ mux := http .NewServeMux ()
678
+ mux .HandleFunc ("/graphql" , func (w http.ResponseWriter , req * http.Request ) {
679
+ attempts ++
680
+ // Always fail with a temporary error
681
+ http .Error (w , "temporary error" , http .StatusServiceUnavailable )
682
+ })
683
+
684
+ client := graphql .NewClient ("/graphql" ,
685
+ & http.Client {
686
+ Transport : localRoundTripper {
687
+ handler : mux ,
688
+ },
689
+ },
690
+ graphql .WithRetry (maxAttempts - 1 ),
691
+ )
692
+
693
+ var q struct {
694
+ User struct {
695
+ Name string
696
+ }
697
+ }
698
+
699
+ err := client .Query (context .Background (), & q , nil )
700
+ if err == nil {
701
+ t .Fatal ("got nil, want error" )
702
+ }
703
+
704
+ // Check that we got the max retries exceeded error
705
+ var gqlErrs graphql.Errors
706
+ if ! errors .As (err , & gqlErrs ) {
707
+ t .Fatalf ("got %T, want graphql.Errors" , err )
708
+ }
709
+
710
+ if len (gqlErrs ) != 1 {
711
+ t .Fatalf ("got %d, want 1 error" , len (gqlErrs ))
712
+ }
713
+
714
+ // First request does not count
715
+ if attempts != maxAttempts {
716
+ t .Errorf ("got %d attempts, want %d" , attempts , maxAttempts )
717
+ }
718
+ }
719
+
720
+ // Define the custom RoundTripper type
721
+ type roundTripperWithRetryCount struct {
722
+ Transport * http.Transport
723
+ attempts * int
724
+ }
725
+
726
+ // Define RoundTrip method for the type
727
+ func (c roundTripperWithRetryCount ) RoundTrip (req * http.Request ) (* http.Response , error ) {
728
+ if c .attempts != nil {
729
+ * c .attempts ++
730
+ }
731
+ return c .Transport .RoundTrip (req )
732
+ }
733
+
734
+ func TestClientOption_WithRetry_shouldNotRetry (t * testing.T ) {
735
+ var attempts int
736
+
737
+ client := graphql .NewClient ("/graphql" ,
738
+ & http.Client {
739
+ Transport : roundTripperWithRetryCount {
740
+ attempts : & attempts ,
741
+ Transport : & http.Transport {
742
+ DialContext : (& net.Dialer {
743
+ Timeout : 3 * time .Second ,
744
+ KeepAlive : 3 * time .Second ,
745
+ }).DialContext ,
746
+ },
747
+ },
748
+ },
749
+ graphql .WithRetry (3 ),
750
+ )
751
+
752
+ var q struct {
753
+ User struct {
754
+ Name string
755
+ }
756
+ }
757
+
758
+ err := client .Query (context .Background (), & q , nil )
759
+ if err == nil {
760
+ t .Fatal ("got nil, want error" )
761
+ }
762
+
763
+ // Should not retry on permanent URL errors
764
+ if attempts != 1 {
765
+ t .Errorf ("got %d attempts, want 1" , attempts )
766
+ }
767
+ }
0 commit comments