github.com/polygon-io/client-go@v1.16.4/rest/iter/iter_test.go (about)

     1  package iter_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"net/http"
     7  	"testing"
     8  
     9  	"github.com/jarcoal/httpmock"
    10  	"github.com/stretchr/testify/assert"
    11  
    12  	"github.com/polygon-io/client-go/rest/client"
    13  	"github.com/polygon-io/client-go/rest/iter"
    14  	"github.com/polygon-io/client-go/rest/models"
    15  )
    16  
    17  const (
    18  	listResourcePath = "/resource/{ticker}"
    19  )
    20  
    21  type Client struct {
    22  	client.Client
    23  }
    24  
    25  type ListResourceResponse struct {
    26  	models.BaseResponse
    27  	Results []Resource `json:"results,omitempty"`
    28  }
    29  
    30  type Resource struct {
    31  	Price string `json:"price"`
    32  }
    33  
    34  type ListResourceParams struct {
    35  	Ticker string `validate:"required" path:"ticker"`
    36  
    37  	Timestamp *string `query:"timestamp"`
    38  }
    39  
    40  func (c *Client) ListResource(ctx context.Context, params *ListResourceParams, options ...models.RequestOption) *iter.Iter[Resource] {
    41  	return iter.NewIter(ctx, listResourcePath, params, func(uri string) (iter.ListResponse, []Resource, error) {
    42  		res := &ListResourceResponse{}
    43  		err := c.CallURL(ctx, http.MethodGet, uri, res, options...)
    44  		return res, res.Results, err
    45  	})
    46  }
    47  
    48  func TestListResource(t *testing.T) {
    49  	c := Client{Client: client.New("API_KEY")}
    50  
    51  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
    52  	defer httpmock.DeactivateAndReset()
    53  
    54  	resource1 := Resource{Price: "price1"}
    55  	registerResponder(200, "https://api.polygon.io/resource/ticker1", ListResourceResponse{
    56  		BaseResponse: models.BaseResponse{
    57  			Status:    "OK",
    58  			RequestID: "req1",
    59  			Count:     1,
    60  			PaginationHooks: models.PaginationHooks{
    61  				NextURL: "https://api.polygon.io/resource/ticker1?cursor=NEXT",
    62  			},
    63  		},
    64  		Results: []Resource{resource1},
    65  	})
    66  
    67  	resource2 := Resource{Price: "price2"}
    68  	resource3 := Resource{Price: "price3"}
    69  	registerResponder(200, "https://api.polygon.io/resource/ticker1?cursor=NEXT", ListResourceResponse{
    70  		BaseResponse: models.BaseResponse{
    71  			Status:    "OK",
    72  			RequestID: "req2",
    73  			Count:     2,
    74  			PaginationHooks: models.PaginationHooks{
    75  				NextURL: "https://api.polygon.io/resource/ticker1?cursor=NEXTER",
    76  			},
    77  		},
    78  		Results: []Resource{resource2, resource3},
    79  	})
    80  
    81  	registerResponder(200, "https://api.polygon.io/resource/ticker1?cursor=NEXTER", ListResourceResponse{
    82  		BaseResponse: models.BaseResponse{
    83  			Status:    "OK",
    84  			RequestID: "req3",
    85  			Count:     0,
    86  			PaginationHooks: models.PaginationHooks{
    87  				NextURL: "https://api.polygon.io/resource/ticker1?cursor=NEXTER",
    88  			},
    89  		},
    90  	})
    91  
    92  	it := c.ListResource(context.Background(), &ListResourceParams{
    93  		Ticker: "ticker1",
    94  	})
    95  
    96  	// verify the first page
    97  	assert.Nil(t, it.Err())
    98  	assert.NotNil(t, it.Item())
    99  	// verify the first and second quotes
   100  	assert.True(t, it.Next())
   101  	assert.Nil(t, it.Err())
   102  	assert.Equal(t, resource1, it.Item())
   103  
   104  	// verify the second page
   105  	assert.True(t, it.Next())
   106  	assert.Nil(t, it.Err())
   107  	assert.Equal(t, resource2, it.Item())
   108  	assert.True(t, it.Next())
   109  	assert.Nil(t, it.Err())
   110  	assert.Equal(t, resource3, it.Item())
   111  
   112  	// verify the third page (end of list)
   113  	assert.False(t, it.Next()) // this should be false since the third page has no results
   114  	assert.Nil(t, it.Err())
   115  }
   116  
   117  func TestListResourceError(t *testing.T) {
   118  	c := Client{Client: client.New("API_KEY")}
   119  
   120  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   121  	defer httpmock.DeactivateAndReset()
   122  
   123  	baseRes := models.BaseResponse{
   124  		Status:       "NOT FOUND",
   125  		RequestID:    "req1",
   126  		ErrorMessage: "resource not found",
   127  	}
   128  	expectedErr := models.ErrorResponse{
   129  		StatusCode:   404,
   130  		BaseResponse: baseRes,
   131  	}
   132  	registerResponder(404, "https://api.polygon.io/resource/ticker1", ListResourceResponse{
   133  		BaseResponse: baseRes,
   134  	})
   135  
   136  	it := c.ListResource(context.Background(), &ListResourceParams{
   137  		Ticker: "ticker1",
   138  	})
   139  
   140  	// it.Next() should return false and the error should not be nil
   141  	assert.NotNil(t, it.Err())
   142  	assert.False(t, it.Next())
   143  	assert.NotNil(t, it.Err())
   144  	assert.Equal(t, expectedErr.Error(), it.Err().Error())
   145  
   146  	// subsequent calls to it.Next() should be false, item should be not nil, page should be an empty response
   147  	assert.False(t, it.Next())
   148  	assert.NotNil(t, it.Item())
   149  }
   150  
   151  func TestListResourceEncodeError(t *testing.T) {
   152  	c := Client{Client: client.New("API_KEY")}
   153  
   154  	httpmock.ActivateNonDefault(c.HTTP.GetClient())
   155  	defer httpmock.DeactivateAndReset()
   156  
   157  	it := c.ListResource(context.Background(), nil)
   158  
   159  	// it.Next() should return false and the error should not be nil
   160  	assert.NotNil(t, it.Err())
   161  	assert.False(t, it.Next())
   162  	assert.NotNil(t, it.Err())
   163  
   164  	// subsequent calls to it.Next() should be false, item should be not nil, page should be an empty response
   165  	assert.False(t, it.Next())
   166  	assert.NotNil(t, it.Item())
   167  }
   168  
   169  func registerResponder(status int, url string, res ListResourceResponse) {
   170  	httpmock.RegisterResponder("GET", url,
   171  		func(req *http.Request) (*http.Response, error) {
   172  			b, err := json.Marshal(res)
   173  			if err != nil {
   174  				return nil, err
   175  			}
   176  			resp := httpmock.NewStringResponse(status, string(b))
   177  			resp.Header.Add("Content-Type", "application/json")
   178  			return resp, nil
   179  		},
   180  	)
   181  }