Repository: mailgun/mailgun-go
Pull request #276 (2021-12-15 14:47:27)

Partially add mocks for unsubscribes endpoints and rewrite unsubscribes test to use them.
SSIA

It's not perfect, but I hope you're okay with the changes!
If it's an unnecessary change, I'll withdraw it.


Patch:
diff --git a/mock.go b/mock.go
index 1b4f36c..656334b 100644
--- a/mock.go
+++ b/mock.go
@@ -41,6 +41,7 @@ type mockServer struct {
 	events           []Event
 	templates        []Template
 	templateVersions map[string][]TemplateVersion
+	unsubscribes     []Unsubscribe
 	webhooks         WebHooksListResponse
 	mutex            sync.Mutex
 }
@@ -93,6 +94,12 @@ func (ms *mockServer) Templates() []Template {
 	return ms.templates
 }
 
+func (ms *mockServer) Unsubscribes() []Unsubscribe {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+	return ms.unsubscribes
+}
+
 // Create a new instance of the mailgun API mock server
 func NewMockServer() MockServer {
 	ms := mockServer{}
@@ -111,6 +118,7 @@ func NewMockServer() MockServer {
 		ms.addWebhookRoutes(r)
 		ms.addTemplateRoutes(r)
 		ms.addTemplateVersionRoutes(r)
+		ms.addUnsubscribesRoutes(r)
 	}(r.PathPrefix("/v3").Subrouter())
 	ms.addValidationRoutes(r)
 
diff --git a/mock_unsubscribes.go b/mock_unsubscribes.go
new file mode 100644
index 0000000..d60fae4
--- /dev/null
+++ b/mock_unsubscribes.go
@@ -0,0 +1,150 @@
+package mailgun
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gorilla/mux"
+)
+
+func (ms *mockServer) addUnsubscribesRoutes(r *mux.Router) {
+	r.HandleFunc("/{domain}/unsubscribes/{address}", ms.getUnsubscribe).Methods(http.MethodGet)
+
+	r.HandleFunc("/{domain}/unsubscribes", ms.createUnsubscribe).Methods(http.MethodPost)
+	r.HandleFunc("/{domain}/unsubscribes/{address}", ms.deleteUnsubscribe).Methods(http.MethodDelete)
+
+	ms.unsubscribes = append(ms.unsubscribes, Unsubscribe{
+		CreatedAt: RFC2822Time(time.Now()),
+		Tags:      []string{"*"},
+		ID:        "1",
+		Address:   "foo@mailgun.test",
+	})
+
+	ms.unsubscribes = append(ms.unsubscribes, Unsubscribe{
+		CreatedAt: RFC2822Time(time.Now()),
+		Tags:      []string{"some", "tag"},
+		ID:        "2",
+		Address:   "alice@example.com",
+	})
+}
+
+func (ms *mockServer) getUnsubscribe(w http.ResponseWriter, r *http.Request) {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+
+	for _, unsubscribe := range ms.unsubscribes {
+		if unsubscribe.Address == mux.Vars(r)["address"] {
+			toJSON(w, unsubscribe)
+			return
+		}
+	}
+	w.WriteHeader(http.StatusNotFound)
+	w.Write([]byte("{\"message\": \"Address not found in unsubscribers table\"}"))
+}
+
+func (ms *mockServer) createUnsubscribe(w http.ResponseWriter, r *http.Request) {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+
+	if r.Header.Get("Content-Type") == "application/json" {
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte("{\"message\": \"Add multiple unsubscribes is not yet implemented\"}"))
+		return
+	}
+
+	if err := r.ParseForm(); err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte(err.Error()))
+		return
+	}
+
+	address := r.FormValue("address")
+	if len(address) == 0 {
+		w.WriteHeader(http.StatusBadRequest)
+		w.Write([]byte("{\"message\": \"Invalid format for parameter address: \"}"))
+		return
+	}
+
+	tag := r.FormValue("tag")
+
+	var addressExist bool
+	for i, unsubscribe := range ms.unsubscribes {
+		if unsubscribe.Address == address {
+			ms.unsubscribes[i].Tags = append(ms.unsubscribes[i].Tags, tag)
+			addressExist = true
+		}
+	}
+
+	if !addressExist {
+		unsubscribe := Unsubscribe{
+			CreatedAt: RFC2822Time(time.Now()),
+			Tags:      []string{tag},
+			Address:   address,
+		}
+		ms.unsubscribes = append(ms.unsubscribes, unsubscribe)
+	}
+
+	toJSON(w, map[string]interface{}{
+		"message": "Address has been added to the unsubscribes table",
+		"address": address,
+	})
+}
+
+func (ms *mockServer) deleteUnsubscribe(w http.ResponseWriter, r *http.Request) {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+
+	if err := r.ParseForm(); err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte(err.Error()))
+		return
+	}
+
+	var addressExist bool
+	for _, unsubscribe := range ms.unsubscribes {
+		if unsubscribe.Address == mux.Vars(r)["address"] {
+			addressExist = true
+		}
+	}
+
+	if !addressExist {
+		toJSON(w, map[string]interface{}{
+			"message": "Address not found in unsubscribers table",
+		})
+		return
+	}
+
+	tag := r.FormValue("tag")
+	if len(tag) == 0 {
+		for i, unsubscribe := range ms.unsubscribes {
+			if unsubscribe.Address != mux.Vars(r)["address"] {
+				continue
+			}
+			ms.unsubscribes = append(ms.unsubscribes[:i], ms.unsubscribes[i+1:len(ms.unsubscribes)]...)
+
+			toJSON(w, map[string]interface{}{
+				"message": "Unsubscribe event has been removed",
+			})
+			return
+		}
+	}
+
+	for i, unsubscribe := range ms.unsubscribes {
+		if unsubscribe.Address != mux.Vars(r)["address"] {
+			continue
+		}
+		for j, t := range ms.unsubscribes[i].Tags {
+			if t != tag {
+				continue
+			}
+			ms.unsubscribes[i].Tags = append(ms.unsubscribes[i].Tags[:j], ms.unsubscribes[i].Tags[j+1:]...)
+			toJSON(w, map[string]interface{}{
+				"message": "Unsubscribe event has been removed",
+			})
+			return
+		}
+	}
+
+	w.WriteHeader(http.StatusNotFound)
+	toJSON(w, map[string]string{"message": "Unsubscribe event for this tag does not exist"})
+}


