Skip to content

Commit 0ad73e5

Browse files
AchoArnoldCopilot
andcommitted
feat(tests): add integration test runner with send and receive tests
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 29944e5 commit 0ad73e5

4 files changed

Lines changed: 177 additions & 0 deletions

File tree

tests/go.mod

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module github.com/NdoleStudio/httpsms/tests
2+
3+
go 1.25.0
4+
5+
require github.com/stretchr/testify v1.11.1
6+
7+
require (
8+
github.com/davecgh/go-spew v1.1.1 // indirect
9+
github.com/pmezard/go-difflib v1.0.0 // indirect
10+
gopkg.in/yaml.v3 v3.0.1 // indirect
11+
)

tests/go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
6+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
7+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
8+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

tests/helpers_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package tests
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"net/http"
8+
"testing"
9+
"time"
10+
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
const (
15+
apiBaseURL = "http://localhost:8000"
16+
userAPIKey = "test-user-api-key"
17+
phoneAPIKey = "pk_test-phone-api-key"
18+
testPhone = "+18005550199"
19+
testContact = "+18005550100"
20+
)
21+
22+
func apiClient() *http.Client {
23+
return &http.Client{Timeout: 10 * time.Second}
24+
}
25+
26+
func doRequest(t *testing.T, method, url string, body io.Reader, apiKey string) *http.Response {
27+
t.Helper()
28+
req, err := http.NewRequest(method, url, body)
29+
require.NoError(t, err)
30+
req.Header.Set("Content-Type", "application/json")
31+
req.Header.Set("x-api-key", apiKey)
32+
33+
resp, err := apiClient().Do(req)
34+
require.NoError(t, err)
35+
return resp
36+
}
37+
38+
func pollMessageStatus(t *testing.T, messageID, targetStatus string, timeout time.Duration) map[string]interface{} {
39+
t.Helper()
40+
deadline := time.Now().Add(timeout)
41+
42+
for time.Now().Before(deadline) {
43+
url := fmt.Sprintf("%s/v1/messages/%s", apiBaseURL, messageID)
44+
resp := doRequest(t, "GET", url, nil, userAPIKey)
45+
46+
body, err := io.ReadAll(resp.Body)
47+
resp.Body.Close()
48+
require.NoError(t, err)
49+
50+
if resp.StatusCode == http.StatusOK {
51+
var result map[string]interface{}
52+
require.NoError(t, json.Unmarshal(body, &result))
53+
54+
data, ok := result["data"].(map[string]interface{})
55+
if ok && data["status"] == targetStatus {
56+
return data
57+
}
58+
}
59+
60+
time.Sleep(500 * time.Millisecond)
61+
}
62+
63+
t.Fatalf("message %s did not reach status %q within %v", messageID, targetStatus, timeout)
64+
return nil
65+
}

tests/integration_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package tests
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"testing"
10+
"time"
11+
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestSendSMS_E2E(t *testing.T) {
17+
sendPayload := map[string]interface{}{
18+
"from": testPhone,
19+
"to": testContact,
20+
"content": "Hello from integration test",
21+
}
22+
body, _ := json.Marshal(sendPayload)
23+
24+
url := fmt.Sprintf("%s/v1/messages/send", apiBaseURL)
25+
resp := doRequest(t, "POST", url, bytes.NewReader(body), userAPIKey)
26+
defer resp.Body.Close()
27+
28+
respBody, err := io.ReadAll(resp.Body)
29+
require.NoError(t, err)
30+
require.Equal(t, http.StatusOK, resp.StatusCode, "send response: %s", string(respBody))
31+
32+
var sendResult map[string]interface{}
33+
require.NoError(t, json.Unmarshal(respBody, &sendResult))
34+
data := sendResult["data"].(map[string]interface{})
35+
messageID := data["id"].(string)
36+
require.NotEmpty(t, messageID)
37+
38+
t.Logf("sent message with ID: %s", messageID)
39+
40+
message := pollMessageStatus(t, messageID, "delivered", 30*time.Second)
41+
42+
assert.Equal(t, "delivered", message["status"])
43+
assert.Equal(t, testPhone, message["owner"])
44+
assert.Equal(t, testContact, message["contact"])
45+
assert.Equal(t, "Hello from integration test", message["content"])
46+
}
47+
48+
func TestReceiveSMS_E2E(t *testing.T) {
49+
receivePayload := map[string]interface{}{
50+
"from": testContact,
51+
"to": testPhone,
52+
"content": "Hi there from integration test",
53+
"encrypted": false,
54+
"sim": "SIM1",
55+
"timestamp": time.Now().UTC().Format(time.RFC3339),
56+
}
57+
body, _ := json.Marshal(receivePayload)
58+
59+
url := fmt.Sprintf("%s/v1/messages/receive", apiBaseURL)
60+
resp := doRequest(t, "POST", url, bytes.NewReader(body), phoneAPIKey)
61+
defer resp.Body.Close()
62+
63+
respBody, err := io.ReadAll(resp.Body)
64+
require.NoError(t, err)
65+
require.Equal(t, http.StatusOK, resp.StatusCode, "receive response: %s", string(respBody))
66+
67+
var receiveResult map[string]interface{}
68+
require.NoError(t, json.Unmarshal(respBody, &receiveResult))
69+
data := receiveResult["data"].(map[string]interface{})
70+
messageID := data["id"].(string)
71+
require.NotEmpty(t, messageID)
72+
73+
t.Logf("received message with ID: %s", messageID)
74+
75+
getURL := fmt.Sprintf("%s/v1/messages/%s", apiBaseURL, messageID)
76+
getResp := doRequest(t, "GET", getURL, nil, userAPIKey)
77+
defer getResp.Body.Close()
78+
79+
getBody, err := io.ReadAll(getResp.Body)
80+
require.NoError(t, err)
81+
require.Equal(t, http.StatusOK, getResp.StatusCode)
82+
83+
var getMessage map[string]interface{}
84+
require.NoError(t, json.Unmarshal(getBody, &getMessage))
85+
messageData := getMessage["data"].(map[string]interface{})
86+
87+
assert.Equal(t, "received", messageData["status"])
88+
assert.Equal(t, testPhone, messageData["owner"])
89+
assert.Equal(t, testContact, messageData["contact"])
90+
assert.Equal(t, "Hi there from integration test", messageData["content"])
91+
}

0 commit comments

Comments
 (0)