From d0afd0138d39efdfd8da49c7cf5b299d8a07f667 Mon Sep 17 00:00:00 2001 From: "Derrick J. Wippler" Date: Sat, 5 Jan 2019 23:00:28 -0600 Subject: [PATCH] mailing list tests now use the mock server --- common_test.go | 25 +++ domains.go | 6 +- domains_test.go | 16 +- limits_test.go | 2 +- mailgun.go | 2 +- mailing_lists.go | 26 +-- mailing_lists_test.go | 111 +++++-------- members.go | 30 ++-- mock.go | 51 +++++- mock_domains.go | 4 +- mock_mailing_list.go | 358 ++++++++++++++++++++++++++++++++++++------ 11 files changed, 468 insertions(+), 163 deletions(-) create mode 100644 common_test.go diff --git a/common_test.go b/common_test.go new file mode 100644 index 00000000..5c4481e8 --- /dev/null +++ b/common_test.go @@ -0,0 +1,25 @@ +package mailgun_test + +import ( + "crypto/rand" + "fmt" + "strings" +) + +// randomString generates a string of given length, but random content. +// All content will be within the ASCII graphic character set. +// (Implementation from Even Shaw's contribution on +// http://stackoverflow.com/questions/12771930/what-is-the-fastest-way-to-generate-a-long-random-string-in-go). +func randomString(n int, prefix string) string { + const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + var bytes = make([]byte, n) + rand.Read(bytes) + for i, b := range bytes { + bytes[i] = alphanum[b%byte(len(alphanum))] + } + return prefix + string(bytes) +} + +func randomEmail(prefix, domain string) string { + return strings.ToLower(fmt.Sprintf("%s@%s", randomString(20, prefix), domain)) +} diff --git a/domains.go b/domains.go index 719dd7b3..4552fe9c 100644 --- a/domains.go +++ b/domains.go @@ -115,9 +115,9 @@ func (mg *MailgunImpl) GetDomain(domain string) (Domain, []DNSRecord, []DNSRecor r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain) r.setClient(mg.Client()) r.setBasicAuth(basicAuthUser, mg.APIKey()) - var envelope domainResponse - err := getResponseFromJSON(r, &envelope) - return envelope.Domain, envelope.ReceivingDNSRecords, envelope.SendingDNSRecords, err + var resp domainResponse + err := getResponseFromJSON(r, &resp) + return resp.Domain, resp.ReceivingDNSRecords, resp.SendingDNSRecords, err } // CreateDomain instructs Mailgun to create a new domain for your account. diff --git a/domains_test.go b/domains_test.go index 463dbfec..9b894f3d 100644 --- a/domains_test.go +++ b/domains_test.go @@ -9,7 +9,7 @@ import ( ) const ( - sampleDomain = "samples.mailgun.org" + testDomain = "mailgun.test" ) func TestGetDomains(t *testing.T) { @@ -53,7 +53,7 @@ func TestGetSingleDomainNotExist(t *testing.T) { mg, err := mailgun.NewMailgunFromEnv() mg.SetAPIBase(server.URL()) ensure.Nil(t, err) - _, _, _, err = mg.GetDomain("mailgun.test") + _, _, _, err = mg.GetDomain("unknown.domain") if err == nil { t.Fatal("Did not expect a domain to exist") } @@ -68,9 +68,9 @@ func TestAddDeleteDomain(t *testing.T) { ensure.Nil(t, err) // First, we need to add the domain. - ensure.Nil(t, mg.CreateDomain("mailgun.test", "supersecret", mailgun.Tag, false)) + ensure.Nil(t, mg.CreateDomain("mx.mailgun.test", "supersecret", mailgun.Tag, false)) // Next, we delete it. - ensure.Nil(t, mg.DeleteDomain("mailgun.test")) + ensure.Nil(t, mg.DeleteDomain("mx.mailgun.test")) } func TestDomainConnection(t *testing.T) { @@ -78,17 +78,17 @@ func TestDomainConnection(t *testing.T) { mg.SetAPIBase(server.URL()) ensure.Nil(t, err) - info, err := mg.GetDomainConnection(sampleDomain) + info, err := mg.GetDomainConnection(testDomain) ensure.Nil(t, err) ensure.DeepEqual(t, info.RequireTLS, true) ensure.DeepEqual(t, info.SkipVerification, true) info.RequireTLS = false - err = mg.UpdateDomainConnection(sampleDomain, info) + err = mg.UpdateDomainConnection(testDomain, info) ensure.Nil(t, err) - info, err = mg.GetDomainConnection(sampleDomain) + info, err = mg.GetDomainConnection(testDomain) ensure.Nil(t, err) ensure.DeepEqual(t, info.RequireTLS, false) ensure.DeepEqual(t, info.SkipVerification, true) @@ -99,7 +99,7 @@ func TestDomainTracking(t *testing.T) { mg.SetAPIBase(server.URL()) ensure.Nil(t, err) - info, err := mg.GetDomainTracking(sampleDomain) + info, err := mg.GetDomainTracking(testDomain) ensure.Nil(t, err) ensure.DeepEqual(t, info.Unsubscribe.Active, false) diff --git a/limits_test.go b/limits_test.go index 0b456f74..b97f5f8a 100644 --- a/limits_test.go +++ b/limits_test.go @@ -12,7 +12,7 @@ func TestLimits(t *testing.T) { mg.SetAPIBase(server.URL()) ensure.Nil(t, err) - limits, err := mg.GetTagLimits(sampleDomain) + limits, err := mg.GetTagLimits(testDomain) ensure.Nil(t, err) ensure.DeepEqual(t, limits.Limit, 50000) diff --git a/mailgun.go b/mailgun.go index 63e03732..c25afcc7 100644 --- a/mailgun.go +++ b/mailgun.go @@ -210,7 +210,7 @@ type Mailgun interface { UpdateMailingList(string, MailingList) (MailingList, error) ListMembers(address string, opts *ListOptions) *MemberListIterator - GetMemberByAddress(MemberAddr, listAddr string) (Member, error) + GetMember(MemberAddr, listAddr string) (Member, error) CreateMember(merge bool, addr string, prototype Member) error CreateMemberList(subscribed *bool, addr string, newMembers []interface{}) error UpdateMember(Member, list string, prototype Member) (Member, error) diff --git a/mailing_lists.go b/mailing_lists.go index 10e570a6..9d9c9fbb 100644 --- a/mailing_lists.go +++ b/mailing_lists.go @@ -30,10 +30,14 @@ type MailingList struct { } type listsResponse struct { - Lists []MailingList `json:"items"` + Items []MailingList `json:"items"` Paging Paging `json:"paging"` } +type mailingListResponse struct { + MailingList MailingList `json:"member"` +} + type ListsIterator struct { listsResponse mg Mailgun @@ -86,8 +90,8 @@ func (li *ListsIterator) Next(items *[]MailingList) bool { if li.err != nil { return false } - *items = li.Lists - if len(li.Lists) == 0 { + *items = li.Items + if len(li.Items) == 0 { return false } return true @@ -104,7 +108,7 @@ func (li *ListsIterator) First(items *[]MailingList) bool { if li.err != nil { return false } - *items = li.Lists + *items = li.Items return true } @@ -120,7 +124,7 @@ func (li *ListsIterator) Last(items *[]MailingList) bool { if li.err != nil { return false } - *items = li.Lists + *items = li.Items return true } @@ -138,8 +142,8 @@ func (li *ListsIterator) Previous(items *[]MailingList) bool { if li.err != nil { return false } - *items = li.Lists - if len(li.Lists) == 0 { + *items = li.Items + if len(li.Items) == 0 { return false } return true @@ -207,11 +211,9 @@ func (mg *MailgunImpl) GetMailingList(addr string) (MailingList, error) { return MailingList{}, err } - var envelope struct { - MailingList `json:"list"` - } - err = response.parseFromJSON(&envelope) - return envelope.MailingList, err + var resp mailingListResponse + err = response.parseFromJSON(&resp) + return resp.MailingList, err } // UpdateList allows you to change various attributes of a list. diff --git a/mailing_lists_test.go b/mailing_lists_test.go index db90e5c6..843a3116 100644 --- a/mailing_lists_test.go +++ b/mailing_lists_test.go @@ -3,65 +3,38 @@ package mailgun_test import ( "testing" - "github.com/davecgh/go-spew/spew" - "github.com/facebookgo/ensure" "github.com/mailgun/mailgun-go" ) -func TestPaging(t *testing.T) { +func TestMailingListMembers(t *testing.T) { mg, err := mailgun.NewMailgunFromEnv() mg.SetAPIBase(server.URL()) ensure.Nil(t, err) - it := mg.ListMailingLists(&mailgun.ListOptions{Limit: 10}) - var page []mailgun.MailingList - var first []mailgun.MailingList - - /*for it.Next(&page) { - spew.Dump(page) - }*/ - //var count int - it.Next(&first) - it.First(&page) - spew.Dump(page) - //ensure.DeepEqual(t, page, first) - /*if count > 2 { - break - } - count++*/ - //} - //ensure.Nil(t, it.Err()) -} - -/*func setup(t *testing.T) (Mailgun, string) { - domain := reqEnv(t, "MG_DOMAIN") - mg, err := NewMailgunFromEnv() - ensure.Nil(t, err) - - address := fmt.Sprintf("%s@%s", strings.ToLower(randomString(6, "list")), domain) - _, err = mg.CreateMailingList(MailingList{ + address := randomEmail("list", testDomain) + _, err = mg.CreateMailingList(mailgun.MailingList{ Address: address, Name: address, Description: "TestMailingListMembers-related mailing list", - AccessLevel: Members, + AccessLevel: mailgun.Members, }) ensure.Nil(t, err) - return mg, address -} - -func teardown(t *testing.T, mg Mailgun, address string) { - ensure.Nil(t, mg.DeleteMailingList(address)) -} + defer func() { + ensure.Nil(t, mg.DeleteMailingList(address)) + }() -func TestMailingListMembers(t *testing.T) { - mg, address := setup(t) - defer teardown(t, mg, address) + var page []mailgun.MailingList + it := mg.ListMailingLists(nil) + for it.Next(&page) { + ensure.DeepEqual(t, len(page) != 0, true) + } - var countPeople = func() int { + var countMembers = func() int { + var page []mailgun.Member var count int + it := mg.ListMembers(address, nil) - var page []Member for it.Next(&page) { count += len(page) } @@ -69,46 +42,46 @@ func TestMailingListMembers(t *testing.T) { return count } - startCount := countPeople() - protoJoe := Member{ + startCount := countMembers() + protoJoe := mailgun.Member{ Address: "joe@example.com", Name: "Joe Example", - Subscribed: Subscribed, + Subscribed: mailgun.Subscribed, } ensure.Nil(t, mg.CreateMember(true, address, protoJoe)) - newCount := countPeople() + newCount := countMembers() ensure.False(t, newCount <= startCount) - theMember, err := mg.GetMemberByAddress("joe@example.com", address) + theMember, err := mg.GetMember("joe@example.com", address) ensure.Nil(t, err) ensure.DeepEqual(t, theMember.Address, protoJoe.Address) ensure.DeepEqual(t, theMember.Name, protoJoe.Name) ensure.DeepEqual(t, theMember.Subscribed, protoJoe.Subscribed) ensure.True(t, len(theMember.Vars) == 0) - _, err = mg.UpdateMember("joe@example.com", address, Member{ + _, err = mg.UpdateMember("joe@example.com", address, mailgun.Member{ Name: "Joe Cool", }) ensure.Nil(t, err) - theMember, err = mg.GetMemberByAddress("joe@example.com", address) + theMember, err = mg.GetMember("joe@example.com", address) ensure.Nil(t, err) ensure.DeepEqual(t, theMember.Name, "Joe Cool") ensure.Nil(t, mg.DeleteMember("joe@example.com", address)) - ensure.DeepEqual(t, countPeople(), startCount) + ensure.DeepEqual(t, countMembers(), startCount) err = mg.CreateMemberList(nil, address, []interface{}{ - Member{ + mailgun.Member{ Address: "joe.user1@example.com", Name: "Joe's debugging account", - Subscribed: Unsubscribed, + Subscribed: mailgun.Unsubscribed, }, - Member{ + mailgun.Member{ Address: "Joe Cool ", Name: "Joe's Cool Account", - Subscribed: Subscribed, + Subscribed: mailgun.Subscribed, }, - Member{ + mailgun.Member{ Address: "joe.user3@example.com", Vars: map[string]interface{}{ "packet-email": "KW9ABC @ BOGBBS-4.#NCA.CA.USA.NOAM", @@ -117,7 +90,7 @@ func TestMailingListMembers(t *testing.T) { }) ensure.Nil(t, err) - theMember, err = mg.GetMemberByAddress("joe.user2@example.com", address) + theMember, err = mg.GetMember("joe.user2@example.com", address) ensure.Nil(t, err) ensure.DeepEqual(t, theMember.Name, "Joe's Cool Account") ensure.NotNil(t, theMember.Subscribed) @@ -125,22 +98,22 @@ func TestMailingListMembers(t *testing.T) { } func TestMailingLists(t *testing.T) { - domain := reqEnv(t, "MG_DOMAIN") - mg, err := NewMailgunFromEnv() + mg, err := mailgun.NewMailgunFromEnv() + mg.SetAPIBase(server.URL()) ensure.Nil(t, err) - listAddr := fmt.Sprintf("%s@%s", strings.ToLower(randomString(7, "list")), domain) - protoList := MailingList{ - Address: listAddr, + address := randomEmail("list", testDomain) + protoList := mailgun.MailingList{ + Address: address, Name: "List1", Description: "A list created by an acceptance test.", - AccessLevel: Members, + AccessLevel: mailgun.Members, } var countLists = func() int { var count int it := mg.ListMailingLists(nil) - var page []MailingList + var page []mailgun.MailingList for it.Next(&page) { count += len(page) } @@ -151,30 +124,30 @@ func TestMailingLists(t *testing.T) { _, err = mg.CreateMailingList(protoList) ensure.Nil(t, err) defer func() { - ensure.Nil(t, mg.DeleteMailingList(listAddr)) + ensure.Nil(t, mg.DeleteMailingList(address)) - _, err := mg.GetMailingList(listAddr) + _, err := mg.GetMailingList(address) ensure.NotNil(t, err) }() actualCount := countLists() ensure.False(t, actualCount < 1) - theList, err := mg.GetMailingList(listAddr) + theList, err := mg.GetMailingList(address) ensure.Nil(t, err) protoList.CreatedAt = theList.CreatedAt // ignore this field when comparing. ensure.DeepEqual(t, theList, protoList) - _, err = mg.UpdateMailingList(listAddr, MailingList{ + _, err = mg.UpdateMailingList(address, mailgun.MailingList{ Description: "A list whose description changed", }) ensure.Nil(t, err) - theList, err = mg.GetMailingList(listAddr) + theList, err = mg.GetMailingList(address) ensure.Nil(t, err) newList := protoList newList.Description = "A list whose description changed" ensure.DeepEqual(t, theList, newList) -}*/ +} diff --git a/members.go b/members.go index aab16243..5f36ad11 100644 --- a/members.go +++ b/members.go @@ -2,7 +2,6 @@ package mailgun import ( "encoding/json" - "fmt" "strconv" ) @@ -35,13 +34,17 @@ type Member struct { Vars map[string]interface{} `json:"vars,omitempty"` } -type memberListsResponse struct { +type memberListResponse struct { Lists []Member `json:"items"` Paging Paging `json:"paging"` } +type memberResponse struct { + Member Member `json:"list"` +} + type MemberListIterator struct { - memberListsResponse + memberListResponse mg Mailgun err error } @@ -61,9 +64,9 @@ func (mg *MailgunImpl) ListMembers(address string, opts *ListOptions) *MemberLis } url, err := r.generateUrlWithParameters() return &MemberListIterator{ - mg: mg, - memberListsResponse: memberListsResponse{Paging: Paging{Next: url, First: url}}, - err: err, + mg: mg, + memberListResponse: memberListResponse{Paging: Paging{Next: url, First: url}}, + err: err, } } @@ -161,12 +164,12 @@ func (li *MemberListIterator) fetch(url string) error { r.setClient(li.mg.Client()) r.setBasicAuth(basicAuthUser, li.mg.APIKey()) - return getResponseFromJSON(r, &li.memberListsResponse) + return getResponseFromJSON(r, &li.memberListResponse) } -// GetMemberByAddress returns a complete Member structure for a member of a mailing list, +// GetMember returns a complete Member structure for a member of a mailing list, // given only their subscription e-mail address. -func (mg *MailgunImpl) GetMemberByAddress(s, l string) (Member, error) { +func (mg *MailgunImpl) GetMember(s, l string) (Member, error) { r := newHTTPRequest(generateMemberApiUrl(mg, listsEndpoint, l) + "/" + s) r.setClient(mg.Client()) r.setBasicAuth(basicAuthUser, mg.APIKey()) @@ -174,11 +177,9 @@ func (mg *MailgunImpl) GetMemberByAddress(s, l string) (Member, error) { if err != nil { return Member{}, err } - var envelope struct { - Member Member `json:"member"` - } - err = response.parseFromJSON(&envelope) - return envelope.Member, err + var resp memberResponse + err = response.parseFromJSON(&resp) + return resp.Member, err } // CreateMember registers a new member of the indicated mailing list. @@ -269,7 +270,6 @@ func (mg *MailgunImpl) CreateMemberList(u *bool, addr string, newMembers []inter if err != nil { return err } - fmt.Println(string(bs)) p.addValue("members", string(bs)) _, err = makePostRequest(r, p) return err diff --git a/mock.go b/mock.go index ac4a8067..d64d7a3b 100644 --- a/mock.go +++ b/mock.go @@ -4,7 +4,10 @@ import ( "encoding/json" "net/http" "net/http/httptest" + "net/mail" + "net/url" "strconv" + "strings" "github.com/go-chi/chi" ) @@ -51,26 +54,59 @@ func toJSON(w http.ResponseWriter, obj interface{}) { w.Header().Set("Content-Type", "application/json") } -func stringToBool(b string) bool { - result, err := strconv.ParseBool(b) +func stringToBool(v string) bool { + lower := strings.ToLower(v) + if lower == "yes" || lower == "no" { + return lower == "yes" + } + + if v == "" { + return false + } + + result, err := strconv.ParseBool(v) if err != nil { panic(err) } return result } -func stringToInt(b string) int { - if b == "" { +func stringToInt(v string) int { + if v == "" { return 0 } - result, err := strconv.ParseInt(b, 10, 64) + result, err := strconv.ParseInt(v, 10, 64) if err != nil { panic(err) } return int(result) } +func stringToMap(v string) map[string]interface{} { + if v == "" { + return nil + } + + result := make(map[string]interface{}) + err := json.Unmarshal([]byte(v), &result) + if err != nil { + panic(err) + } + return result +} + +func parseAddress(v string) string { + if v == "" { + return "" + } + e, err := mail.ParseAddress(v) + if err != nil { + panic(err) + } + return e.Address +} + // Given the page direction, pivot value and limit, calculate the offsets for the slice func pageOffsets(pivotIdx []string, pivotDir, pivotVal string, limit int) (int, int) { switch pivotDir { @@ -113,3 +149,8 @@ func pageOffsets(pivotIdx []string, pivotDir, pivotVal string, limit int) (int, } return 0, limit } + +func getPageURL(r *http.Request, params url.Values) string { + params.Add("limit", r.FormValue("limit")) + return "http://" + r.Host + r.URL.EscapedPath() + "?" + params.Encode() +} diff --git a/mock_domains.go b/mock_domains.go index 8ff000b4..2f1cdeb0 100644 --- a/mock_domains.go +++ b/mock_domains.go @@ -21,8 +21,8 @@ func (ms *MockServer) addDomainRoutes(r chi.Router) { ms.domainList = append(ms.domainList, domainContainer{ Domain: Domain{ CreatedAt: "Wed, 10 Jul 2013 19:26:52 GMT", - Name: "samples.mailgun.org", - SMTPLogin: "postmaster@samples.mailgun.org", + Name: "mailgun.test", + SMTPLogin: "postmaster@mailgun.test", SMTPPassword: "4rtqo4p6rrx9", Wildcard: true, SpamAction: "disabled", diff --git a/mock_mailing_list.go b/mock_mailing_list.go index 3814384e..c4f80458 100644 --- a/mock_mailing_list.go +++ b/mock_mailing_list.go @@ -1,9 +1,10 @@ package mailgun import ( - "fmt" + "encoding/json" "net/http" "net/url" + "time" "github.com/go-chi/chi" ) @@ -13,32 +14,19 @@ type mailingListContainer struct { Members []Member } -type paging struct { - First string `json:"first"` - Last string `json:"last"` - Next string `json:"next"` - Previous string `json:"previous"` -} - -type mailingListResponse struct { - Items []MailingList `json:"items"` - Paging paging `json:"paging"` -} - func (ms *MockServer) addMailingListRoutes(r chi.Router) { r.Get("/lists/pages", ms.listMailingLists) - /*r.Get("/lists/{address}", ms.getMailingList) + r.Get("/lists/{address}", ms.getMailingList) r.Post("/lists", ms.createMailingList) r.Put("/lists/{address}", ms.updateMailingList) r.Delete("/lists/{address}", ms.deleteMailingList) r.Get("/lists/{address}/members/pages", ms.listMembers) - r.Get("/lists/{address}/members/{address}", ms.getMember) + r.Get("/lists/{address}/members/{member}", ms.getMember) r.Post("/lists/{address}/members", ms.createMember) - r.Post("/lists/{address}/members", ms.createMember) - r.Put("/lists/{address}/members/{address}", ms.updateMember) - r.Delete("/lists/{address}/members/{address}", ms.deleteMember) - r.Post("/lists/{address}/members.json", ms.bulkCreate)*/ + r.Put("/lists/{address}/members/{member}", ms.updateMember) + r.Delete("/lists/{address}/members/{member}", ms.deleteMember) + r.Post("/lists/{address}/members.json", ms.bulkCreate) ms.mailingList = append(ms.mailingList, mailingListContainer{ MailingList: MailingList{ @@ -56,34 +44,15 @@ func (ms *MockServer) addMailingListRoutes(r chi.Router) { }, }, }) - - for i := 0; i < 20; i++ { - ms.mailingList = append(ms.mailingList, mailingListContainer{ - MailingList: MailingList{ - AccessLevel: "everyone", - Address: fmt.Sprintf("%0d@mailgun.test", i), - CreatedAt: "Tue, 06 Mar 2012 05:44:45 GMT", - Description: "Mailgun developers list", - MembersCount: 1, - Name: "", - }, - Members: []Member{ - { - Address: "dev@samples.mailgun.org", - Name: "Developer", - }, - }, - }) - } } func (ms *MockServer) listMailingLists(w http.ResponseWriter, r *http.Request) { var list []MailingList var idx []string - for _, item := range ms.mailingList { - list = append(list, item.MailingList) - idx = append(idx, item.MailingList.Address) + for _, ml := range ms.mailingList { + list = append(list, ml.MailingList) + idx = append(idx, ml.MailingList.Address) } limit := stringToInt(r.FormValue("limit")) @@ -94,12 +63,12 @@ func (ms *MockServer) listMailingLists(w http.ResponseWriter, r *http.Request) { results := list[start:end] if len(results) == 0 { - toJSON(w, mailingListResponse{}) + toJSON(w, listsResponse{}) return } - resp := mailingListResponse{ - Paging: paging{ + resp := listsResponse{ + Paging: Paging{ First: getPageURL(r, url.Values{ "page": []string{"first"}, }), @@ -120,7 +89,302 @@ func (ms *MockServer) listMailingLists(w http.ResponseWriter, r *http.Request) { toJSON(w, resp) } -func getPageURL(r *http.Request, params url.Values) string { - params.Add("limit", r.FormValue("limit")) - return "http://" + r.Host + r.URL.EscapedPath() + "?" + params.Encode() +func (ms *MockServer) getMailingList(w http.ResponseWriter, r *http.Request) { + for _, ml := range ms.mailingList { + if ml.MailingList.Address == chi.URLParam(r, "address") { + toJSON(w, mailingListResponse{MailingList: ml.MailingList}) + return + } + } + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) +} + +func (ms *MockServer) deleteMailingList(w http.ResponseWriter, r *http.Request) { + result := ms.mailingList[:0] + for _, ml := range ms.mailingList { + if ml.MailingList.Address == chi.URLParam(r, "address") { + continue + } + result = append(result, ml) + } + + if len(result) != len(ms.mailingList) { + toJSON(w, okResp{Message: "success"}) + ms.mailingList = result + return + } + + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) +} + +func (ms *MockServer) updateMailingList(w http.ResponseWriter, r *http.Request) { + for i, d := range ms.mailingList { + if d.MailingList.Address == chi.URLParam(r, "address") { + if r.FormValue("address") != "" { + ms.mailingList[i].MailingList.Address = r.FormValue("address") + } + if r.FormValue("name") != "" { + ms.mailingList[i].MailingList.Name = r.FormValue("name") + } + if r.FormValue("description") != "" { + ms.mailingList[i].MailingList.Description = r.FormValue("description") + } + if r.FormValue("access_level") != "" { + ms.mailingList[i].MailingList.AccessLevel = r.FormValue("access_level") + } + toJSON(w, okResp{Message: "Mailing list member has been updated"}) + return + } + } + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) +} + +func (ms *MockServer) createMailingList(w http.ResponseWriter, r *http.Request) { + now := time.Now() + ms.mailingList = append(ms.mailingList, mailingListContainer{ + MailingList: MailingList{ + CreatedAt: formatMailgunTime(&now), + Name: r.FormValue("name"), + Address: r.FormValue("address"), + Description: r.FormValue("description"), + AccessLevel: r.FormValue("access_level"), + }, + }) + toJSON(w, okResp{Message: "Mailing list has been created"}) +} + +func (ms *MockServer) listMembers(w http.ResponseWriter, r *http.Request) { + var list []Member + var idx []string + var found bool + + for _, ml := range ms.mailingList { + if ml.MailingList.Address == chi.URLParam(r, "address") { + found = true + for _, member := range ml.Members { + list = append(list, member) + idx = append(idx, member.Address) + } + } + } + + if !found { + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) + return + } + + limit := stringToInt(r.FormValue("limit")) + if limit == 0 { + limit = 100 + } + start, end := pageOffsets(idx, r.FormValue("page"), r.FormValue("address"), limit) + results := list[start:end] + + if len(results) == 0 { + toJSON(w, memberListResponse{}) + return + } + + resp := memberListResponse{ + Paging: Paging{ + First: getPageURL(r, url.Values{ + "page": []string{"first"}, + }), + Last: getPageURL(r, url.Values{ + "page": []string{"last"}, + }), + Next: getPageURL(r, url.Values{ + "page": []string{"next"}, + "address": []string{results[len(results)-1].Address}, + }), + Previous: getPageURL(r, url.Values{ + "page": []string{"prev"}, + "address": []string{results[0].Address}, + }), + }, + Lists: results, + } + toJSON(w, resp) +} + +func (ms *MockServer) getMember(w http.ResponseWriter, r *http.Request) { + var found bool + for _, ml := range ms.mailingList { + if ml.MailingList.Address == chi.URLParam(r, "address") { + found = true + for _, member := range ml.Members { + if member.Address == chi.URLParam(r, "member") { + toJSON(w, memberResponse{Member: member}) + return + } + } + } + } + + if !found { + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) + return + } + + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "member not found"}) +} + +func (ms *MockServer) deleteMember(w http.ResponseWriter, r *http.Request) { + idx := -1 + for i, ml := range ms.mailingList { + if ml.MailingList.Address == chi.URLParam(r, "address") { + idx = i + } + } + + if idx == -1 { + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) + return + } + + result := ms.mailingList[idx].Members[:0] + for _, m := range ms.mailingList[idx].Members { + if m.Address == chi.URLParam(r, "member") { + continue + } + result = append(result, m) + } + + if len(result) != len(ms.mailingList[idx].Members) { + toJSON(w, okResp{Message: "Mailing list member has been deleted"}) + ms.mailingList[idx].Members = result + return + } + + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "member not found"}) +} + +func (ms *MockServer) updateMember(w http.ResponseWriter, r *http.Request) { + idx := -1 + for i, ml := range ms.mailingList { + if ml.MailingList.Address == chi.URLParam(r, "address") { + idx = i + } + } + + if idx == -1 { + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) + return + } + + for i, m := range ms.mailingList[idx].Members { + if m.Address == chi.URLParam(r, "member") { + if r.FormValue("address") != "" { + ms.mailingList[idx].Members[i].Address = parseAddress(r.FormValue("address")) + } + if r.FormValue("name") != "" { + ms.mailingList[idx].Members[i].Name = r.FormValue("name") + } + if r.FormValue("vars") != "" { + ms.mailingList[idx].Members[i].Vars = stringToMap(r.FormValue("vars")) + } + if r.FormValue("subscribed") != "" { + sub := stringToBool(r.FormValue("subscribed")) + ms.mailingList[idx].Members[i].Subscribed = &sub + } + toJSON(w, okResp{Message: "Mailing list member has been updated"}) + return + } + } + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "member not found"}) +} + +func (ms *MockServer) createMember(w http.ResponseWriter, r *http.Request) { + idx := -1 + for i, ml := range ms.mailingList { + if ml.MailingList.Address == chi.URLParam(r, "address") { + idx = i + } + } + + if idx == -1 { + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) + return + } + + sub := stringToBool(r.FormValue("subscribed")) + + if len(ms.mailingList[idx].Members) != 0 { + for i, m := range ms.mailingList[idx].Members { + if m.Address == r.FormValue("address") { + if !stringToBool(r.FormValue("upsert")) { + w.WriteHeader(http.StatusConflict) + toJSON(w, okResp{Message: "member already exists"}) + return + } + + ms.mailingList[idx].Members[i].Address = parseAddress(r.FormValue("address")) + ms.mailingList[idx].Members[i].Name = r.FormValue("name") + ms.mailingList[idx].Members[i].Vars = stringToMap(r.FormValue("vars")) + ms.mailingList[idx].Members[i].Subscribed = &sub + break + } + } + } + + ms.mailingList[idx].Members = append(ms.mailingList[idx].Members, Member{ + Name: r.FormValue("name"), + Address: parseAddress(r.FormValue("address")), + Vars: stringToMap(r.FormValue("vars")), + Subscribed: &sub, + }) + toJSON(w, okResp{Message: "Mailing list member has been created"}) +} + +func (ms *MockServer) bulkCreate(w http.ResponseWriter, r *http.Request) { + idx := -1 + for i, ml := range ms.mailingList { + if ml.MailingList.Address == chi.URLParam(r, "address") { + idx = i + } + } + + if idx == -1 { + w.WriteHeader(http.StatusNotFound) + toJSON(w, okResp{Message: "mailing list not found"}) + return + } + + var bulkList []Member + if err := json.Unmarshal([]byte(r.FormValue("members")), &bulkList); err != nil { + w.WriteHeader(http.StatusInternalServerError) + toJSON(w, okResp{Message: "while un-marshalling 'members' param - " + err.Error()}) + return + } + +BULK: + for _, member := range bulkList { + member.Address = parseAddress(member.Address) + if len(ms.mailingList[idx].Members) != 0 { + for i, m := range ms.mailingList[idx].Members { + if m.Address == member.Address { + if !stringToBool(r.FormValue("upsert")) { + w.WriteHeader(http.StatusConflict) + toJSON(w, okResp{Message: "member already exists"}) + return + } + ms.mailingList[idx].Members[i] = member + continue BULK + } + } + } + ms.mailingList[idx].Members = append(ms.mailingList[idx].Members, member) + } + toJSON(w, okResp{Message: "Mailing list has been updated"}) }