Test patch:
diff --git a/unsubscribes_test.go b/unsubscribes_test.go
index ecb4a1f..c0d3de0 100644
--- a/unsubscribes_test.go
+++ b/unsubscribes_test.go
@@ -1,4 +1,4 @@
-package mailgun
+package mailgun_test
 
 import (
 	"context"
@@ -6,16 +6,14 @@ import (
 	"testing"
 
 	"github.com/facebookgo/ensure"
+	"github.com/mailgun/mailgun-go/v4"
 )
 
 func TestCreateUnsubscriber(t *testing.T) {
-	if reason := SkipNetworkTest(); reason != "" {
-		t.Skip(reason)
-	}
+	mg := mailgun.NewMailgun(testDomain, testKey)
+	mg.SetAPIBase(server.URL())
 
 	email := randomEmail("unsubcribe", os.Getenv("MG_DOMAIN"))
-	mg, err := NewMailgunFromEnv()
-	ensure.Nil(t, err)
 	ctx := context.Background()
 
 	// Create unsubscription record
@@ -23,11 +21,11 @@ func TestCreateUnsubscriber(t *testing.T) {
 }
 
 func TestCreateUnsubscribes(t *testing.T) {
-	if reason := SkipNetworkTest(); reason != "" {
+	if reason := mailgun.SkipNetworkTest(); reason != "" {
 		t.Skip(reason)
 	}
 
-	unsubscribes := []Unsubscribe{
+	unsubscribes := []mailgun.Unsubscribe{
 		{
 			Address: randomEmail("unsubcribe", os.Getenv("MG_DOMAIN")),
 		},
@@ -36,7 +34,7 @@ func TestCreateUnsubscribes(t *testing.T) {
 			Tags:    []string{"tag1"},
 		},
 	}
-	mg, err := NewMailgunFromEnv()
+	mg, err := mailgun.NewMailgunFromEnv()
 	ensure.Nil(t, err)
 	ctx := context.Background()
 
@@ -45,16 +43,16 @@ func TestCreateUnsubscribes(t *testing.T) {
 }
 
 func TestListUnsubscribes(t *testing.T) {
-	if reason := SkipNetworkTest(); reason != "" {
+	if reason := mailgun.SkipNetworkTest(); reason != "" {
 		t.Skip(reason)
 	}
 
-	mg, err := NewMailgunFromEnv()
+	mg, err := mailgun.NewMailgunFromEnv()
 	ensure.Nil(t, err)
 	ctx := context.Background()
 
 	it := mg.ListUnsubscribes(nil)
-	var page []Unsubscribe
+	var page []mailgun.Unsubscribe
 	for it.Next(ctx, &page) {
 		t.Logf("Received %d unsubscribe records.\n", len(page))
 		if len(page) > 0 {
@@ -68,13 +66,11 @@ func TestListUnsubscribes(t *testing.T) {
 }
 
 func TestGetUnsubscribe(t *testing.T) {
-	if reason := SkipNetworkTest(); reason != "" {
-		t.Skip(reason)
-	}
+	mg := mailgun.NewMailgun(testDomain, testKey)
+	mg.SetAPIBase(server.URL())
 
 	email := randomEmail("unsubcribe", os.Getenv("MG_DOMAIN"))
-	mg, err := NewMailgunFromEnv()
-	ensure.Nil(t, err)
+
 	ctx := context.Background()
 
 	// Create unsubscription record
@@ -89,20 +85,17 @@ func TestGetUnsubscribe(t *testing.T) {
 }
 
 func TestCreateDestroyUnsubscription(t *testing.T) {
-	if reason := SkipNetworkTest(); reason != "" {
-		t.Skip(reason)
-	}
+	mg := mailgun.NewMailgun(testDomain, testKey)
+	mg.SetAPIBase(server.URL())
 
 	email := randomEmail("unsubcribe", os.Getenv("MG_DOMAIN"))
-	mg, err := NewMailgunFromEnv()
-	ensure.Nil(t, err)
 
 	ctx := context.Background()
 
 	// Create unsubscription record
 	ensure.Nil(t, mg.CreateUnsubscribe(ctx, email, "*"))
 
-	_, err = mg.GetUnsubscribe(ctx, email)
+	_, err := mg.GetUnsubscribe(ctx, email)
 	ensure.Nil(t, err)
 	/*t.Logf("Received %d out of %d unsubscribe records.\n", len(us), n)*/