@@ -18,46 +18,64 @@ import (
1818
1919var ctx = context .Background ()
2020
21- // mockPardotClientImpl is a mock implementation of PardotClient.
22- type mockPardotClientImpl struct {
21+ var _ SalesforceClient = (* mockSalesforceClientImpl )(nil )
22+
23+ // mockSalesforceClientImpl is a mock implementation of PardotClient.
24+ type mockSalesforceClientImpl struct {
25+ SalesforceClient
26+
2327 sync.Mutex
2428 CreatedContacts []string
29+ CreatedCases []Case
2530}
2631
27- // newMockPardotClientImpl returns a MockPardotClientImpl, implementing the
28- // PardotClient interface. Both refer to the same instance, with the interface
29- // for mock interaction and the struct for state inspection and modification.
30- func newMockPardotClientImpl () * mockPardotClientImpl {
31- return & mockPardotClientImpl {
32- CreatedContacts : []string {},
33- }
32+ // newMockSalesforceClientImpl returns a mockSalesforceClientImpl, which implements
33+ // the PardotClient interface. It returns the underlying concrete type, so callers
34+ // have access to its struct members and helper methods.
35+ func newMockSalesforceClientImpl () * mockSalesforceClientImpl {
36+ return & mockSalesforceClientImpl {}
3437}
3538
3639// SendContact adds an email to CreatedContacts.
37- func (m * mockPardotClientImpl ) SendContact (email string ) error {
40+ func (m * mockSalesforceClientImpl ) SendContact (email string ) error {
3841 m .Lock ()
42+ defer m .Unlock ()
3943 m .CreatedContacts = append (m .CreatedContacts , email )
40- m .Unlock ()
4144 return nil
4245}
4346
44- func (m * mockPardotClientImpl ) getCreatedContacts () []string {
47+ func (m * mockSalesforceClientImpl ) getCreatedContacts () []string {
4548 m .Lock ()
4649 defer m .Unlock ()
4750
4851 // Return a copy to avoid race conditions.
4952 return slices .Clone (m .CreatedContacts )
5053}
5154
52- // setup creates a new ExporterImpl, a MockPardotClientImpl, and the start and
55+ func (m * mockSalesforceClientImpl ) SendCase (payload Case ) error {
56+ m .Lock ()
57+ defer m .Unlock ()
58+ m .CreatedCases = append (m .CreatedCases , payload )
59+ return nil
60+ }
61+
62+ func (m * mockSalesforceClientImpl ) getCreatedCases () []Case {
63+ m .Lock ()
64+ defer m .Unlock ()
65+
66+ // Return a copy to avoid race conditions.
67+ return slices .Clone (m .CreatedCases )
68+ }
69+
70+ // setup creates a new ExporterImpl, a mockSalesForceClientImpl, and the start and
5371// cleanup functions for the ExporterImpl. Call start() to begin processing the
5472// ExporterImpl queue and cleanup() to drain and shutdown. If start() is called,
5573// cleanup() must be called.
56- func setup () (* ExporterImpl , * mockPardotClientImpl , func (), func ()) {
57- mockClient := newMockPardotClientImpl ()
58- exporter := NewExporterImpl (mockClient , nil , 1000000 , 5 , metrics .NoopRegisterer , blog .NewMock ())
74+ func setup () (* ExporterImpl , * mockSalesforceClientImpl , func (), func ()) {
75+ clientImpl := newMockSalesforceClientImpl ()
76+ exporter := NewExporterImpl (clientImpl , nil , 1000000 , 5 , metrics .NoopRegisterer , blog .NewMock ())
5977 daemonCtx , cancel := context .WithCancel (context .Background ())
60- return exporter , mockClient ,
78+ return exporter , clientImpl ,
6179 func () { exporter .Start (daemonCtx ) },
6280 func () {
6381 cancel ()
@@ -134,7 +152,9 @@ func TestSendContactsQueueDrains(t *testing.T) {
134152 test .AssertEquals (t , 100 , len (clientImpl .getCreatedContacts ()))
135153}
136154
137- type mockAlwaysFailClient struct {}
155+ type mockAlwaysFailClient struct {
156+ mockSalesforceClientImpl
157+ }
138158
139159func (m * mockAlwaysFailClient ) SendContact (email string ) error {
140160 return fmt .Errorf ("simulated failure" )
@@ -166,8 +186,8 @@ func TestSendContactDeduplication(t *testing.T) {
166186 t .Parallel ()
167187
168188 cache := NewHashedEmailCache (1000 , metrics .NoopRegisterer )
169- mockClient := newMockPardotClientImpl ()
170- exporter := NewExporterImpl (mockClient , cache , 1000000 , 5 , metrics .NoopRegisterer , blog .NewMock ())
189+ clientImpl := newMockSalesforceClientImpl ()
190+ exporter := NewExporterImpl (clientImpl , cache , 1000000 , 5 , metrics .NoopRegisterer , blog .NewMock ())
171191
172192 daemonCtx , cancel := context .WithCancel (context .Background ())
173193 exporter .Start (daemonCtx )
@@ -181,7 +201,7 @@ func TestSendContactDeduplication(t *testing.T) {
181201 cancel ()
182202 exporter .Drain ()
183203
184- contacts := mockClient .getCreatedContacts ()
204+ contacts := clientImpl .getCreatedContacts ()
185205 test .AssertEquals (t , 1 , len (contacts ))
186206 test .
AssertEquals (
t ,
"[email protected] " ,
contacts [
0 ])
187207
@@ -222,3 +242,68 @@ func TestSendContactErrorRemovesFromCache(t *testing.T) {
222242 // Check that the error counter was incremented.
223243 test .AssertMetricWithLabelsEquals (t , exporter .pardotErrorCounter , prometheus.Labels {}, 1 )
224244}
245+
246+ func TestSendCase (t * testing.T ) {
247+ t .Parallel ()
248+
249+ clientImpl := newMockSalesforceClientImpl ()
250+ exporter := NewExporterImpl (clientImpl , nil , 1000000 , 5 , metrics .NoopRegisterer , blog .NewMock ())
251+
252+ _ , err := exporter .SendCase (ctx , & emailpb.SendCaseRequest {
253+ Origin : "Web" ,
254+ Subject : "Some Override" ,
255+ Description : "Please review" ,
256+ ContactEmail :
"[email protected] " ,
257+ })
258+ test .AssertNotError (t , err , "SendCase should succeed" )
259+
260+ got := clientImpl .getCreatedCases ()
261+ if len (got ) != 1 {
262+ t .Fatalf ("expected 1 case, got %d" , len (got ))
263+ }
264+ test .AssertEquals (t , got [0 ].Origin , "Web" )
265+ test .AssertEquals (t , got [0 ].Subject , "Some Override" )
266+ test .AssertEquals (t , got [0 ].Description , "Please review" )
267+ test .
AssertEquals (
t ,
got [
0 ].
ContactEmail ,
"[email protected] " )
268+ test .AssertMetricWithLabelsEquals (t , exporter .caseErrorCounter , prometheus.Labels {}, 0 )
269+ }
270+
271+ type mockAlwaysFailCaseClient struct {
272+ mockSalesforceClientImpl
273+ }
274+
275+ func (m * mockAlwaysFailCaseClient ) SendCase (payload Case ) error {
276+ return fmt .Errorf ("oops, lol" )
277+ }
278+
279+ func TestSendCaseClientErrorIncrementsMetric (t * testing.T ) {
280+ t .Parallel ()
281+
282+ mockClient := & mockAlwaysFailCaseClient {}
283+ exporter := NewExporterImpl (mockClient , nil , 1000000 , 5 , metrics .NoopRegisterer , blog .NewMock ())
284+
285+ _ , err := exporter .SendCase (ctx , & emailpb.SendCaseRequest {
286+ Origin : "Web" ,
287+ Subject : "Some Override" ,
288+ Description : "Please review" ,
289+ ContactEmail :
"[email protected] " ,
290+ })
291+ test .AssertError (t , err , "SendCase should return error on client failure" )
292+ test .AssertMetricWithLabelsEquals (t , exporter .caseErrorCounter , prometheus.Labels {}, 1 )
293+ }
294+
295+ func TestSendCaseMissingOriginValidation (t * testing.T ) {
296+ t .Parallel ()
297+
298+ clientImpl := newMockSalesforceClientImpl ()
299+ exporter := NewExporterImpl (clientImpl , nil , 1000000 , 5 , metrics .NoopRegisterer , blog .NewMock ())
300+
301+ _ , err := exporter .SendCase (ctx , & emailpb.SendCaseRequest {Subject : "No origin in this one, d00d" })
302+ test .AssertError (t , err , "SendCase should fail validation when Origin is missing" )
303+
304+ got := clientImpl .getCreatedCases ()
305+ if len (got ) != 0 {
306+ t .Errorf ("expected 0 cases due to validation error, got %d" , len (got ))
307+ }
308+ test .AssertMetricWithLabelsEquals (t , exporter .caseErrorCounter , prometheus.Labels {}, 0 )
309+ }
0 commit comments