Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions friendly-captcha-sdk-testserver/fixtures/fixture_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package fixtures

import (
"encoding/json"
"testing"

"github.com/guregu/null/v6"
)

type SiteverifyResponse struct {
Success bool `json:"success"`
Data SiteverifyResponseSuccessData `json:"data,omitempty"`
}

type SiteverifyResponseSuccessData struct {
EventID string `json:"event_id"`

Challenge SiteverifyResponseSuccessDataChallenge `json:"challenge"`

RiskIntelligence null.Value[RiskIntelligenceData] `json:"risk_intelligence"`
}

type SiteverifyResponseSuccessDataChallenge struct {
Timestamp string `json:"timestamp"`
Origin string `json:"origin"`
}

type RiskIntelligenceData struct {
// Note: this only contains a subset of the actual API response values.

RiskScores RiskIntelligenceDataRiskScores `json:"risk_scores"`

Client RiskIntelligenceDataClient `json:"client"`
}

type RiskIntelligenceDataRiskScores struct {
Overall uint8 `json:"overall"`
Network uint8 `json:"network"`
Browser uint8 `json:"browser"`
}

type RiskIntelligenceDataClient struct {
// Note: this only contains a subset of the actual API response values.

HeaderUserAgent string `json:"header_user_agent"`
Browser null.Value[RiskIntelligenceDataClientBrowser] `json:"browser"`
}

type RiskIntelligenceDataClientBrowser struct {
// Note: this only contains a subset of the actual API response values.

ID string `json:"id"`
}

func TestFixtures(t *testing.T) {
t.Parallel()

testCases, err := Load("")
if err != nil {
t.Fatalf("Failed to load embedded test cases: %v", err)
}

// For each fixture make sure it has a name, response and expectation.
for i, tc := range testCases.Tests {
if tc.Name == "" {
t.Errorf("Test case %d has an empty name", i)
}
if tc.Response == "" {
t.Errorf("Test case %d (%s) has an empty response", i, tc.Name)
}

// Parse as SiteverifyResponse to ensure it's valid JSON.
var svr SiteverifyResponse
err := json.Unmarshal(tc.SiteverifyResponse, &svr)
if err != nil {
// Some responses are completely invalid JSON (e.g., HTML error pages).
// We only validate the ones that are supposed to be valid JSON.

// We hardcode those that we expect to fail to parse:
invalidJSONCases := map[string]bool{
"bad_response_200": true,
"bad_response_200_strict": true,
"bad_response_500": true,
"bad_response_400_strict": true,
"empty_string_response_200": true,
"empty_string_response_200_strict": true,
}
if !invalidJSONCases[tc.Name] {
t.Errorf("Test case %d (%s) has invalid siteverify_response JSON: %v", i, tc.Name, err)
}
return
}

if !svr.Success { // For non-success cases we don't validate further.
continue
}

ri := svr.Data.RiskIntelligence

// If risk intelligence data is present, ensure it has expected fields.
if ri.Valid {
if ri.V.Client.HeaderUserAgent == "" {
t.Errorf("Test case %d (%s) has risk intelligence data with empty client header_user_agent", i, tc.Name)
}

if ri.V.Client.Browser.Valid {
if ri.V.Client.Browser.V.ID == "" {
t.Errorf("Test case %d (%s) has risk intelligence data with empty browser id", i, tc.Name)
}
}
}

}
}
76 changes: 73 additions & 3 deletions friendly-captcha-sdk-testserver/fixtures/test_cases.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 1,
"version": 2,
"tests": [
{
"name": "success",
Expand All @@ -8,10 +8,12 @@
"siteverify_response": {
"success": true,
"data": {
"event_id": "ev_2b5ec269-2890-4df2-adbd-45be9974131e",
"challenge": {
"timestamp": "2023-08-04T13:01:25Z",
"origin": "https://example.com"
}
},
"risk_intelligence": null
}
},
"siteverify_status_code": 200,
Expand Down Expand Up @@ -172,10 +174,12 @@
"siteverify_response": {
"success": true,
"data": {
"event_id": "ev_720d50fd-1e47-4a2d-bc94-f5eeda259f7b",
"challenge": {
"timestamp": "2023-08-04T13:01:25Z",
"origin": "https://example.com"
}
},
"risk_intelligence": null
}
},
"siteverify_status_code": 200,
Expand Down Expand Up @@ -400,6 +404,72 @@
"was_able_to_verify": false,
"is_client_error": false
}
},
{
"name": "success_with_risk_intelligence",
"response": "dc2fe149-04ce-45e5-a317-41425942abba",
"strict": false,
"siteverify_response": {
"success": true,
"data": {
"event_id": "ev_dc2fe149-04ce-45e5-a317-41425942abba",
"challenge": {
"timestamp": "2023-08-04T13:01:25Z",
"origin": "https://example.com"
},
"risk_intelligence": {
"risk_scores": {
"overall": 3,
"network": 3,
"browser": 2
},
"client": {
"header_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"browser": {
"id": "chrome"
}
}
}
}
},
"siteverify_status_code": 200,
"expectation": {
"should_accept": true,
"was_able_to_verify": true,
"is_client_error": false
}
},
{
"name": "success_with_risk_intelligence_with_null_client_browser",
"response": "c4b0031a-68c1-481e-a40e-fe526b0e0398",
"strict": false,
"siteverify_response": {
"success": true,
"data": {
"event_id": "ev_c4b0031a-68c1-481e-a40e-fe526b0e0398",
"challenge": {
"timestamp": "2023-08-04T13:01:25Z",
"origin": "https://example.com"
},
"risk_intelligence": {
"risk_scores": {
"overall": 1,
"network": 1,
"browser": 1
},
"client": {
"header_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"browser": null
}
}
}
},
"siteverify_status_code": 200,
"expectation": {
"should_accept": true,
"was_able_to_verify": true,
"is_client_error": false
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be an event_id as part of this expectation? and the one above it? maybe it's supposed to be like this but i noticed all the ones you added above have one

}
}
]
}
6 changes: 5 additions & 1 deletion friendly-captcha-sdk-testserver/go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
module github.com/friendlycaptcha/friendly-captcha-sdk-tooling/friendly-captcha-sdk-testserver

go 1.21
go 1.22.12

toolchain go1.24.3

require github.com/alecthomas/kong v0.8.0

require github.com/guregu/null/v6 v6.0.0 // indirect
2 changes: 2 additions & 0 deletions friendly-captcha-sdk-testserver/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s
github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/guregu/null/v6 v6.0.0 h1:N14VRS+4di81i1PXRiprbQJ9EM9gqBa0+KVMeS/QSjQ=
github.com/guregu/null/v6 v6.0.0/go.mod h1:hrMIhIfrOZeLPZhROSn149tpw2gHkidAqxoXNyeX3iQ=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
9 changes: 5 additions & 4 deletions friendly-captcha-sdk-testserver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import (
// Usage: go run main.go serve --port 1090 --tests ./test_cases.json
// Or just use the defaults: go run main.go serve

const defaultSiteverifyEndpoint = "/api/v2/captcha/siteverify"
const defaultTestsJSONEndpoint = "/api/v1/tests"
const (
defaultSiteverifyEndpoint = "/api/v2/captcha/siteverify"
defaultTestsJSONEndpoint = "/api/v1/tests"
)

var CLI struct {
Serve struct {
Expand All @@ -36,7 +38,6 @@ func main() {
default:
panic(ctx.Command())
}

}

func serve(port int, testsPath string) {
Expand All @@ -45,7 +46,7 @@ func serve(port int, testsPath string) {
panic(err)
}

if tf.Version != 1 {
if tf.Version != 2 {
panic("Unsupported test file version")
}

Expand Down
4 changes: 3 additions & 1 deletion friendly-captcha-sdk-testserver/model/model.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package model

import "encoding/json"
import (
"encoding/json"
)

// What the SDK should conclude from the API response.
type TestCaseExpectation struct {
Expand Down
Loading