Repository: mailgun/mailgun-go
Pull request #275 (2021-12-10 12:11:06)

Mock server template versions
And use those mock to test template version methods.


Patch:
diff --git a/mock.go b/mock.go
index 071a6c9..1b4f36c 100644
--- a/mock.go
+++ b/mock.go
@@ -110,6 +110,7 @@ func NewMockServer() MockServer {
 		ms.addRoutes(r)
 		ms.addWebhookRoutes(r)
 		ms.addTemplateRoutes(r)
+		ms.addTemplateVersionRoutes(r)
 	}(r.PathPrefix("/v3").Subrouter())
 	ms.addValidationRoutes(r)
 
diff --git a/mock_template_versions.go b/mock_template_versions.go
new file mode 100644
index 0000000..44d0400
--- /dev/null
+++ b/mock_template_versions.go
@@ -0,0 +1,330 @@
+package mailgun
+
+import (
+	"fmt"
+	"net/http"
+	"net/url"
+	"strings"
+	"time"
+
+	"github.com/gorilla/mux"
+)
+
+func (ms *mockServer) addTemplateVersionRoutes(r *mux.Router) {
+	r.HandleFunc("/{domain}/templates/{template}/versions", ms.listTemplateVersions).Methods(http.MethodGet)
+	r.HandleFunc("/{domain}/templates/{template}/versions/{tag}", ms.getTemplateVersion).Methods(http.MethodGet)
+	r.HandleFunc("/{domain}/templates/{template}/versions", ms.createTemplateVersion).Methods(http.MethodPost)
+	r.HandleFunc("/{domain}/templates/{template}/versions/{tag}", ms.updateTemplateVersion).Methods(http.MethodPut)
+	r.HandleFunc("/{domain}/templates/{template}/versions/{tag}", ms.deleteTemplateVersion).Methods(http.MethodDelete)
+}
+
+func (ms *mockServer) listTemplateVersions(w http.ResponseWriter, r *http.Request) {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+
+	templateName := mux.Vars(r)["template"]
+	template, found := ms.fetchTemplate(templateName)
+	if !found {
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte("{\"message\": \"template not found\"}"))
+		return
+	}
+
+	templateVersions := ms.templateVersions[templateName]
+
+	var idx []string
+	for _, t := range templateVersions {
+		idx = append(idx, t.Tag)
+	}
+
+	limit := stringToInt(r.FormValue("limit"))
+	if limit == 0 {
+		limit = 10
+	}
+
+	page := r.FormValue("page")
+	var pivot string
+	if len(page) != 0 {
+		pivot = r.FormValue("p")
+		if pivot == "" {
+			w.WriteHeader(http.StatusBadRequest)
+			w.Write([]byte("{\"message\": \"Invalid parameter: pivot \"}"))
+			return
+		}
+	}
+	start, end := pageOffsets(idx, page, pivot, limit)
+	var nextAddress, prevAddress string
+	var results []TemplateVersion
+
+	if start != end {
+		results = ms.templateVersions[templateName][start:end]
+		nextAddress = results[len(results)-1].Tag
+		prevAddress = results[0].Tag
+	} else {
+		results = []TemplateVersion{}
+		nextAddress = pivot
+		prevAddress = pivot
+	}
+
+	toJSON(w, templateVersionListResp{
+		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"},
+				"p":    []string{nextAddress},
+			}),
+			Previous: getPageURL(r, url.Values{
+				"page": []string{"prev"},
+				"p":    []string{prevAddress},
+			}),
+		},
+		Template: struct {
+			Template
+			Versions []TemplateVersion `json:"versions,omitempty"`
+		}{
+			Template: template,
+			Versions: results,
+		},
+	})
+}
+
+func (ms *mockServer) getTemplateVersion(w http.ResponseWriter, r *http.Request) {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+
+	templateName := mux.Vars(r)["template"]
+	templateName = strings.ToLower(templateName)
+	templateVersionName := mux.Vars(r)["tag"]
+	templateVersionName = strings.ToLower(templateVersionName)
+
+	template, templateFound := ms.fetchTemplate(templateName)
+	if !templateFound {
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte("{\"message\": \"template not found\"}"))
+		return
+	}
+
+	templateVersion, templateVersionFound := ms.fetchTemplateVersion(templateName, templateVersionName)
+	if !templateVersionFound {
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte("{\"message\": \"template version not found\"}"))
+		return
+	}
+
+	template.Version = templateVersion
+
+	toJSON(w, &templateResp{
+		Item: template,
+	})
+}
+
+func (ms *mockServer) createTemplateVersion(w http.ResponseWriter, r *http.Request) {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+
+	templateName := mux.Vars(r)["template"]
+	templateName = strings.ToLower(templateName)
+
+	r.ParseForm()
+	templateContent := r.FormValue("template")
+	if len(templateContent) == 0 {
+		w.WriteHeader(http.StatusBadRequest)
+		w.Write([]byte("{\"message\": \"Missing mandatory parameter: template\"}"))
+		return
+	}
+	tagName := r.FormValue("tag")
+	if len(templateContent) == 0 {
+		w.WriteHeader(http.StatusBadRequest)
+		w.Write([]byte("{\"message\": \"Missing mandatory parameter: tag\"}"))
+		return
+	}
+
+	template, templateFound := ms.fetchTemplate(templateName)
+	if !templateFound {
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte("{\"message\": \"template not found\"}"))
+		return
+	}
+
+	_, templateVersionFound := ms.fetchTemplateVersion(templateName, tagName)
+	if templateVersionFound {
+		w.WriteHeader(http.StatusConflict)
+		w.Write([]byte(fmt.Sprintf("{\"message\": \"version %s already exists\"}", tagName)))
+		return
+	}
+
+	comment := r.FormValue("comment")
+	active := r.FormValue("active")
+
+	engine := r.FormValue("engine")
+	if len(engine) != 0 {
+		if strings.ToLower(engine) != "go" && strings.ToLower(engine) != "handlebars" {
+			w.WriteHeader(http.StatusBadRequest)
+			w.Write([]byte(fmt.Sprintf("{\"message\": \"Invalid parameter: engine %s is not supported\"}", engine)))
+			return
+		}
+	} else {
+		engine = "handlebars"
+	}
+
+	newTemplateVersion := TemplateVersion{
+		Template:  templateContent,
+		Comment:   comment,
+		Tag:       tagName,
+		Engine:    TemplateEngine(engine),
+		CreatedAt: RFC2822Time(time.Now()),
+	}
+
+	if active == "yes" {
+		newTemplateVersion.Active = true
+		for i, _ := range ms.templateVersions[templateName] {
+			ms.templateVersions[templateName][i].Active = false
+		}
+	}
+
+	ms.templateVersions[templateName] = append(ms.templateVersions[templateName], newTemplateVersion)
+	template.Version = newTemplateVersion
+	toJSON(w, map[string]interface{}{
+		"message":  "new version of the template has been stored",
+		"template": template,
+	})
+}
+
+func (ms *mockServer) updateTemplateVersion(w http.ResponseWriter, r *http.Request) {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+
+	templateName := mux.Vars(r)["template"]
+	templateName = strings.ToLower(templateName)
+	templateVersionName := mux.Vars(r)["tag"]
+	templateVersionName = strings.ToLower(templateVersionName)
+
+	_, templateFound := ms.fetchTemplate(templateName)
+	if !templateFound {
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte("{\"message\": \"template not found\"}"))
+		return
+	}
+
+	var templateVersionFound bool
+	var templateVersion TemplateVersion
+	var templateVersionIndex int
+	for i, tmplVersion := range ms.templateVersions[templateName] {
+		if tmplVersion.Tag == templateVersionName {
+			templateVersion = tmplVersion
+			templateVersionFound = true
+			templateVersionIndex = i
+			break
+		}
+	}
+
+	if !templateVersionFound {
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte("{\"message\": \"template version not found\"}"))
+		return
+	}
+
+	r.ParseForm()
+	templateContent := r.FormValue("template")
+	comment := r.FormValue("comment")
+	active := r.FormValue("active")
+
+	updated := false
+	if len(templateContent) != 0 {
+		templateVersion.Template = templateContent
+		updated = true
+	}
+	if len(comment) != 0 {
+		templateVersion.Comment = comment
+		updated = true
+	}
+	if len(active) != 0 {
+		if active == "yes" {
+			templateVersion.Active = true
+			for i := range ms.templateVersions[templateName] { //every other template version become not active
+				if i == templateVersionIndex {
+					continue
+				}
+				ms.templateVersions[templateName][i].Active = false
+			}
+		}
+		updated = true
+	}
+
+	if !updated {
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte("{\"message\": \"No fields are provided to update\"}"))
+		return
+	}
+
+	ms.templateVersions[templateName][templateVersionIndex] = templateVersion
+	toJSON(w, map[string]interface{}{
+		"message": "version has been updated",
+		"template": map[string]interface{}{
+			"name": templateName,
+			"version": map[string]string{
+				"tag": templateVersionName,
+			},
+		},
+	})
+}
+
+func (ms *mockServer) deleteTemplateVersion(w http.ResponseWriter, r *http.Request) {
+	defer ms.mutex.Unlock()
+	ms.mutex.Lock()
+
+	templateName := mux.Vars(r)["template"]
+	templateName = strings.ToLower(templateName)
+	templateVersionName := mux.Vars(r)["tag"]
+	templateVersionName = strings.ToLower(templateVersionName)
+
+	_, templateFound := ms.fetchTemplate(templateName)
+	if !templateFound {
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte("{\"message\": \"template not found\"}"))
+		return
+	}
+	for i, templateVersion := range ms.templateVersions[templateName] {
+		if templateVersion.Tag == templateVersionName {
+			ms.templateVersions[templateName] = append(ms.templateVersions[templateName][:i], ms.templateVersions[templateName][i+1:len(ms.templateVersions[templateName])]...)
+			break
+		}
+	}
+
+	w.WriteHeader(http.StatusOK)
+	toJSON(w, map[string]interface{}{
+		"message": "version has been deleted",
+		"template": map[string]interface{}{
+			"name": templateName,
+			"version": map[string]string{
+				"tag": templateVersionName,
+			},
+		},
+	})
+}
+
+func (ms *mockServer) fetchTemplate(name string) (template Template, found bool) {
+	for _, existingTemplate := range ms.templates {
+		if existingTemplate.Name == name {
+			template = existingTemplate
+			return template, true
+		}
+	}
+
+	return Template{}, false
+}
+
+func (ms *mockServer) fetchTemplateVersion(templateName string, templateVersionTag string) (TemplateVersion, bool) {
+	for _, existingTemplate := range ms.templateVersions[templateName] {
+		if existingTemplate.Tag == templateVersionTag {
+			return existingTemplate, true
+		}
+	}
+
+	return TemplateVersion{}, false
+}


Test patch:
diff --git a/template_versions_test.go b/template_versions_test.go
index 4cbb4d8..222a453 100644
--- a/template_versions_test.go
+++ b/template_versions_test.go
@@ -9,12 +9,8 @@ import (
 )
 
 func TestTemplateVersionsCRUD(t *testing.T) {
-	if reason := mailgun.SkipNetworkTest(); reason != "" {
-		t.Skip(reason)
-	}
-
-	mg, err := mailgun.NewMailgunFromEnv()
-	ensure.Nil(t, err)
+	mg := mailgun.NewMailgun(testDomain, testKey)
+	mg.SetAPIBase(server.URL())
 	ctx := context.Background()
 
 	findVersion := func(templateName, tag string) bool {
@@ -71,6 +67,7 @@ func TestTemplateVersionsCRUD(t *testing.T) {
 	// Ensure update took
 	updated, err := mg.GetTemplateVersion(ctx, tmpl.Name, version.Tag)
 
+	ensure.Nil(t, err)
 	ensure.DeepEqual(t, updated.Comment, UpdatedComment)
 	ensure.DeepEqual(t, updated.Template, Template+"updated")