Repository: PagerDuty/go-pagerduty
Pull request #282 (2021-02-24 22:54:38)

Omitting EndpointURL from Extension if empty
 - The EndpointURL is an Optional field for many extension schemas such as Slack V2
 - Omitempty allows us to ensure that an empty string is not being sent to the Pagerduty API when an extension is created without one provided

Signed-off-by: Afolabi Badmos <afolabi@autonomic.ai>


Patch:
diff --git a/extension.go b/extension.go
index b8fe0d5..d433577 100644
--- a/extension.go
+++ b/extension.go
@@ -11,7 +11,7 @@ import (
 type Extension struct {
 	APIObject
 	Name             string      `json:"name"`
-	EndpointURL      string      `json:"endpoint_url"`
+	EndpointURL      string      `json:"endpoint_url,omitempty"`
 	ExtensionObjects []APIObject `json:"extension_objects"`
 	ExtensionSchema  APIObject   `json:"extension_schema"`
 	Config           interface{} `json:"config"`


Test patch:
diff --git a/client_test.go b/client_test.go
index 9c5d8cb..ded689c 100644
--- a/client_test.go
+++ b/client_test.go
@@ -6,6 +6,7 @@ import (
 	"net/http"
 	"net/http/httptest"
 	"reflect"
+	"strings"
 	"testing"
 )
 
@@ -43,6 +44,35 @@ func testEqual(t *testing.T, expected interface{}, actual interface{}) {
 	}
 }
 
+// testErrCheck looks to see if errContains is a substring of err.Error(). If
+// not, this calls t.Fatal(). It also calls t.Fatal() if there was an error, but
+// errContains is empty. Returns true if you should continue running the test,
+// or false if you should stop the test.
+func testErrCheck(t *testing.T, name string, errContains string, err error) bool {
+	t.Helper()
+
+	if len(errContains) > 0 {
+		if err == nil {
+			t.Fatalf("%s error = <nil>, should contain %q", name, errContains)
+			return false
+		}
+
+		if errStr := err.Error(); !strings.Contains(errStr, errContains) {
+			t.Fatalf("%s error = %q, should contain %q", name, errStr, errContains)
+			return false
+		}
+
+		return false
+	}
+
+	if err != nil && len(errContains) == 0 {
+		t.Fatalf("%s unexpected error: %v", name, err)
+		return false
+	}
+
+	return true
+}
+
 func TestAPIError_Error(t *testing.T) {
 	const jsonBody = `{"error":{"code": 420, "message": "Enhance Your Calm", "errors":["Enhance Your Calm", "Slow Your Roll"]}}`
 
diff --git a/extension_test.go b/extension_test.go
index f4ed438..996b3f2 100644
--- a/extension_test.go
+++ b/extension_test.go
@@ -1,6 +1,7 @@
 package pagerduty
 
 import (
+	"encoding/json"
 	"net/http"
 	"testing"
 )
@@ -55,28 +56,56 @@ func TestExtension_Create(t *testing.T) {
 	setup()
 	defer teardown()
 
-	input := &Extension{Name: "foo"}
+	input1 := &Extension{Name: "foo"}
+	input2 := &Extension{Name: "bar", EndpointURL: "expected_url"}
 
 	mux.HandleFunc("/extensions", func(w http.ResponseWriter, r *http.Request) {
-		testMethod(t, r, "POST")
-		w.Write([]byte(`{"extension": {"name": "foo", "id": "1"}}`))
+		var got map[string]interface{}
+
+		err := json.NewDecoder(r.Body).Decode(&got)
+
+		testErrCheck(t, "Extension_Create()", "", err)
+		name := got["name"]
+
+		if name == "foo" {
+			testNoEndpointURL(t, got)
+			testMethod(t, r, "POST")
+			w.Write([]byte(`{"extension": {"name": "foo", "id": "1"}}`))
+		} else {
+			testGotExpectedURL(t, "expected_url", got)
+			testMethod(t, r, "POST")
+			w.Write([]byte(`{"extension": {"name": "bar", "id": "2", "endpoint_url": "expected_url"}}`))
+		}
 	})
 
 	var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}
 
-	res, err := client.CreateExtension(input)
-
-	want := &Extension{
+	want1 := &Extension{
 		Name: "foo",
 		APIObject: APIObject{
 			ID: "1",
 		},
 	}
 
+	want2 := &Extension{
+		Name:        "bar",
+		EndpointURL: "expected_url",
+		APIObject: APIObject{
+			ID: "2",
+		},
+	}
+
+	res1, err := client.CreateExtension(input1)
 	if err != nil {
 		t.Fatal(err)
 	}
-	testEqual(t, want, res)
+	testEqual(t, want1, res1)
+
+	res2, err := client.CreateExtension(input2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	testEqual(t, want2, res2)
 }
 
 func TestExtension_Delete(t *testing.T) {
@@ -125,26 +154,71 @@ func TestExtension_Update(t *testing.T) {
 	setup()
 	defer teardown()
 
-	input := &Extension{Name: "foo"}
+	input1 := &Extension{Name: "foo"}
+	input2 := &Extension{Name: "foo", EndpointURL: "expected_url"}
 
 	mux.HandleFunc("/extensions/1", func(w http.ResponseWriter, r *http.Request) {
+		var got map[string]interface{}
+
+		err := json.NewDecoder(r.Body).Decode(&got)
+
+		testErrCheck(t, "Extension_Update()", "", err)
+		testNoEndpointURL(t, got)
+
 		testMethod(t, r, "PUT")
 		w.Write([]byte(`{"extension": {"name": "foo", "id": "1"}}`))
 	})
 
-	var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}
+	mux.HandleFunc("/extensions/2", func(w http.ResponseWriter, r *http.Request) {
+		var got map[string]interface{}
 
-	res, err := client.UpdateExtension("1", input)
+		err := json.NewDecoder(r.Body).Decode(&got)
+		testErrCheck(t, "Extension_Update()", "", err)
 
-	want := &Extension{
+		testGotExpectedURL(t, "expected_url", got)
+
+		testMethod(t, r, "PUT")
+		w.Write([]byte(`{"extension": {"name": "foo", "id": "2", "endpoint_url": "expected_url"}}`))
+	})
+
+	var client = &Client{apiEndpoint: server.URL, authToken: "foo", HTTPClient: defaultHTTPClient}
+
+	want1 := &Extension{
 		Name: "foo",
 		APIObject: APIObject{
 			ID: "1",
 		},
 	}
 
+	want2 := &Extension{
+		Name:        "foo",
+		EndpointURL: "expected_url",
+		APIObject: APIObject{
+			ID: "2",
+		},
+	}
+
+	res1, err := client.UpdateExtension("1", input1)
 	if err != nil {
 		t.Fatal(err)
 	}
-	testEqual(t, want, res)
+	testEqual(t, want1, res1)
+
+	res2, err := client.UpdateExtension("2", input2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	testEqual(t, want2, res2)
+}
+
+func testNoEndpointURL(t *testing.T, got map[string]interface{}) {
+	if _, ok := got["endpoint_url"]; ok {
+		t.Errorf(`Expected no url, got: "%v"`, got["endpoint_url"])
+	}
+}
+
+func testGotExpectedURL(t *testing.T, expected string, got map[string]interface{}) {
+	if got["endpoint_url"] != expected {
+		t.Errorf(`Expected url: "%v", got: "%v"`, "expected_url", got["endpoint_url"])
+	}
 }