Files
onspring-api-sdk-go/records_test.go
T

1175 lines
34 KiB
Go

package onspring_test
import (
"context"
"encoding/json"
"fmt"
"net/http"
"reflect"
"strconv"
"testing"
"github.com/StevanFreeborn/onspring-api-sdk-go"
)
func TestRecords(t *testing.T) {
t.Run("Get", func(t *testing.T) {
t.Run("it should return an error if context is nil", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
var nilContext context.Context = nil
_, err := client.Records.Get(nilContext, 1, 1)
if err == nil {
t.Errorf("Expected error for nil context, got nil")
}
})
t.Run("it should return an error if context is canceled", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
ctx, cancel := context.WithCancel(t.Context())
cancel()
_, err := client.Records.Get(ctx, 1, 1)
if err == nil {
t.Errorf("Expected error for canceled context, got nil")
}
})
t.Run("it should return an error if encounters a network error", func(t *testing.T) {
client := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://invalid-url"),
onspring.WithHTTPClient(&http.Client{Transport: &ErrorTransport{}}),
)
_, err := client.Records.Get(t.Context(), 1, 1)
if err == nil {
t.Errorf("Expected network error, got nil")
}
})
t.Run("it should return an error if create a request fails", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
invalidClient := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://[::1]:namedport"),
onspring.WithHTTPClient(client.HTTPClient()),
)
_, err := invalidClient.Records.Get(t.Context(), 1, 1)
if err == nil {
t.Errorf("Expected request creation error, got nil")
}
})
t.Run("it should return an error if the endpoint returns a non-200 status code", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
_, err := client.Records.Get(t.Context(), 1, 1)
if err == nil {
t.Errorf("Expected error, got nil")
}
})
t.Run("it should perform a GET request to the correct endpoint and return a record", func(t *testing.T) {
appId := 1
recordId := 2
expectedRecord := onspring.Record{
AppId: appId,
RecordId: recordId,
FieldData: []onspring.RecordFieldValue{
{
Type: "String",
FieldId: 1,
Value: "test value",
},
},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("Expected GET method, got %s", r.Method)
}
expectedPath := fmt.Sprintf("/records/appId/%d/recordId/%d", appId, recordId)
if r.URL.Path != expectedPath {
t.Errorf("Expected %s endpoint, got %s", expectedPath, r.URL.Path)
}
jsonData, _ := json.Marshal(expectedRecord)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
})
record, err := client.Records.Get(t.Context(), appId, recordId)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if record.AppId != expectedRecord.AppId {
t.Errorf("Expected AppId %d but got %d", expectedRecord.AppId, record.AppId)
}
if record.RecordId != expectedRecord.RecordId {
t.Errorf("Expected RecordId %d but got %d", expectedRecord.RecordId, record.RecordId)
}
if len(record.FieldData) != len(expectedRecord.FieldData) {
t.Errorf("Expected %d field data items but got %d", len(expectedRecord.FieldData), len(record.FieldData))
}
})
t.Run("it should include fieldIds query param when provided", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
fieldIds := r.URL.Query().Get("fieldIds")
if fieldIds != "1,2,3" {
t.Errorf("Expected query param fieldIds to be 1,2,3 but got %s", fieldIds)
}
jsonData, _ := json.Marshal(onspring.Record{})
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
})
_, _ = client.Records.Get(t.Context(), 1, 1, onspring.WithFieldIds([]int{1, 2, 3}))
})
t.Run("it should include dataFormat query param when provided", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
dataFormat := r.URL.Query().Get("dataFormat")
if dataFormat != "Formatted" {
t.Errorf("Expected query param dataFormat to be Formatted but got %s", dataFormat)
}
jsonData, _ := json.Marshal(onspring.Record{})
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
})
_, _ = client.Records.Get(t.Context(), 1, 1, onspring.WithRecordDataFormat("Formatted"))
})
})
t.Run("List", func(t *testing.T) {
t.Run("it should return an error if context is nil", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
var nilContext context.Context = nil
_, err := client.Records.List(nilContext, 1)
if err == nil {
t.Errorf("Expected error for nil context, got nil")
}
})
t.Run("it should return an error if context is canceled", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
ctx, cancel := context.WithCancel(t.Context())
cancel()
_, err := client.Records.List(ctx, 1)
if err == nil {
t.Errorf("Expected error for canceled context, got nil")
}
})
t.Run("it should return an error if encounters a network error", func(t *testing.T) {
client := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://invalid-url"),
onspring.WithHTTPClient(&http.Client{Transport: &ErrorTransport{}}),
)
_, err := client.Records.List(t.Context(), 1)
if err == nil {
t.Errorf("Expected network error, got nil")
}
})
t.Run("it should return an error if create a request fails", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
invalidClient := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://[::1]:namedport"),
onspring.WithHTTPClient(client.HTTPClient()),
)
_, err := invalidClient.Records.List(t.Context(), 1)
if err == nil {
t.Errorf("Expected request creation error, got nil")
}
})
t.Run("it should return an error if the endpoint returns a non-200 status code", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
_, err := client.Records.List(t.Context(), 1)
if err == nil {
t.Errorf("Expected error, got nil")
}
})
t.Run("it should perform a GET request to the correct endpoint and return page of records", func(t *testing.T) {
appId := 1
expectedPageNumber := 1
expectedPageSize := 50
expectedPage := onspring.Page[onspring.Record]{
TotalPages: 1,
TotalRecords: 1,
PageNumber: 1,
PageSize: 1,
Items: []onspring.Record{
{
AppId: appId,
RecordId: 1,
FieldData: []onspring.RecordFieldValue{},
},
},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
t.Errorf("Expected GET method, got %s", r.Method)
}
expectedPath := fmt.Sprintf("/records/appId/%d", appId)
if r.URL.Path != expectedPath {
t.Errorf("Expected %s endpoint, got %s", expectedPath, r.URL.Path)
}
pageNumber := r.URL.Query().Get("pageNumber")
pageSize := r.URL.Query().Get("pageSize")
if pageNumber != strconv.Itoa(expectedPageNumber) {
t.Errorf("Expected query param pageNumber to be %d but got %s", expectedPageNumber, pageNumber)
}
if pageSize != strconv.Itoa(expectedPageSize) {
t.Errorf("Expected query param pageSize to be %d but got %s", expectedPageSize, pageSize)
}
jsonData, _ := json.Marshal(expectedPage)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
})
page, err := client.Records.List(t.Context(), appId)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if !reflect.DeepEqual(expectedPage, page) {
t.Errorf("Expected %v but got %v", expectedPage, page)
}
})
t.Run("it should include paging and record options when provided", func(t *testing.T) {
appId := 1
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
pageNumber := r.URL.Query().Get("pageNumber")
if pageNumber != "2" {
t.Errorf("Expected query param pageNumber to be 2 but got %s", pageNumber)
}
pageSize := r.URL.Query().Get("pageSize")
if pageSize != "10" {
t.Errorf("Expected query param pageSize to be 10 but got %s", pageSize)
}
fieldIds := r.URL.Query().Get("fieldIds")
if fieldIds != "1,2" {
t.Errorf("Expected query param fieldIds to be 1,2 but got %s", fieldIds)
}
dataFormat := r.URL.Query().Get("dataFormat")
if dataFormat != "Formatted" {
t.Errorf("Expected query param dataFormat to be Formatted but got %s", dataFormat)
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"pageNumber":2,"pageSize":10,"totalPages":2,"totalRecords":2,"items":[]}`))
})
_, _ = client.Records.List(
t.Context(),
appId,
onspring.WithFieldIds([]int{1, 2}),
onspring.WithRecordDataFormat("Formatted"),
onspring.WithPaging(onspring.ForPageNumber(2), onspring.WithPageSize(10)),
)
})
})
t.Run("ListAll", func(t *testing.T) {
t.Run("it should return an error if fails to retrieve any pages of records", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
for _, err := range client.Records.ListAll(t.Context(), 1) {
if err == nil {
t.Errorf("Expected error, got nil")
}
}
})
t.Run("it should return all the records from multiple pages", func(t *testing.T) {
expectedRecords := []onspring.Record{
{AppId: 1, RecordId: 1, FieldData: []onspring.RecordFieldValue{}},
{AppId: 1, RecordId: 2, FieldData: []onspring.RecordFieldValue{}},
}
pageOne := onspring.Page[onspring.Record]{
TotalPages: 2, TotalRecords: 2, PageNumber: 1, PageSize: 1,
Items: []onspring.Record{expectedRecords[0]},
}
pageTwo := onspring.Page[onspring.Record]{
TotalPages: 2, TotalRecords: 2, PageNumber: 2, PageSize: 1,
Items: []onspring.Record{expectedRecords[1]},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
pageNumber := r.URL.Query().Get("pageNumber")
if pageNumber == "1" {
jsonData, _ := json.Marshal(pageOne)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
}
if pageNumber == "2" {
jsonData, _ := json.Marshal(pageTwo)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
}
})
retrievedRecords := []onspring.Record{}
for record, _ := range client.Records.ListAll(t.Context(), 1) {
retrievedRecords = append(retrievedRecords, record)
}
if !reflect.DeepEqual(expectedRecords, retrievedRecords) {
t.Errorf("Expected %v but got %v", expectedRecords, retrievedRecords)
}
})
t.Run("it should return records and errors if some pages fail and some succeed", func(t *testing.T) {
expectedRecords := []onspring.Record{
{AppId: 1, RecordId: 1, FieldData: []onspring.RecordFieldValue{}},
}
pageOne := onspring.Page[onspring.Record]{
TotalPages: 2, TotalRecords: 2, PageNumber: 1, PageSize: 1,
Items: []onspring.Record{expectedRecords[0]},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
pageNumber := r.URL.Query().Get("pageNumber")
if pageNumber == "1" {
jsonData, _ := json.Marshal(pageOne)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
}
if pageNumber == "2" {
w.WriteHeader(http.StatusInternalServerError)
}
})
retrievedRecords := []onspring.Record{}
encounteredErrors := []error{}
for record, err := range client.Records.ListAll(t.Context(), 1) {
if err != nil {
encounteredErrors = append(encounteredErrors, err)
} else {
retrievedRecords = append(retrievedRecords, record)
}
}
if !reflect.DeepEqual(expectedRecords, retrievedRecords) {
t.Errorf("Expected %v but got %v", expectedRecords, retrievedRecords)
}
if len(encounteredErrors) != 1 {
t.Errorf("Expected to receive one error, but received %d", len(encounteredErrors))
}
})
t.Run("it should pass record options through to each page request", func(t *testing.T) {
page := onspring.Page[onspring.Record]{
TotalPages: 1, TotalRecords: 0, PageNumber: 1, PageSize: 1,
Items: []onspring.Record{},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
fieldIds := r.URL.Query().Get("fieldIds")
if fieldIds != "1,2" {
t.Errorf("Expected query param fieldIds to be 1,2 but got %s", fieldIds)
}
jsonData, _ := json.Marshal(page)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
})
for range client.Records.ListAll(t.Context(), 1, onspring.WithFieldIds([]int{1, 2})) {
}
})
})
t.Run("GetMany", func(t *testing.T) {
t.Run("it should return an error if context is nil", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
var nilContext context.Context = nil
_, err := client.Records.GetMany(nilContext, onspring.GetManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected error for nil context, got nil")
}
})
t.Run("it should return an error if context is canceled", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
ctx, cancel := context.WithCancel(t.Context())
cancel()
_, err := client.Records.GetMany(ctx, onspring.GetManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected error for canceled context, got nil")
}
})
t.Run("it should return an error if encounters a network error", func(t *testing.T) {
client := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://invalid-url"),
onspring.WithHTTPClient(&http.Client{Transport: &ErrorTransport{}}),
)
_, err := client.Records.GetMany(t.Context(), onspring.GetManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected network error, got nil")
}
})
t.Run("it should return an error if create a request fails", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
invalidClient := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://[::1]:namedport"),
onspring.WithHTTPClient(client.HTTPClient()),
)
_, err := invalidClient.Records.GetMany(t.Context(), onspring.GetManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected request creation error, got nil")
}
})
t.Run("it should return an error if the endpoint returns a non-200 status code", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
_, err := client.Records.GetMany(t.Context(), onspring.GetManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected error, got nil")
}
})
t.Run("it should perform a POST request to the /records/batch-get endpoint and return a batch of records", func(t *testing.T) {
request := onspring.GetManyRecordsRequest{
AppId: 1,
RecordIds: []int{1, 2},
FieldIds: []int{1},
DataFormat: "Formatted",
}
expectedBatch := onspring.RecordBatch{
Count: 2,
Items: []onspring.Record{
{AppId: 1, RecordId: 1, FieldData: []onspring.RecordFieldValue{}},
{AppId: 1, RecordId: 2, FieldData: []onspring.RecordFieldValue{}},
},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("Expected POST method, got %s", r.Method)
}
if r.URL.Path != "/records/batch-get" {
t.Errorf("Expected /records/batch-get endpoint, got %s", r.URL.Path)
}
var body onspring.GetManyRecordsRequest
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
t.Errorf("Expected to decode request body, but got error: %v", err)
}
if !reflect.DeepEqual(request, body) {
t.Errorf("Expected body to be %v but got %v", request, body)
}
jsonData, _ := json.Marshal(expectedBatch)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
})
batch, err := client.Records.GetMany(t.Context(), request)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if !reflect.DeepEqual(expectedBatch, batch) {
t.Errorf("Expected %v but got %v", expectedBatch, batch)
}
})
})
t.Run("Query", func(t *testing.T) {
t.Run("it should return an error if context is nil", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
var nilContext context.Context = nil
_, err := client.Records.Query(nilContext, onspring.QueryRecordsRequest{AppId: 1, Filter: "field eq 'value'"})
if err == nil {
t.Errorf("Expected error for nil context, got nil")
}
})
t.Run("it should return an error if context is canceled", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
ctx, cancel := context.WithCancel(t.Context())
cancel()
_, err := client.Records.Query(ctx, onspring.QueryRecordsRequest{AppId: 1, Filter: "field eq 'value'"})
if err == nil {
t.Errorf("Expected error for canceled context, got nil")
}
})
t.Run("it should return an error if encounters a network error", func(t *testing.T) {
client := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://invalid-url"),
onspring.WithHTTPClient(&http.Client{Transport: &ErrorTransport{}}),
)
_, err := client.Records.Query(t.Context(), onspring.QueryRecordsRequest{AppId: 1, Filter: "field eq 'value'"})
if err == nil {
t.Errorf("Expected network error, got nil")
}
})
t.Run("it should return an error if create a request fails", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
invalidClient := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://[::1]:namedport"),
onspring.WithHTTPClient(client.HTTPClient()),
)
_, err := invalidClient.Records.Query(t.Context(), onspring.QueryRecordsRequest{AppId: 1, Filter: "field eq 'value'"})
if err == nil {
t.Errorf("Expected request creation error, got nil")
}
})
t.Run("it should return an error if the endpoint returns a non-200 status code", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
_, err := client.Records.Query(t.Context(), onspring.QueryRecordsRequest{AppId: 1, Filter: "field eq 'value'"})
if err == nil {
t.Errorf("Expected error, got nil")
}
})
t.Run("it should perform a POST request to the /records/query endpoint and return page of records", func(t *testing.T) {
request := onspring.QueryRecordsRequest{
AppId: 1,
Filter: "field eq 'value'",
FieldIds: []int{1},
DataFormat: "Formatted",
}
expectedPage := onspring.Page[onspring.Record]{
TotalPages: 1,
TotalRecords: 1,
PageNumber: 1,
PageSize: 1,
Items: []onspring.Record{
{AppId: 1, RecordId: 1, FieldData: []onspring.RecordFieldValue{}},
},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("Expected POST method, got %s", r.Method)
}
if r.URL.Path != "/records/query" {
t.Errorf("Expected /records/query endpoint, got %s", r.URL.Path)
}
var body onspring.QueryRecordsRequest
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
t.Errorf("Expected to decode request body, but got error: %v", err)
}
if !reflect.DeepEqual(request, body) {
t.Errorf("Expected body to be %v but got %v", request, body)
}
jsonData, _ := json.Marshal(expectedPage)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
})
page, err := client.Records.Query(t.Context(), request)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if !reflect.DeepEqual(expectedPage, page) {
t.Errorf("Expected %v but got %v", expectedPage, page)
}
})
t.Run("it should include paging query params when provided", func(t *testing.T) {
expectedPageNumber := 2
expectedPageSize := 10
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
pageNumber := r.URL.Query().Get("pageNumber")
pageSize := r.URL.Query().Get("pageSize")
if pageNumber != strconv.Itoa(expectedPageNumber) {
t.Errorf("Expected query param pageNumber to be %d but got %s", expectedPageNumber, pageNumber)
}
if pageSize != strconv.Itoa(expectedPageSize) {
t.Errorf("Expected query param pageSize to be %d but got %s", expectedPageSize, pageSize)
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"pageNumber":2,"pageSize":10,"totalPages":2,"totalRecords":2,"items":[]}`))
})
_, _ = client.Records.Query(
t.Context(),
onspring.QueryRecordsRequest{AppId: 1, Filter: "field eq 'value'"},
onspring.ForPageNumber(expectedPageNumber),
onspring.WithPageSize(expectedPageSize),
)
})
})
t.Run("QueryAll", func(t *testing.T) {
t.Run("it should return an error if fails to retrieve any pages", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
for _, err := range client.Records.QueryAll(t.Context(), onspring.QueryRecordsRequest{AppId: 1, Filter: "field eq 'value'"}) {
if err == nil {
t.Errorf("Expected error, got nil")
}
}
})
t.Run("it should return all the records from multiple pages", func(t *testing.T) {
expectedRecords := []onspring.Record{
{AppId: 1, RecordId: 1, FieldData: []onspring.RecordFieldValue{}},
{AppId: 1, RecordId: 2, FieldData: []onspring.RecordFieldValue{}},
}
pageOne := onspring.Page[onspring.Record]{
TotalPages: 2, TotalRecords: 2, PageNumber: 1, PageSize: 1,
Items: []onspring.Record{expectedRecords[0]},
}
pageTwo := onspring.Page[onspring.Record]{
TotalPages: 2, TotalRecords: 2, PageNumber: 2, PageSize: 1,
Items: []onspring.Record{expectedRecords[1]},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
pageNumber := r.URL.Query().Get("pageNumber")
if pageNumber == "1" {
jsonData, _ := json.Marshal(pageOne)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
}
if pageNumber == "2" {
jsonData, _ := json.Marshal(pageTwo)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
}
})
retrievedRecords := []onspring.Record{}
for record, _ := range client.Records.QueryAll(t.Context(), onspring.QueryRecordsRequest{AppId: 1, Filter: "field eq 'value'"}) {
retrievedRecords = append(retrievedRecords, record)
}
if !reflect.DeepEqual(expectedRecords, retrievedRecords) {
t.Errorf("Expected %v but got %v", expectedRecords, retrievedRecords)
}
})
})
t.Run("Save", func(t *testing.T) {
t.Run("it should return an error if context is nil", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
var nilContext context.Context = nil
_, err := client.Records.Save(nilContext, onspring.SaveRecordRequest{AppId: 1, Fields: map[string]any{}})
if err == nil {
t.Errorf("Expected error for nil context, got nil")
}
})
t.Run("it should return an error if context is canceled", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
ctx, cancel := context.WithCancel(t.Context())
cancel()
_, err := client.Records.Save(ctx, onspring.SaveRecordRequest{AppId: 1, Fields: map[string]any{}})
if err == nil {
t.Errorf("Expected error for canceled context, got nil")
}
})
t.Run("it should return an error if encounters a network error", func(t *testing.T) {
client := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://invalid-url"),
onspring.WithHTTPClient(&http.Client{Transport: &ErrorTransport{}}),
)
_, err := client.Records.Save(t.Context(), onspring.SaveRecordRequest{AppId: 1, Fields: map[string]any{}})
if err == nil {
t.Errorf("Expected network error, got nil")
}
})
t.Run("it should return an error if create a request fails", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
invalidClient := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://[::1]:namedport"),
onspring.WithHTTPClient(client.HTTPClient()),
)
_, err := invalidClient.Records.Save(t.Context(), onspring.SaveRecordRequest{AppId: 1, Fields: map[string]any{}})
if err == nil {
t.Errorf("Expected request creation error, got nil")
}
})
t.Run("it should return an error if the endpoint returns a non-2xx status code", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
_, err := client.Records.Save(t.Context(), onspring.SaveRecordRequest{AppId: 1, Fields: map[string]any{}})
if err == nil {
t.Errorf("Expected error, got nil")
}
})
t.Run("it should perform a PUT request to the /records endpoint and return a response when successful", func(t *testing.T) {
recordId := 1
request := onspring.SaveRecordRequest{
AppId: 1,
RecordId: &recordId,
Fields: map[string]any{"1": "value"},
}
expectedResponse := onspring.SaveRecordResponse{
Id: 1,
Warnings: []string{"warning"},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPut {
t.Errorf("Expected PUT method, got %s", r.Method)
}
if r.URL.Path != "/records" {
t.Errorf("Expected /records endpoint, got %s", r.URL.Path)
}
var body onspring.SaveRecordRequest
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
t.Errorf("Expected to decode request body, but got error: %v", err)
}
if !reflect.DeepEqual(request, body) {
t.Errorf("Expected body to be %v but got %v", request, body)
}
jsonData, _ := json.Marshal(expectedResponse)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(jsonData)
})
response, err := client.Records.Save(t.Context(), request)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if !reflect.DeepEqual(expectedResponse, response) {
t.Errorf("Expected %v but got %v", expectedResponse, response)
}
})
})
t.Run("Delete", func(t *testing.T) {
t.Run("it should return an error if context is nil", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
var nilContext context.Context = nil
err := client.Records.Delete(nilContext, 1, 1)
if err == nil {
t.Errorf("Expected error for nil context, got nil")
}
})
t.Run("it should return an error if context is canceled", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
ctx, cancel := context.WithCancel(t.Context())
cancel()
err := client.Records.Delete(ctx, 1, 1)
if err == nil {
t.Errorf("Expected error for canceled context, got nil")
}
})
t.Run("it should return an error if encounters a network error", func(t *testing.T) {
client := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://invalid-url"),
onspring.WithHTTPClient(&http.Client{Transport: &ErrorTransport{}}),
)
err := client.Records.Delete(t.Context(), 1, 1)
if err == nil {
t.Errorf("Expected network error, got nil")
}
})
t.Run("it should return an error if create a request fails", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
invalidClient := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://[::1]:namedport"),
onspring.WithHTTPClient(client.HTTPClient()),
)
err := invalidClient.Records.Delete(t.Context(), 1, 1)
if err == nil {
t.Errorf("Expected request creation error, got nil")
}
})
t.Run("it should return an error if the endpoint returns a non-2xx status code", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
err := client.Records.Delete(t.Context(), 1, 1)
if err == nil {
t.Errorf("Expected error, got nil")
}
})
t.Run("it should perform a DELETE request to the correct endpoint and return no error if receives 204 status code", func(t *testing.T) {
appId := 1
recordId := 2
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
t.Errorf("Expected DELETE method, got %s", r.Method)
}
expectedPath := fmt.Sprintf("/records/appId/%d/recordId/%d", appId, recordId)
if r.URL.Path != expectedPath {
t.Errorf("Expected %s endpoint, got %s", expectedPath, r.URL.Path)
}
w.WriteHeader(http.StatusNoContent)
})
err := client.Records.Delete(t.Context(), appId, recordId)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
})
t.Run("DeleteMany", func(t *testing.T) {
t.Run("it should return an error if context is nil", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
var nilContext context.Context = nil
err := client.Records.DeleteMany(nilContext, onspring.DeleteManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected error for nil context, got nil")
}
})
t.Run("it should return an error if context is canceled", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
ctx, cancel := context.WithCancel(t.Context())
cancel()
err := client.Records.DeleteMany(ctx, onspring.DeleteManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected error for canceled context, got nil")
}
})
t.Run("it should return an error if encounters a network error", func(t *testing.T) {
client := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://invalid-url"),
onspring.WithHTTPClient(&http.Client{Transport: &ErrorTransport{}}),
)
err := client.Records.DeleteMany(t.Context(), onspring.DeleteManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected network error, got nil")
}
})
t.Run("it should return an error if create a request fails", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
invalidClient := onspring.NewClient(
"test-api-key",
onspring.WithBaseURL("http://[::1]:namedport"),
onspring.WithHTTPClient(client.HTTPClient()),
)
err := invalidClient.Records.DeleteMany(t.Context(), onspring.DeleteManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected request creation error, got nil")
}
})
t.Run("it should return an error if the endpoint returns a non-2xx status code", func(t *testing.T) {
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
})
err := client.Records.DeleteMany(t.Context(), onspring.DeleteManyRecordsRequest{AppId: 1, RecordIds: []int{1}})
if err == nil {
t.Errorf("Expected error, got nil")
}
})
t.Run("it should perform a POST request to the /records/batch-delete endpoint and return no error if receives 204 status code", func(t *testing.T) {
request := onspring.DeleteManyRecordsRequest{
AppId: 1,
RecordIds: []int{1, 2},
}
_, client := setupMockServer(t, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("Expected POST method, got %s", r.Method)
}
if r.URL.Path != "/records/batch-delete" {
t.Errorf("Expected /records/batch-delete endpoint, got %s", r.URL.Path)
}
var body onspring.DeleteManyRecordsRequest
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
t.Errorf("Expected to decode request body, but got error: %v", err)
}
if !reflect.DeepEqual(request, body) {
t.Errorf("Expected body to be %v but got %v", request, body)
}
w.WriteHeader(http.StatusNoContent)
})
err := client.Records.DeleteMany(t.Context(), request)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
})
}