168 lines
4.5 KiB
Go
168 lines
4.5 KiB
Go
//go:build integration
|
|
|
|
package integration
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/eggsampler/acme/v3"
|
|
|
|
"github.com/letsencrypt/boulder/test"
|
|
)
|
|
|
|
// randomDomain creates a random domain name for testing.
|
|
func randomDomain(t *testing.T) string {
|
|
t.Helper()
|
|
|
|
var bytes [4]byte
|
|
_, err := rand.Read(bytes[:])
|
|
if err != nil {
|
|
test.AssertNotError(t, err, "Failed to generate random domain")
|
|
}
|
|
return fmt.Sprintf("%x.mail.com", bytes[:])
|
|
}
|
|
|
|
// getOAuthToken queries the pardot-test-srv for the current OAuth token.
|
|
func getOAuthToken(t *testing.T) string {
|
|
t.Helper()
|
|
|
|
data, err := os.ReadFile("test/secrets/salesforce_client_id")
|
|
test.AssertNotError(t, err, "Failed to read Salesforce client ID")
|
|
clientId := string(data)
|
|
|
|
data, err = os.ReadFile("test/secrets/salesforce_client_secret")
|
|
test.AssertNotError(t, err, "Failed to read Salesforce client secret")
|
|
clientSecret := string(data)
|
|
|
|
httpClient := http.DefaultClient
|
|
resp, err := httpClient.PostForm("http://localhost:9601/services/oauth2/token", url.Values{
|
|
"grant_type": {"client_credentials"},
|
|
"client_id": {strings.TrimSpace(clientId)},
|
|
"client_secret": {strings.TrimSpace(clientSecret)},
|
|
})
|
|
test.AssertNotError(t, err, "Failed to fetch OAuth token")
|
|
test.AssertEquals(t, resp.StatusCode, http.StatusOK)
|
|
defer resp.Body.Close()
|
|
|
|
var response struct {
|
|
AccessToken string `json:"access_token"`
|
|
}
|
|
decoder := json.NewDecoder(resp.Body)
|
|
err = decoder.Decode(&response)
|
|
test.AssertNotError(t, err, "Failed to decode OAuth token")
|
|
return response.AccessToken
|
|
}
|
|
|
|
// getCreatedContacts queries the pardot-test-srv for the list of created
|
|
// contacts.
|
|
func getCreatedContacts(t *testing.T, token string) []string {
|
|
t.Helper()
|
|
|
|
httpClient := http.DefaultClient
|
|
req, err := http.NewRequest("GET", "http://localhost:9602/contacts", nil)
|
|
test.AssertNotError(t, err, "Failed to create request")
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
resp, err := httpClient.Do(req)
|
|
test.AssertNotError(t, err, "Failed to query contacts")
|
|
test.AssertEquals(t, resp.StatusCode, http.StatusOK)
|
|
defer resp.Body.Close()
|
|
|
|
var got struct {
|
|
Contacts []string `json:"contacts"`
|
|
}
|
|
decoder := json.NewDecoder(resp.Body)
|
|
err = decoder.Decode(&got)
|
|
test.AssertNotError(t, err, "Failed to decode contacts")
|
|
return got.Contacts
|
|
}
|
|
|
|
// assertAllContactsReceived waits for the expected contacts to be received by
|
|
// pardot-test-srv. Retries every 50ms for up to 2 seconds and fails if the
|
|
// expected contacts are not received.
|
|
func assertAllContactsReceived(t *testing.T, token string, expect []string) {
|
|
t.Helper()
|
|
|
|
for attempt := range 20 {
|
|
if attempt > 0 {
|
|
time.Sleep(50 * time.Millisecond)
|
|
}
|
|
got := getCreatedContacts(t, token)
|
|
|
|
allFound := true
|
|
for _, e := range expect {
|
|
if !slices.Contains(got, e) {
|
|
allFound = false
|
|
break
|
|
}
|
|
}
|
|
if allFound {
|
|
break
|
|
}
|
|
if attempt >= 19 {
|
|
t.Fatalf("Expected contacts=%v to be received by pardot-test-srv, got contacts=%v", expect, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestContactsSentForNewAccount tests that contacts are dispatched to
|
|
// pardot-test-srv by the email-exporter when a new account is created.
|
|
func TestContactsSentForNewAccount(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if os.Getenv("BOULDER_CONFIG_DIR") != "test/config-next" {
|
|
t.Skip("Test requires WFE to be configured to use email-exporter")
|
|
}
|
|
|
|
token := getOAuthToken(t)
|
|
domain := randomDomain(t)
|
|
|
|
tests := []struct {
|
|
name string
|
|
contacts []string
|
|
expectContacts []string
|
|
}{
|
|
{
|
|
name: "Single email",
|
|
contacts: []string{"mailto:example@" + domain},
|
|
expectContacts: []string{"example@" + domain},
|
|
},
|
|
{
|
|
name: "Multiple emails",
|
|
contacts: []string{"mailto:example1@" + domain, "mailto:example2@" + domain},
|
|
expectContacts: []string{"example1@" + domain, "example2@" + domain},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
c, err := acme.NewClient("http://boulder.service.consul:4001/directory")
|
|
if err != nil {
|
|
t.Fatalf("failed to connect to acme directory: %s", err)
|
|
}
|
|
|
|
acctKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatalf("failed to generate account key: %s", err)
|
|
}
|
|
|
|
_, err = c.NewAccount(acctKey, false, true, tt.contacts...)
|
|
test.AssertNotError(t, err, "Failed to create initial account with contacts")
|
|
assertAllContactsReceived(t, token, tt.expectContacts)
|
|
})
|
|
}
|
|
}
|