tests: add integration tests

This commit is contained in:
Stevan Freeborn
2026-03-26 16:59:49 -05:00
parent 6c5b225d97
commit d1f57f77a5
15 changed files with 2290 additions and 12 deletions
+1
View File
@@ -11,3 +11,4 @@ go.work.sum
*.html *.html
cover.out cover.out
coverage.txt coverage.txt
.env
+211
View File
@@ -0,0 +1,211 @@
//go:build integration
package onspring_test
import (
"context"
"net/http"
"testing"
"github.com/StevanFreeborn/onspring-api-sdk-go"
)
func TestAppsIntegration(t *testing.T) {
loadEnvFile(t)
client := createClient(t)
ctx := context.Background()
t.Run("Get", func(t *testing.T) {
t.Run("should return an app", func(t *testing.T) {
appId := requireEnvInt(t, "TEST_APP_ID")
app, err := client.Apps.Get(ctx, appId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if app.Id != appId {
t.Errorf("Expected app id %d, got %d", appId, app.Id)
}
if app.Name == "" {
t.Error("Expected app name to not be empty")
}
if app.Href == "" {
t.Error("Expected app href to not be empty")
}
})
t.Run("should return a 401 error when an invalid api key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
appId := requireEnvInt(t, "TEST_APP_ID")
_, err := invalidClient.Apps.Get(ctx, appId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when api key does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
_, err := client.Apps.Get(ctx, appIdNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 error when an app id cannot be found", func(t *testing.T) {
_, err := client.Apps.Get(ctx, 0)
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("List", func(t *testing.T) {
t.Run("should return a paged list of apps", func(t *testing.T) {
page, err := client.Apps.List(ctx)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber == 0 {
t.Error("Expected page number to not be zero")
}
if page.PageSize == 0 {
t.Error("Expected page size to not be zero")
}
if page.TotalPages == 0 {
t.Error("Expected total pages to not be zero")
}
if page.TotalRecords == 0 {
t.Error("Expected total records to not be zero")
}
if len(page.Items) == 0 {
t.Error("Expected items to not be empty")
}
for _, app := range page.Items {
if app.Id == 0 {
t.Error("Expected app id to not be zero")
}
if app.Name == "" {
t.Error("Expected app name to not be empty")
}
if app.Href == "" {
t.Error("Expected app href to not be empty")
}
}
})
t.Run("should return a paged list of apps with correct page size and number when passed paging request", func(t *testing.T) {
page, err := client.Apps.List(ctx, onspring.ForPageNumber(1), onspring.WithPageSize(1))
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber != 1 {
t.Errorf("Expected page number 1, got %d", page.PageNumber)
}
if page.PageSize != 1 {
t.Errorf("Expected page size 1, got %d", page.PageSize)
}
if len(page.Items) != 1 {
t.Errorf("Expected 1 item, got %d", len(page.Items))
}
})
t.Run("should return a 400 response when an invalid page size is used", func(t *testing.T) {
_, err := client.Apps.List(ctx, onspring.WithPageSize(1001))
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 response when an invalid api key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
_, err := invalidClient.Apps.List(ctx)
assertAPIError(t, err, http.StatusUnauthorized)
})
})
t.Run("ListAll", func(t *testing.T) {
t.Run("should iterate all apps", func(t *testing.T) {
var apps []onspring.App
for app, err := range client.Apps.ListAll(ctx, onspring.WithPageSize(1)) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
apps = append(apps, app)
}
if len(apps) == 0 {
t.Error("Expected to iterate at least one app")
}
})
})
t.Run("GetMany", func(t *testing.T) {
t.Run("should return a collection of apps", func(t *testing.T) {
appIds := requireEnvIntSlice(t, "TEST_APP_IDS")
batch, err := client.Apps.GetMany(ctx, appIds)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if batch.Count != len(appIds) {
t.Errorf("Expected count %d, got %d", len(appIds), batch.Count)
}
if len(batch.Items) != len(appIds) {
t.Errorf("Expected %d items, got %d", len(appIds), len(batch.Items))
}
for _, app := range batch.Items {
if app.Id == 0 {
t.Error("Expected app id to not be zero")
}
if app.Name == "" {
t.Error("Expected app name to not be empty")
}
if app.Href == "" {
t.Error("Expected app href to not be empty")
}
}
})
t.Run("should return a 401 error when an invalid api key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
appIds := requireEnvIntSlice(t, "TEST_APP_IDS")
_, err := invalidClient.Apps.GetMany(ctx, appIds)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when api key does not have access to the apps", func(t *testing.T) {
appIdsNoAccess := requireEnvIntSlice(t, "TEST_APP_IDS_NO_ACCESS")
_, err := client.Apps.GetMany(ctx, appIdsNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
})
}
+1 -1
View File
@@ -21,7 +21,7 @@ const (
// defaultTimeout is the default HTTP client timeout duration. // defaultTimeout is the default HTTP client timeout duration.
defaultTimeout = 120 * time.Second defaultTimeout = 120 * time.Second
// defaultAPIKeyHeader is the HTTP header name used for API key authentication. // defaultAPIKeyHeader is the HTTP header name used for API key authentication.
defaultAPIKeyHeader = "x-api-key" defaultAPIKeyHeader = "x-apikey"
// defaultAPIVersionHeader is the HTTP header name used to specify the API version. // defaultAPIVersionHeader is the HTTP header name used to specify the API version.
defaultAPIVersionHeader = "x-api-version" defaultAPIVersionHeader = "x-api-version"
// defaultAPIVersion is the default Onspring API version to use. // defaultAPIVersion is the default Onspring API version to use.
+35
View File
@@ -0,0 +1,35 @@
API_BASE_URL=https://api.onspring.com
SANDBOX_API_KEY=your-sandbox-api-key
TEST_APP_ID=1
TEST_APP_ID_NO_ACCESS=2
TEST_APP_IDS=1,2,3
TEST_APP_IDS_NO_ACCESS=4,5,6
TEST_SURVEY_ID=1
TEST_SURVEY_RECORD_ID=1
TEST_SURVEY_AUTO_NUMBER_FIELD=1
TEST_FIELD_ID=1
TEST_FIELD_ID_NO_ACCESS=2
TEST_FIELD_IDS=1,2,3
TEST_FIELD_IDS_NO_ACCESS=4,5,6
TEST_TEXT_FIELD=1
TEST_RECORD=1
TEST_ATTACHMENT_FIELD=1
TEST_ATTACHMENT_FIELD_NO_ACCESS_FIELD=2
TEST_ATTACHMENT_FIELD_NO_ACCESS_APP=3
TEST_ATTACHMENT=1
TEST_IMAGE_FIELD=1
TEST_IMAGE=1
TEST_LIST_FIELD=1
TEST_LIST_FIELD_NO_ACCESS=2
TEST_LIST_ID=1
TEST_LIST_ID_NO_ACCESS=2
TEST_LIST_ITEM_ID_NO_ACCESS=some-guid
TEST_REPORT=1
TEST_REPORT_NO_ACCESS=2
TEST_REPORT_WITH_CHART_DATA=3
+11 -2
View File
@@ -32,7 +32,7 @@ type Field struct {
// FormulaField represents a formula field type in Onspring // FormulaField represents a formula field type in Onspring
type FormulaField struct { type FormulaField struct {
OutputType string `json:"outputType"` OutputType string `json:"outputType"`
Values []string `json:"values"` Values []ListValue `json:"values"`
} }
// ReferenceField represents a reference field type in Onspring // ReferenceField represents a reference field type in Onspring
@@ -41,10 +41,19 @@ type ReferenceField struct {
ReferenceAppId string `json:"referenceAppId"` ReferenceAppId string `json:"referenceAppId"`
} }
// ListValue represents a value option within a list field in Onspring.
type ListValue struct {
Id string `json:"id"`
Name string `json:"name"`
SortOrder int `json:"sortOrder"`
NumericValue float64 `json:"numericValue"`
Color string `json:"color"`
}
// ListField represents a list field type in Onspring // ListField represents a list field type in Onspring
type ListField struct { type ListField struct {
Multiplicity string `json:"multiplicity"` Multiplicity string `json:"multiplicity"`
Values []string `json:"values"` Values []ListValue `json:"values"`
ListId int `json:"listId"` ListId int `json:"listId"`
} }
+232
View File
@@ -0,0 +1,232 @@
//go:build integration
package onspring_test
import (
"context"
"net/http"
"testing"
"github.com/StevanFreeborn/onspring-api-sdk-go"
)
func TestFieldsIntegration(t *testing.T) {
loadEnvFile(t)
client := createClient(t)
ctx := context.Background()
t.Run("Get", func(t *testing.T) {
t.Run("should return a field", func(t *testing.T) {
fieldId := requireEnvInt(t, "TEST_FIELD_ID")
field, err := client.Fields.Get(ctx, fieldId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if field.Id != fieldId {
t.Errorf("Expected field id %d, got %d", fieldId, field.Id)
}
if field.Name == "" {
t.Error("Expected field name to not be empty")
}
if field.AppId == 0 {
t.Error("Expected field appId to not be zero")
}
if field.Type == "" {
t.Error("Expected field type to not be empty")
}
if field.Status == "" {
t.Error("Expected field status to not be empty")
}
})
t.Run("should return a 401 error when an invalid api key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
fieldId := requireEnvInt(t, "TEST_FIELD_ID")
_, err := invalidClient.Fields.Get(ctx, fieldId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when api key does not have access to the field", func(t *testing.T) {
fieldIdNoAccess := requireEnvInt(t, "TEST_FIELD_ID_NO_ACCESS")
_, err := client.Fields.Get(ctx, fieldIdNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 error when the field does not exist", func(t *testing.T) {
_, err := client.Fields.Get(ctx, 0)
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("List", func(t *testing.T) {
t.Run("should return a paged list of fields", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
page, err := client.Fields.List(ctx, surveyId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber == 0 {
t.Error("Expected page number to not be zero")
}
if page.TotalRecords == 0 {
t.Error("Expected total records to not be zero")
}
if len(page.Items) == 0 {
t.Error("Expected items to not be empty")
}
for _, field := range page.Items {
if field.Id == 0 {
t.Error("Expected field id to not be zero")
}
if field.Name == "" {
t.Error("Expected field name to not be empty")
}
if field.AppId == 0 {
t.Error("Expected field appId to not be zero")
}
if field.Type == "" {
t.Error("Expected field type to not be empty")
}
if field.Status == "" {
t.Error("Expected field status to not be empty")
}
}
})
t.Run("should return a paged list of fields with correct page size and number when passed paging request", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
page, err := client.Fields.List(ctx, surveyId, onspring.ForPageNumber(1), onspring.WithPageSize(1))
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber != 1 {
t.Errorf("Expected page number 1, got %d", page.PageNumber)
}
if page.PageSize != 1 {
t.Errorf("Expected page size 1, got %d", page.PageSize)
}
if len(page.Items) != 1 {
t.Errorf("Expected 1 item, got %d", len(page.Items))
}
})
t.Run("should return a 400 response when an invalid page size is used", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
_, err := client.Fields.List(ctx, surveyId, onspring.WithPageSize(1001))
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 response when an invalid api key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
_, err := invalidClient.Fields.List(ctx, surveyId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 response when api key does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
_, err := client.Fields.List(ctx, appIdNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
})
t.Run("ListAll", func(t *testing.T) {
t.Run("should iterate all fields for an app", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
var fields []onspring.Field
for field, err := range client.Fields.ListAll(ctx, surveyId, onspring.WithPageSize(1)) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
fields = append(fields, field)
}
if len(fields) == 0 {
t.Error("Expected to iterate at least one field")
}
})
})
t.Run("GetMany", func(t *testing.T) {
t.Run("should return a collection of fields", func(t *testing.T) {
fieldIds := requireEnvIntSlice(t, "TEST_FIELD_IDS")
batch, err := client.Fields.GetMany(ctx, fieldIds)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if batch.Count != len(fieldIds) {
t.Errorf("Expected count %d, got %d", len(fieldIds), batch.Count)
}
if len(batch.Items) != len(fieldIds) {
t.Errorf("Expected %d items, got %d", len(fieldIds), len(batch.Items))
}
for _, field := range batch.Items {
if field.Id == 0 {
t.Error("Expected field id to not be zero")
}
if field.Name == "" {
t.Error("Expected field name to not be empty")
}
}
})
t.Run("should return a 401 response when an invalid api key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
fieldIds := requireEnvIntSlice(t, "TEST_FIELD_IDS")
_, err := invalidClient.Fields.GetMany(ctx, fieldIds)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 response when the api key does not have access to any of the requested fields", func(t *testing.T) {
fieldIdsNoAccess := requireEnvIntSlice(t, "TEST_FIELD_IDS_NO_ACCESS")
_, err := client.Fields.GetMany(ctx, fieldIdsNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
})
}
+16 -4
View File
@@ -138,7 +138,10 @@ func TestFields(t *testing.T) {
"isRequired": true, "isRequired": true,
"isUnique": false, "isUnique": false,
"outputType": "Number", "outputType": "Number",
"values": ["1", "2", "3"] "values": [
{"id": "a1", "name": "Value1", "sortOrder": 1, "numericValue": 1, "color": "#fff"},
{"id": "b2", "name": "Value2", "sortOrder": 2, "numericValue": 2, "color": "#000"}
]
}` }`
var field onspring.Field var field onspring.Field
@@ -161,7 +164,10 @@ func TestFields(t *testing.T) {
expectedFormulaField := onspring.FormulaField{ expectedFormulaField := onspring.FormulaField{
OutputType: "Number", OutputType: "Number",
Values: []string{"1", "2", "3"}, Values: []onspring.ListValue{
{Id: "a1", Name: "Value1", SortOrder: 1, NumericValue: 1, Color: "#fff"},
{Id: "b2", Name: "Value2", SortOrder: 2, NumericValue: 2, Color: "#000"},
},
} }
if !reflect.DeepEqual(formulaField, expectedFormulaField) { if !reflect.DeepEqual(formulaField, expectedFormulaField) {
@@ -220,7 +226,10 @@ func TestFields(t *testing.T) {
"isRequired": false, "isRequired": false,
"isUnique": false, "isUnique": false,
"multiplicity": "MultiSelect", "multiplicity": "MultiSelect",
"values": ["OptionA", "OptionB"], "values": [
{"id": "aaa", "name": "OptionA", "sortOrder": 1, "numericValue": 0, "color": "#ffffff"},
{"id": "bbb", "name": "OptionB", "sortOrder": 2, "numericValue": 0, "color": "#000000"}
],
"listId": 456 "listId": 456
}` }`
@@ -244,7 +253,10 @@ func TestFields(t *testing.T) {
expectedListField := onspring.ListField{ expectedListField := onspring.ListField{
Multiplicity: "MultiSelect", Multiplicity: "MultiSelect",
Values: []string{"OptionA", "OptionB"}, Values: []onspring.ListValue{
{Id: "aaa", Name: "OptionA", SortOrder: 1, NumericValue: 0, Color: "#ffffff"},
{Id: "bbb", Name: "OptionB", SortOrder: 2, NumericValue: 0, Color: "#000000"},
},
ListId: 456, ListId: 456,
} }
+590
View File
@@ -0,0 +1,590 @@
//go:build integration
package onspring_test
import (
"context"
"net/http"
"os"
"testing"
"github.com/StevanFreeborn/onspring-api-sdk-go"
)
func TestFilesIntegration(t *testing.T) {
loadEnvFile(t)
client := createClient(t)
ctx := context.Background()
t.Run("GetInfo", func(t *testing.T) {
t.Run("should return information about a file in an attachment field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
info, err := client.Files.GetInfo(ctx, recordId, fieldId, fileId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if info.Name == "" {
t.Error("Expected name to not be empty")
}
if info.ContentType == "" {
t.Error("Expected content type to not be empty")
}
if info.CreatedDate == "" {
t.Error("Expected created date to not be empty")
}
if info.ModifiedDate == "" {
t.Error("Expected modified date to not be empty")
}
if info.Owner == "" {
t.Error("Expected owner to not be empty")
}
if info.Type == "" {
t.Error("Expected type to not be empty")
}
if info.FileHref == "" {
t.Error("Expected file href to not be empty")
}
})
t.Run("should return information about a file in an image field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_IMAGE_FIELD")
fileId := requireEnvInt(t, "TEST_IMAGE")
info, err := client.Files.GetInfo(ctx, recordId, fieldId, fileId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if info.Name == "" {
t.Error("Expected name to not be empty")
}
if info.ContentType == "" {
t.Error("Expected content type to not be empty")
}
if info.Type == "" {
t.Error("Expected type to not be empty")
}
})
t.Run("should return a 400 response when fieldId is not for a file field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetInfo(ctx, recordId, textFieldId, fileId)
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 response when the api key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := invalidClient.Files.GetInfo(ctx, recordId, fieldId, fileId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 response when the api key does not have access to the file field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldIdNoAccess := requireEnvInt(t, "TEST_ATTACHMENT_FIELD_NO_ACCESS_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetInfo(ctx, recordId, fieldIdNoAccess, fileId)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 403 response when the api key does not have access to the app", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldIdNoApp := requireEnvInt(t, "TEST_ATTACHMENT_FIELD_NO_ACCESS_APP")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetInfo(ctx, recordId, fieldIdNoApp, fileId)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 response when the file field cannot be found", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetInfo(ctx, recordId, 0, fileId)
assertAPIError(t, err, http.StatusNotFound)
})
t.Run("should return a 404 response when the file record cannot be found", func(t *testing.T) {
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetInfo(ctx, 0, fieldId, fileId)
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("GetContent", func(t *testing.T) {
t.Run("should return a file in an attachment field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
content, err := client.Files.GetContent(ctx, recordId, fieldId, fileId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(content.Data) == 0 {
t.Error("Expected data to not be empty")
}
if content.ContentType == "" {
t.Error("Expected content type to not be empty")
}
if content.FileName == "" {
t.Error("Expected file name to not be empty")
}
})
t.Run("should return a file in an image field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_IMAGE_FIELD")
fileId := requireEnvInt(t, "TEST_IMAGE")
content, err := client.Files.GetContent(ctx, recordId, fieldId, fileId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if len(content.Data) == 0 {
t.Error("Expected data to not be empty")
}
if content.ContentType == "" {
t.Error("Expected content type to not be empty")
}
if content.FileName == "" {
t.Error("Expected file name to not be empty")
}
})
t.Run("should return a 400 response when fieldId is not for a file field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetContent(ctx, recordId, textFieldId, fileId)
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 response when the api key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := invalidClient.Files.GetContent(ctx, recordId, fieldId, fileId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 response when the api key does not have access to the file field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldIdNoAccess := requireEnvInt(t, "TEST_ATTACHMENT_FIELD_NO_ACCESS_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetContent(ctx, recordId, fieldIdNoAccess, fileId)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 403 response when the api key does not have access to the app", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldIdNoApp := requireEnvInt(t, "TEST_ATTACHMENT_FIELD_NO_ACCESS_APP")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetContent(ctx, recordId, fieldIdNoApp, fileId)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 response when the file field cannot be found", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetContent(ctx, recordId, 0, fileId)
assertAPIError(t, err, http.StatusNotFound)
})
t.Run("should return a 404 response when the file record cannot be found", func(t *testing.T) {
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
_, err := client.Files.GetContent(ctx, 0, fieldId, fileId)
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("Save", func(t *testing.T) {
t.Run("should save a file into an attachment field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
file, err := os.Open("testdata/test-attachment.txt")
if err != nil {
t.Fatalf("Failed to open test attachment: %v", err)
}
defer func() {
_ = file.Close()
}()
response, err := client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: fieldId,
FileName: "test-attachment.txt",
FileContents: file,
})
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if response.Id == 0 {
t.Error("Expected file id to not be zero")
}
t.Cleanup(func() {
_ = client.Files.Delete(context.Background(), recordId, fieldId, response.Id)
})
})
t.Run("should save a file into an image field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_IMAGE_FIELD")
file, err := os.Open("testdata/test-image.jpeg")
if err != nil {
t.Fatalf("Failed to open test image: %v", err)
}
defer func() {
_ = file.Close()
}()
response, err := client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: fieldId,
FileName: "test-image.jpeg",
FileContents: file,
})
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if response.Id == 0 {
t.Error("Expected file id to not be zero")
}
t.Cleanup(func() {
_ = client.Files.Delete(context.Background(), recordId, fieldId, response.Id)
})
})
t.Run("should return a 400 response when fieldId is not for a file field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
file, err := os.Open("testdata/test-attachment.txt")
if err != nil {
t.Fatalf("Failed to open test attachment: %v", err)
}
defer func() {
_ = file.Close()
}()
_, err = client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: textFieldId,
FileName: "test-attachment.txt",
FileContents: file,
})
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 response when the api key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
file, err := os.Open("testdata/test-attachment.txt")
if err != nil {
t.Fatalf("Failed to open test attachment: %v", err)
}
defer func() {
_ = file.Close()
}()
_, err = invalidClient.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: fieldId,
FileName: "test-attachment.txt",
FileContents: file,
})
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 response when the api key does not have access to the field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldIdNoAccess := requireEnvInt(t, "TEST_ATTACHMENT_FIELD_NO_ACCESS_FIELD")
file, err := os.Open("testdata/test-attachment.txt")
if err != nil {
t.Fatalf("Failed to open test attachment: %v", err)
}
defer func() {
_ = file.Close()
}()
_, err = client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: fieldIdNoAccess,
FileName: "test-attachment.txt",
FileContents: file,
})
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 403 response when the api key does not have access to the app", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldIdNoApp := requireEnvInt(t, "TEST_ATTACHMENT_FIELD_NO_ACCESS_APP")
file, err := os.Open("testdata/test-attachment.txt")
if err != nil {
t.Fatalf("Failed to open test attachment: %v", err)
}
defer func() {
_ = file.Close()
}()
_, err = client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: fieldIdNoApp,
FileName: "test-attachment.txt",
FileContents: file,
})
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 response when the file field cannot be found", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
file, err := os.Open("testdata/test-attachment.txt")
if err != nil {
t.Fatalf("Failed to open test attachment: %v", err)
}
defer func() {
_ = file.Close()
}()
_, err = client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: 0,
FileName: "test-attachment.txt",
FileContents: file,
})
assertAPIError(t, err, http.StatusNotFound)
})
t.Run("should return a 404 response when the file record cannot be found", func(t *testing.T) {
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
file, err := os.Open("testdata/test-attachment.txt")
if err != nil {
t.Fatalf("Failed to open test attachment: %v", err)
}
defer func() {
_ = file.Close()
}()
_, err = client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: 0,
FieldId: fieldId,
FileName: "test-attachment.txt",
FileContents: file,
})
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("Delete", func(t *testing.T) {
t.Run("should delete a file from an attachment field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
file, err := os.Open("testdata/test-attachment.txt")
if err != nil {
t.Fatalf("Failed to open test attachment: %v", err)
}
defer func() {
_ = file.Close()
}()
saveResponse, err := client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: fieldId,
FileName: "test-attachment-to-delete.txt",
FileContents: file,
})
if err != nil {
t.Fatalf("Failed to save file: %v", err)
}
err = client.Files.Delete(ctx, recordId, fieldId, saveResponse.Id)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
t.Run("should delete a file from an image field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_IMAGE_FIELD")
file, err := os.Open("testdata/test-image.jpeg")
if err != nil {
t.Fatalf("Failed to open test image: %v", err)
}
defer func() {
_ = file.Close()
}()
saveResponse, err := client.Files.Save(ctx, onspring.SaveFileRequest{
RecordId: recordId,
FieldId: fieldId,
FileName: "test-image-to-delete.jpeg",
FileContents: file,
})
if err != nil {
t.Fatalf("Failed to save file: %v", err)
}
err = client.Files.Delete(ctx, recordId, fieldId, saveResponse.Id)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
t.Run("should return a 400 response when fieldId is not for a file field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
err := client.Files.Delete(ctx, recordId, textFieldId, fileId)
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 response when the api key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
recordId := requireEnvInt(t, "TEST_RECORD")
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
err := invalidClient.Files.Delete(ctx, recordId, fieldId, fileId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 response when the api key does not have access to the field", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldIdNoAccess := requireEnvInt(t, "TEST_ATTACHMENT_FIELD_NO_ACCESS_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
err := client.Files.Delete(ctx, recordId, fieldIdNoAccess, fileId)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 403 response when the api key does not have access to the app", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fieldIdNoApp := requireEnvInt(t, "TEST_ATTACHMENT_FIELD_NO_ACCESS_APP")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
err := client.Files.Delete(ctx, recordId, fieldIdNoApp, fileId)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 response when the file field cannot be found", func(t *testing.T) {
recordId := requireEnvInt(t, "TEST_RECORD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
err := client.Files.Delete(ctx, recordId, 0, fileId)
assertAPIError(t, err, http.StatusNotFound)
})
t.Run("should return a 404 response when the file record cannot be found", func(t *testing.T) {
fieldId := requireEnvInt(t, "TEST_ATTACHMENT_FIELD")
fileId := requireEnvInt(t, "TEST_ATTACHMENT")
err := client.Files.Delete(ctx, 0, fieldId, fileId)
assertAPIError(t, err, http.StatusNotFound)
})
})
}
+158
View File
@@ -0,0 +1,158 @@
//go:build integration
package onspring_test
import (
"bufio"
"context"
"errors"
"fmt"
"os"
"strconv"
"strings"
"testing"
"github.com/StevanFreeborn/onspring-api-sdk-go"
)
func loadEnvFile(t *testing.T) {
t.Helper()
file, err := os.Open(".env")
if err != nil {
t.Fatalf("Failed to open .env file: %v", err)
}
defer func() {
_ = file.Close()
}()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
key, value, found := strings.Cut(line, "=")
if !found {
continue
}
key = strings.TrimSpace(key)
value = strings.TrimSpace(value)
t.Setenv(key, value)
}
if err := scanner.Err(); err != nil {
t.Fatalf("Failed to read .env file: %v", err)
}
}
func requireEnv(t *testing.T, key string) string {
t.Helper()
value := os.Getenv(key)
if value == "" {
t.Fatalf("Required environment variable %s is not set", key)
}
return value
}
func requireEnvInt(t *testing.T, key string) int {
t.Helper()
value := requireEnv(t, key)
intValue, err := strconv.Atoi(value)
if err != nil {
t.Fatalf("Environment variable %s is not a valid integer: %v", key, err)
}
return intValue
}
func requireEnvIntSlice(t *testing.T, key string) []int {
t.Helper()
value := requireEnv(t, key)
parts := strings.Split(value, ",")
result := make([]int, len(parts))
for i, part := range parts {
intValue, err := strconv.Atoi(strings.TrimSpace(part))
if err != nil {
t.Fatalf("Environment variable %s contains invalid integer '%s': %v", key, part, err)
}
result[i] = intValue
}
return result
}
func createClient(t *testing.T) *onspring.Client {
t.Helper()
return onspring.NewClient(
requireEnv(t, "SANDBOX_API_KEY"),
onspring.WithBaseURL(requireEnv(t, "API_BASE_URL")),
)
}
func createInvalidClient(t *testing.T) *onspring.Client {
t.Helper()
return onspring.NewClient(
"invalid-api-key",
onspring.WithBaseURL(requireEnv(t, "API_BASE_URL")),
)
}
func assertAPIError(t *testing.T, err error, expectedStatus int) {
t.Helper()
if err == nil {
t.Fatalf("Expected error, got nil")
}
var apiErr *onspring.OnspringAPIError
if !errors.As(err, &apiErr) {
t.Fatalf("Expected OnspringAPIError, got %T: %v", err, err)
}
if apiErr.StatusCode != expectedStatus {
t.Errorf("Expected status code %d, got %d", expectedStatus, apiErr.StatusCode)
}
}
func addTestRecord(t *testing.T, client *onspring.Client, appId, textFieldId int) int {
t.Helper()
ctx := context.Background()
response, err := client.Records.Save(ctx, onspring.SaveRecordRequest{
AppId: appId,
Fields: map[string]any{
fmt.Sprintf("%d", textFieldId): "test",
},
})
if err != nil {
t.Fatalf("Failed to create test record: %v", err)
}
t.Cleanup(func() {
_ = client.Records.Delete(context.Background(), appId, response.Id)
})
return response.Id
}
+155
View File
@@ -0,0 +1,155 @@
//go:build integration
package onspring_test
import (
"context"
"net/http"
"testing"
"github.com/StevanFreeborn/onspring-api-sdk-go"
)
func TestListsIntegration(t *testing.T) {
loadEnvFile(t)
client := createClient(t)
ctx := context.Background()
t.Run("Save", func(t *testing.T) {
t.Run("should add a list item", func(t *testing.T) {
listId := requireEnvInt(t, "TEST_LIST_ID")
item := onspring.SaveListItemRequest{
Name: "Integration Test Item",
}
response, err := client.Lists.Save(ctx, listId, item)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if response.Id == "" {
t.Error("Expected list item id to not be empty")
}
t.Cleanup(func() {
_ = client.Lists.Delete(context.Background(), listId, response.Id)
})
})
t.Run("should update a list item", func(t *testing.T) {
listId := requireEnvInt(t, "TEST_LIST_ID")
item := onspring.SaveListItemRequest{
Name: "Integration Test Item",
}
addResponse, err := client.Lists.Save(ctx, listId, item)
if err != nil {
t.Fatalf("Failed to add list item: %v", err)
}
t.Cleanup(func() {
_ = client.Lists.Delete(context.Background(), listId, addResponse.Id)
})
updateItem := onspring.SaveListItemRequest{
Id: addResponse.Id,
Name: "Updated Integration Test Item",
}
updateResponse, err := client.Lists.Save(ctx, listId, updateItem)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if updateResponse.Id == "" {
t.Error("Expected list item id to not be empty")
}
})
t.Run("should return a 401 error when an invalid api key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
listId := requireEnvInt(t, "TEST_LIST_ID")
item := onspring.SaveListItemRequest{
Name: "Integration Test Item",
}
_, err := invalidClient.Lists.Save(ctx, listId, item)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when api key does not have access to the list", func(t *testing.T) {
listIdNoAccess := requireEnvInt(t, "TEST_LIST_ID_NO_ACCESS")
item := onspring.SaveListItemRequest{
Name: "Integration Test Item",
}
_, err := client.Lists.Save(ctx, listIdNoAccess, item)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 error when the list does not exist", func(t *testing.T) {
item := onspring.SaveListItemRequest{
Name: "Integration Test Item",
}
_, err := client.Lists.Save(ctx, 0, item)
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("Delete", func(t *testing.T) {
t.Run("should delete a list item", func(t *testing.T) {
listId := requireEnvInt(t, "TEST_LIST_ID")
item := onspring.SaveListItemRequest{
Name: "Integration Test Item To Delete",
}
response, err := client.Lists.Save(ctx, listId, item)
if err != nil {
t.Fatalf("Failed to add list item: %v", err)
}
err = client.Lists.Delete(ctx, listId, response.Id)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
t.Run("should return a 401 error when an invalid api key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
listId := requireEnvInt(t, "TEST_LIST_ID")
err := invalidClient.Lists.Delete(ctx, listId, "some-item-id")
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when api key does not have access to the list", func(t *testing.T) {
listIdNoAccess := requireEnvInt(t, "TEST_LIST_ID_NO_ACCESS")
listItemIdNoAccess := requireEnv(t, "TEST_LIST_ITEM_ID_NO_ACCESS")
err := client.Lists.Delete(ctx, listIdNoAccess, listItemIdNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 error when the list does not exist", func(t *testing.T) {
err := client.Lists.Delete(ctx, 0, "a57e3d33-9195-4039-9ac0-c180013b043e")
assertAPIError(t, err, http.StatusNotFound)
})
})
}
+22
View File
@@ -0,0 +1,22 @@
//go:build integration
package onspring_test
import (
"context"
"testing"
)
func TestPingIntegration(t *testing.T) {
loadEnvFile(t)
t.Run("Get should be able to connect to the API", func(t *testing.T) {
client := createClient(t)
err := client.Ping.Get(context.Background())
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
}
+649
View File
@@ -0,0 +1,649 @@
//go:build integration
package onspring_test
import (
"context"
"fmt"
"net/http"
"testing"
"github.com/StevanFreeborn/onspring-api-sdk-go"
)
func TestRecordsIntegration(t *testing.T) {
loadEnvFile(t)
client := createClient(t)
ctx := context.Background()
t.Run("Get", func(t *testing.T) {
t.Run("should get a record", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
record, err := client.Records.Get(ctx, surveyId, recordId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if record.AppId != surveyId {
t.Errorf("Expected appId %d, got %d", surveyId, record.AppId)
}
if record.RecordId != recordId {
t.Errorf("Expected recordId %d, got %d", recordId, record.RecordId)
}
if len(record.FieldData) == 0 {
t.Error("Expected field data to not be empty")
}
for _, field := range record.FieldData {
if field.FieldId == 0 {
t.Error("Expected field id to not be zero")
}
if field.Type == "" {
t.Error("Expected field type to not be empty")
}
}
})
t.Run("should get a record when fieldIds and data format are passed as parameters", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
record, err := client.Records.Get(
ctx,
surveyId,
recordId,
onspring.WithFieldIds([]int{textFieldId}),
onspring.WithRecordDataFormat("Formatted"),
)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if record.AppId != surveyId {
t.Errorf("Expected appId %d, got %d", surveyId, record.AppId)
}
if record.RecordId != recordId {
t.Errorf("Expected recordId %d, got %d", recordId, record.RecordId)
}
if len(record.FieldData) == 0 {
t.Error("Expected field data to not be empty")
}
})
t.Run("should return a 401 error when an invalid API key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
_, err := invalidClient.Records.Get(ctx, surveyId, recordId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 404 error when an invalid record id is used", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
_, err := client.Records.Get(ctx, surveyId, 0)
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("List", func(t *testing.T) {
t.Run("should get records", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
page, err := client.Records.List(ctx, surveyId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber == 0 {
t.Error("Expected page number to not be zero")
}
if page.TotalRecords == 0 {
t.Error("Expected total records to not be zero")
}
if len(page.Items) == 0 {
t.Error("Expected items to not be empty")
}
for _, record := range page.Items {
if record.AppId != surveyId {
t.Errorf("Expected appId %d, got %d", surveyId, record.AppId)
}
if record.RecordId == 0 {
t.Error("Expected recordId to not be zero")
}
}
})
t.Run("should get records when fieldIds, paging information, and data format are passed as parameters", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
page, err := client.Records.List(
ctx,
surveyId,
onspring.WithFieldIds([]int{textFieldId}),
onspring.WithRecordDataFormat("Formatted"),
onspring.WithPaging(onspring.ForPageNumber(1), onspring.WithPageSize(1)),
)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber != 1 {
t.Errorf("Expected page number 1, got %d", page.PageNumber)
}
if page.PageSize != 1 {
t.Errorf("Expected page size 1, got %d", page.PageSize)
}
if len(page.Items) != 1 {
t.Errorf("Expected 1 item, got %d", len(page.Items))
}
})
t.Run("should return a 401 error when an invalid API key is passed", func(t *testing.T) {
invalidClient := createInvalidClient(t)
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
_, err := invalidClient.Records.List(ctx, surveyId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when the api key does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
_, err := client.Records.List(ctx, appIdNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
})
t.Run("ListAll", func(t *testing.T) {
t.Run("should iterate all records for an app", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
var records []onspring.Record
for record, err := range client.Records.ListAll(ctx, surveyId, onspring.WithPaging(onspring.WithPageSize(1))) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
records = append(records, record)
}
if len(records) == 0 {
t.Error("Expected to iterate at least one record")
}
})
})
t.Run("GetMany", func(t *testing.T) {
t.Run("should get records", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
batch, err := client.Records.GetMany(ctx, onspring.GetManyRecordsRequest{
AppId: surveyId,
RecordIds: []int{recordId},
})
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if batch.Count == 0 {
t.Error("Expected count to not be zero")
}
if len(batch.Items) == 0 {
t.Error("Expected items to not be empty")
}
for _, record := range batch.Items {
if record.AppId != surveyId {
t.Errorf("Expected appId %d, got %d", surveyId, record.AppId)
}
if record.RecordId == 0 {
t.Error("Expected recordId to not be zero")
}
}
})
t.Run("should get records when field ids and data format are passed as parameters", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
batch, err := client.Records.GetMany(ctx, onspring.GetManyRecordsRequest{
AppId: surveyId,
RecordIds: []int{recordId},
FieldIds: []int{textFieldId},
DataFormat: "Formatted",
})
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if batch.Count == 0 {
t.Error("Expected count to not be zero")
}
if len(batch.Items) == 0 {
t.Error("Expected items to not be empty")
}
})
t.Run("should return a 400 error if too many record ids are passed", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
ids := make([]int, 101)
for i := range ids {
ids[i] = i + 1
}
_, err := client.Records.GetMany(ctx, onspring.GetManyRecordsRequest{
AppId: surveyId,
RecordIds: ids,
})
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 error if the api key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
_, err := invalidClient.Records.GetMany(ctx, onspring.GetManyRecordsRequest{
AppId: surveyId,
RecordIds: []int{recordId},
})
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error if the user does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
_, err := client.Records.GetMany(ctx, onspring.GetManyRecordsRequest{
AppId: appIdNoAccess,
RecordIds: []int{recordId},
})
assertAPIError(t, err, http.StatusForbidden)
})
})
t.Run("Query", func(t *testing.T) {
t.Run("should return records", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
autoNumberField := requireEnvInt(t, "TEST_SURVEY_AUTO_NUMBER_FIELD")
filter := fmt.Sprintf("%d gt 0", autoNumberField)
page, err := client.Records.Query(ctx, onspring.QueryRecordsRequest{
AppId: surveyId,
Filter: filter,
})
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber == 0 {
t.Error("Expected page number to not be zero")
}
if page.TotalRecords == 0 {
t.Error("Expected total records to not be zero")
}
if len(page.Items) == 0 {
t.Error("Expected items to not be empty")
}
for _, record := range page.Items {
if record.AppId != surveyId {
t.Errorf("Expected appId %d, got %d", surveyId, record.AppId)
}
if record.RecordId == 0 {
t.Error("Expected recordId to not be zero")
}
}
})
t.Run("should return records when data format, paging information, and fields are passed as parameters", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
autoNumberField := requireEnvInt(t, "TEST_SURVEY_AUTO_NUMBER_FIELD")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
filter := fmt.Sprintf("%d gt 0", autoNumberField)
page, err := client.Records.Query(
ctx,
onspring.QueryRecordsRequest{
AppId: surveyId,
Filter: filter,
FieldIds: []int{textFieldId},
DataFormat: "Formatted",
},
onspring.ForPageNumber(1),
onspring.WithPageSize(1),
)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber != 1 {
t.Errorf("Expected page number 1, got %d", page.PageNumber)
}
if page.PageSize != 1 {
t.Errorf("Expected page size 1, got %d", page.PageSize)
}
if len(page.Items) != 1 {
t.Errorf("Expected 1 item, got %d", len(page.Items))
}
})
t.Run("should return a 400 error if page size is invalid", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
autoNumberField := requireEnvInt(t, "TEST_SURVEY_AUTO_NUMBER_FIELD")
filter := fmt.Sprintf("%d gt 0", autoNumberField)
_, err := client.Records.Query(
ctx,
onspring.QueryRecordsRequest{
AppId: surveyId,
Filter: filter,
},
onspring.WithPageSize(1001),
)
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 error if the API key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
autoNumberField := requireEnvInt(t, "TEST_SURVEY_AUTO_NUMBER_FIELD")
filter := fmt.Sprintf("%d gt 0", autoNumberField)
_, err := invalidClient.Records.Query(ctx, onspring.QueryRecordsRequest{
AppId: surveyId,
Filter: filter,
})
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error if the API key does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
autoNumberField := requireEnvInt(t, "TEST_SURVEY_AUTO_NUMBER_FIELD")
filter := fmt.Sprintf("%d gt 0", autoNumberField)
_, err := client.Records.Query(ctx, onspring.QueryRecordsRequest{
AppId: appIdNoAccess,
Filter: filter,
})
assertAPIError(t, err, http.StatusForbidden)
})
})
t.Run("QueryAll", func(t *testing.T) {
t.Run("should iterate all records matching a query", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
autoNumberField := requireEnvInt(t, "TEST_SURVEY_AUTO_NUMBER_FIELD")
filter := fmt.Sprintf("%d gt 0", autoNumberField)
var records []onspring.Record
for record, err := range client.Records.QueryAll(
ctx,
onspring.QueryRecordsRequest{
AppId: surveyId,
Filter: filter,
},
onspring.WithPageSize(1),
) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
records = append(records, record)
}
if len(records) == 0 {
t.Error("Expected to iterate at least one record")
}
})
})
t.Run("Save", func(t *testing.T) {
t.Run("should add a record when no record id is passed", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
response, err := client.Records.Save(ctx, onspring.SaveRecordRequest{
AppId: surveyId,
Fields: map[string]any{
fmt.Sprintf("%d", textFieldId): "integration test record",
},
})
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if response.Id == 0 {
t.Error("Expected record id to not be zero")
}
if response.Warnings == nil {
t.Error("Expected warnings to not be nil")
}
t.Cleanup(func() {
_ = client.Records.Delete(context.Background(), surveyId, response.Id)
})
})
t.Run("should update a record when a record id is passed", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
recordId := addTestRecord(t, client, surveyId, textFieldId)
response, err := client.Records.Save(ctx, onspring.SaveRecordRequest{
AppId: surveyId,
RecordId: &recordId,
Fields: map[string]any{
fmt.Sprintf("%d", textFieldId): "updated integration test record",
},
})
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if response.Id == 0 {
t.Error("Expected record id to not be zero")
}
})
t.Run("should return a 400 error when field data is empty", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
_, err := client.Records.Save(ctx, onspring.SaveRecordRequest{
AppId: surveyId,
Fields: map[string]any{},
})
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 error when the api key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
_, err := invalidClient.Records.Save(ctx, onspring.SaveRecordRequest{
AppId: surveyId,
Fields: map[string]any{
fmt.Sprintf("%d", textFieldId): "test",
},
})
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when the api key does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
_, err := client.Records.Save(ctx, onspring.SaveRecordRequest{
AppId: appIdNoAccess,
Fields: map[string]any{
fmt.Sprintf("%d", textFieldId): "test",
},
})
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 error when the record id is not found", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
recordId := 0
_, err := client.Records.Save(ctx, onspring.SaveRecordRequest{
AppId: surveyId,
RecordId: &recordId,
Fields: map[string]any{
fmt.Sprintf("%d", textFieldId): "test",
},
})
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("Delete", func(t *testing.T) {
t.Run("should delete a record", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
recordId := addTestRecord(t, client, surveyId, textFieldId)
err := client.Records.Delete(ctx, surveyId, recordId)
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
t.Run("should return a 401 error when the API key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
err := invalidClient.Records.Delete(ctx, surveyId, recordId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when the API key does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
recordId := requireEnvInt(t, "TEST_SURVEY_RECORD_ID")
err := client.Records.Delete(ctx, appIdNoAccess, recordId)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 error when the record does not exist", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
err := client.Records.Delete(ctx, surveyId, 0)
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("DeleteMany", func(t *testing.T) {
t.Run("should delete records", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
textFieldId := requireEnvInt(t, "TEST_TEXT_FIELD")
recordId1 := addTestRecord(t, client, surveyId, textFieldId)
recordId2 := addTestRecord(t, client, surveyId, textFieldId)
err := client.Records.DeleteMany(ctx, onspring.DeleteManyRecordsRequest{
AppId: surveyId,
RecordIds: []int{recordId1, recordId2},
})
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
t.Run("should return a 400 error when no record ids are provided", func(t *testing.T) {
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
err := client.Records.DeleteMany(ctx, onspring.DeleteManyRecordsRequest{
AppId: surveyId,
RecordIds: []int{},
})
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 error when an invalid API key is used", func(t *testing.T) {
invalidClient := createInvalidClient(t)
surveyId := requireEnvInt(t, "TEST_SURVEY_ID")
err := invalidClient.Records.DeleteMany(ctx, onspring.DeleteManyRecordsRequest{
AppId: surveyId,
RecordIds: []int{1},
})
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error when the API key does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
err := client.Records.DeleteMany(ctx, onspring.DeleteManyRecordsRequest{
AppId: appIdNoAccess,
RecordIds: []int{1},
})
assertAPIError(t, err, http.StatusForbidden)
})
})
}
+203
View File
@@ -0,0 +1,203 @@
//go:build integration
package onspring_test
import (
"context"
"net/http"
"testing"
"github.com/StevanFreeborn/onspring-api-sdk-go"
)
func TestReportsIntegration(t *testing.T) {
loadEnvFile(t)
client := createClient(t)
ctx := context.Background()
t.Run("Get", func(t *testing.T) {
t.Run("should return a report", func(t *testing.T) {
reportId := requireEnvInt(t, "TEST_REPORT")
report, err := client.Reports.Get(ctx, reportId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if report.Columns == nil {
t.Error("Expected columns to not be nil")
}
if report.Rows == nil {
t.Error("Expected rows to not be nil")
}
for _, row := range report.Rows {
if row.Cells == nil {
t.Error("Expected cells to not be nil")
}
}
})
t.Run("should return report data for a report with chart data when report data is requested", func(t *testing.T) {
reportId := requireEnvInt(t, "TEST_REPORT_WITH_CHART_DATA")
report, err := client.Reports.Get(ctx, reportId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if report.Columns == nil {
t.Error("Expected columns to not be nil")
}
if report.Rows == nil {
t.Error("Expected rows to not be nil")
}
})
t.Run("should return chart data for a report with a chart when chart data is requested", func(t *testing.T) {
reportId := requireEnvInt(t, "TEST_REPORT_WITH_CHART_DATA")
report, err := client.Reports.Get(
ctx,
reportId,
onspring.WithDataFormat("Raw"),
onspring.WithDataType("ChartData"),
)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if report.Columns == nil {
t.Error("Expected columns to not be nil")
}
if report.Rows == nil {
t.Error("Expected rows to not be nil")
}
})
t.Run("should return a 400 error if chart data is requested for a report without chart data", func(t *testing.T) {
reportId := requireEnvInt(t, "TEST_REPORT")
_, err := client.Reports.Get(
ctx,
reportId,
onspring.WithDataFormat("Raw"),
onspring.WithDataType("ChartData"),
)
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 error if the api key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
reportId := requireEnvInt(t, "TEST_REPORT")
_, err := invalidClient.Reports.Get(ctx, reportId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error if the api key does not have access to the report", func(t *testing.T) {
reportIdNoAccess := requireEnvInt(t, "TEST_REPORT_NO_ACCESS")
_, err := client.Reports.Get(ctx, reportIdNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
t.Run("should return a 404 error if the report does not exist", func(t *testing.T) {
_, err := client.Reports.Get(ctx, 0)
assertAPIError(t, err, http.StatusNotFound)
})
})
t.Run("List", func(t *testing.T) {
t.Run("should return a list of reports", func(t *testing.T) {
appId := requireEnvInt(t, "TEST_APP_ID")
page, err := client.Reports.List(ctx, appId)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
if page.PageNumber == 0 {
t.Error("Expected page number to not be zero")
}
if page.TotalRecords == 0 {
t.Error("Expected total records to not be zero")
}
if len(page.Items) == 0 {
t.Error("Expected items to not be empty")
}
for _, report := range page.Items {
if report.Id == 0 {
t.Error("Expected report id to not be zero")
}
if report.AppId == 0 {
t.Error("Expected report appId to not be zero")
}
if report.Name == "" {
t.Error("Expected report name to not be empty")
}
}
})
t.Run("should return a 400 error if page size is invalid", func(t *testing.T) {
appId := requireEnvInt(t, "TEST_APP_ID")
_, err := client.Reports.List(ctx, appId, onspring.WithPageSize(1001))
assertAPIError(t, err, http.StatusBadRequest)
})
t.Run("should return a 401 error if the api key is invalid", func(t *testing.T) {
invalidClient := createInvalidClient(t)
appId := requireEnvInt(t, "TEST_APP_ID")
_, err := invalidClient.Reports.List(ctx, appId)
assertAPIError(t, err, http.StatusUnauthorized)
})
t.Run("should return a 403 error if the api key does not have access to the app", func(t *testing.T) {
appIdNoAccess := requireEnvInt(t, "TEST_APP_ID_NO_ACCESS")
_, err := client.Reports.List(ctx, appIdNoAccess)
assertAPIError(t, err, http.StatusForbidden)
})
})
t.Run("ListAll", func(t *testing.T) {
t.Run("should iterate all reports for an app", func(t *testing.T) {
appId := requireEnvInt(t, "TEST_APP_ID")
var reports []onspring.Report
for report, err := range client.Reports.ListAll(ctx, appId, onspring.WithPageSize(1)) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
reports = append(reports, report)
}
if len(reports) == 0 {
t.Error("Expected to iterate at least one report")
}
})
})
}
+1
View File
@@ -0,0 +1 @@
This is a test attachment.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB