Skip to content

Commit fa5b5f4

Browse files
authored
Merge pull request #49 from robmorgan/claude/issue-48-20250724-0710
feat: add HTTP request support for API testing
2 parents c63270d + 2295f61 commit fa5b5f4

File tree

21 files changed

+1081
-72
lines changed

21 files changed

+1081
-72
lines changed

.github/workflows/golangci-lint.yml

Lines changed: 0 additions & 27 deletions
This file was deleted.

.github/workflows/test.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ jobs:
1919
env:
2020
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
2121

22+
- name: Start httpbin
23+
run: |
24+
docker run -d --name httpbin -p 8000:80 kennethreitz/httpbin
25+
# Wait for httpbin to be ready
26+
timeout 30 bash -c 'until curl -f http://localhost:8000/status/200; do sleep 1; done'
27+
2228
- name: Install Terraform
2329
uses: hashicorp/setup-terraform@v3
2430
with:
@@ -36,3 +42,9 @@ jobs:
3642
go test -v ./...
3743
env:
3844
INFRASPEC_TELEMETRY_DISABLED: "1"
45+
46+
- name: Cleanup httpbin
47+
if: always()
48+
run: |
49+
docker stop httpbin || true
50+
docker rm httpbin || true

CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ Use these scopes when relevant:
113113

114114
## Architecture Guidelines
115115

116+
## Adding New Assertion Functions
117+
1. Create provider specific assertion functions below `pkg/assertions`. (e.g Create AWS service-specific assertion functions in `pkg/assertions/aws`).
118+
2. All assertion function names should begin with `Assert`.
119+
116120
### Adding New AWS Cloud Services
117121
1. Create AWS service-specific assertion functions in `pkg/assertions/aws/`
118122
2. Add corresponding step definitions in `pkg/steps/aws/`

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ fmt: tidy ## tidy, format and imports
2525
goimports -w `find . -type f -name '*.go' -not -path "./vendor/*"`
2626
gci write --skip-generated -s standard -s default -s "prefix(github.com/robmorgan/infraspec)" .
2727

28+
.PHONY: test
29+
test: ## run tests
30+
go test -v ./...
31+
2832
.PHONY: go-test-cover
2933
go-test-cover: ## run test & generate coverage
3034
@printf $(COLOR) "Running test with coverage..."

examples/http/test-file.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
This is a test file for HTTP upload testing.
2+
It contains sample content to verify file upload functionality.
3+
4+
UUID: 191152a9-0bd6-4db0-999d-12787295f1ec
5+
Type: document
6+
Status: test

features/http/api_tests.feature

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Feature: API Testing Example
2+
As a DevOps Engineer
3+
I want to test my API endpoints
4+
So that I can ensure they are working correctly after deployment
5+
6+
Scenario: Test authentication endpoint
7+
Given I have a HTTP endpoint at "http://localhost:8000/basic-auth/testuser/testpass"
8+
And I set the headers to
9+
| Name | Value |
10+
| Content-Type | application/json |
11+
And I set basic auth credentials with username "testuser" and password "testpass"
12+
When I send a GET request
13+
Then the HTTP response status should be 200
14+
And the HTTP response should be valid JSON
15+
And the HTTP response should contain "authenticated"
16+
17+
Scenario: Test protected endpoint with authentication
18+
Given I have a HTTP endpoint at "http://localhost:8000/bearer"
19+
And I set the headers to
20+
| Name | Value |
21+
| Authorization | Bearer test-token |
22+
When I send a GET request
23+
Then the HTTP response status should be 200
24+
And the HTTP response should be valid JSON
25+
And the HTTP response should contain "token"
26+
27+
Scenario: Test file upload endpoint
28+
Given I have a HTTP endpoint at "http://localhost:8000/post"
29+
And I have a file "../../examples/http/test-file.txt" as field "file"
30+
And I set content type to "multipart/form-data"
31+
And I set the form data to:
32+
| Name | Value |
33+
| category | document |
34+
| userId | test-user |
35+
When I send a POST request
36+
Then the HTTP response status should be 200
37+
And the HTTP response should be valid JSON
38+
And the HTTP response should contain "191152a9-0bd6-4db0-999d-12787295f1ec"
39+
40+
Scenario: Test API error handling
41+
Given I have a HTTP endpoint at "http://localhost:8000/status/404"
42+
When I send a GET request
43+
Then the HTTP response status should be 404
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
Feature: HTTP Requests
2+
As a DevOps Engineer
3+
I want to test HTTP endpoints
4+
So that I can validate API functionality and infrastructure
5+
6+
Scenario: Test basic GET request
7+
Given I have a HTTP endpoint at "http://localhost:8000/get"
8+
When I make a GET request
9+
Then the HTTP response status should be 200
10+
11+
Scenario: Test GET request with JSON response
12+
Given I have a HTTP endpoint at "http://localhost:8000/json"
13+
When I make a GET request
14+
Then the HTTP response status should be 200
15+
And the response should be valid JSON
16+
17+
Scenario: Test POST request with status assertion
18+
Given I have a HTTP endpoint at "http://localhost:8000/post"
19+
When I make a POST request
20+
Then the HTTP response status should be 200
21+
22+
Scenario: Test response content validation
23+
Given I have a HTTP endpoint at "http://localhost:8000/user-agent"
24+
When I make a GET request
25+
Then the HTTP response should contain "user-agent"
26+
27+
Scenario: Test custom headers
28+
Given I have a HTTP endpoint at "http://localhost:8000/headers"
29+
And I set the headers to
30+
| Name | Value |
31+
| Authorization | Bearer test-token |
32+
| Content-Type | application/json |
33+
When I make a GET request
34+
Then the HTTP response status should be 200
35+
36+
Scenario: Test POST with body and headers
37+
Given I have a HTTP endpoint at "http://localhost:8000/post"
38+
And I set the headers to
39+
| Name | Value |
40+
| Content-Type | application/json |
41+
And I set the request body to "test data"
42+
When I make a POST request
43+
Then the HTTP response status should be 200
44+
And the HTTP response should contain "test data"
45+
46+
Scenario: Test response header validation
47+
Given I have a HTTP endpoint at "http://localhost:8000/response-headers?Content-Type=application/json"
48+
When I make a GET request
49+
Then the HTTP response status should be 200
50+
And the HTTP response header "Content-Type" should be "application/json"
51+
52+
Scenario: Test file upload
53+
Given I have a HTTP endpoint at "http://localhost:8000/post"
54+
And I have a file "../../examples/http/test-file.txt" as field "file"
55+
When I make a POST request
56+
Then the HTTP response status should be 200
57+
58+
Scenario: Test file upload with form data
59+
Given I have a HTTP endpoint at "http://localhost:8000/post"
60+
And I have a file "../../examples/http/test-file.txt" as field "file"
61+
And I set content type to "multipart/form-data"
62+
And I set the form data to:
63+
| Name | Value |
64+
| uuid | 191152a9-0bd6-4db0-999d-12787295f1ec |
65+
| type | document |
66+
When I make a POST request
67+
Then the HTTP response status should be 200
68+
69+
Scenario: Test multiple response validations
70+
Given I have a HTTP endpoint at "http://localhost:8000/json"
71+
When I make a GET request
72+
Then the HTTP response status should be 200
73+
And the HTTP response should be valid JSON
74+
And the HTTP response should contain "slideshow"

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ require (
1414
github.com/aws/aws-sdk-go-v2/service/ssm v1.59.3
1515
github.com/aws/aws-sdk-go-v2/service/sts v1.34.1
1616
github.com/charmbracelet/lipgloss v1.1.0
17-
github.com/cli/safeexec v1.0.1
1817
github.com/cucumber/godog v0.15.1
1918
github.com/denisbrodbeck/machineid v1.0.1
2019
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0G
5858
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
5959
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
6060
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
61-
github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00=
62-
github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
6361
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
6462
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
6563
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=

internal/contexthelpers/helpers.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,35 @@ import (
66

77
"github.com/robmorgan/infraspec/internal/config"
88
"github.com/robmorgan/infraspec/pkg/assertions"
9+
"github.com/robmorgan/infraspec/pkg/httphelpers"
910
"github.com/robmorgan/infraspec/pkg/iacprovisioner"
1011
)
1112

12-
// ConfigCtxKey is the key used to store the configuration in the context.Context.
13+
// ConfigCtxKey is the key used to store the configuration in context.Context.
1314
type ConfigCtxKey struct{}
1415

15-
// TFOptionsCtxKey is the key used to store the Terraform options in the context.Context.
16+
// TFOptionsCtxKey is the key used to store the Terraform options in context.Context.
1617
type TFOptionsCtxKey struct{}
1718

18-
// AwsRegionCtxKey is the key used to store the AWS region in the context.Context.
19+
// AwsRegionCtxKey is the key used to store the AWS region in context.Context.
1920
type AwsRegionCtxKey struct{}
2021

21-
// RDSDBInstanceIDCtxKey is the key used to store the RDS DB instance ID in the context.Context.
22+
// RDSDBInstanceIDCtxKey is the key used to store the RDS DB instance ID in context.Context.
2223
type RDSDBInstanceIDCtxKey struct{}
2324

24-
// TerraformHasAppliedCtxKey is the key used to store the Terraform has applied flag in the context.Context.
25+
// TerraformHasAppliedCtxKey is the key used to store the Terraform has applied flag in context.Context.
2526
type TerraformHasAppliedCtxKey struct{}
2627

27-
// AssertionsCtxKey is the key used to store the available assertions in the context.Context.
28+
// HttpRequestOptionsCtxKey is the key used to the store the Http Request options in context.Context.
29+
type HttpRequestOptionsCtxKey struct{}
30+
31+
// HttpResponseCtxKey is the key used to store the HTTP response in context.Context.
32+
type HttpResponseCtxKey struct{}
33+
34+
// AssertionsCtxKey is the key used to store the available assertions in context.Context.
2835
type AssertionsCtxKey struct{}
2936

30-
// UriCtxKey is the key used to store the scenario URI in the context.Context.
37+
// UriCtxKey is the key used to store the scenario URI in context.Context.
3138
type UriCtxKey struct{}
3239

3340
// GetAsserter returns the asserter for the given provider.
@@ -80,6 +87,22 @@ func GetIacProvisionerOptions(ctx context.Context) *iacprovisioner.Options {
8087
return opts
8188
}
8289

90+
func GetHttpRequestOptions(ctx context.Context) *httphelpers.HttpRequestOptions {
91+
opts, exists := ctx.Value(HttpRequestOptionsCtxKey{}).(*httphelpers.HttpRequestOptions)
92+
if !exists {
93+
return nil
94+
}
95+
return opts
96+
}
97+
98+
func GetHttpResponse(ctx context.Context) *httphelpers.HttpResponse {
99+
resp, exists := ctx.Value(HttpResponseCtxKey{}).(*httphelpers.HttpResponse)
100+
if !exists {
101+
return nil
102+
}
103+
return resp
104+
}
105+
83106
// SetAwsRegion sets the AWS region in the context.
84107
func SetAwsRegion(ctx context.Context, region string) context.Context {
85108
return context.WithValue(ctx, AwsRegionCtxKey{}, region)

0 commit comments

Comments
 (0)