Repository: nicklaw5/helix
Pull request #69 (2020-12-02 06:39:51)

Adding Start Commercial endpoint support


Patch:
diff --git a/README.md b/README.md
index 0180bfd..95178b7 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ looking for the Twitch API docs, see the [Twitch Developer website](https://dev.
 
 **API Endpoint:**
 
-- [ ] Start Commercial
+- [x] Start Commercial
 - [x] Get Extension Analytics
 - [ ] Get Cheermotes
 - [x] Get Game Analytics
@@ -40,7 +40,7 @@ looking for the Twitch API docs, see the [Twitch Developer website](https://dev.
 - [x] Create Entitlement Grants Upload URL
 - [x] Get Code Status
 - [x] Get Drops Entitlements
-- [x] Redeem Code
+- [ ] Redeem Code
 - [x] Get Top Games
 - [x] Get Games
 - [ ] Get Hype Train Events
diff --git a/ads.go b/ads.go
new file mode 100644
index 0000000..da18cd7
--- /dev/null
+++ b/ads.go
@@ -0,0 +1,51 @@
+package helix
+
+type AdLengthEnum int
+
+const (
+	_ AdLengthEnum = iota * 30
+	AdLen30
+	AdLen60
+	AdLen90
+	AdLen120
+	AdLen150
+	AdLen180
+)
+
+// StartCommercialParams ...
+type StartCommercialParams struct {
+	BroadcasterID string       `query:"broadcaster_id"`
+	Length        AdLengthEnum `query:"length"`
+}
+
+type AdDetails struct {
+	Length     AdLengthEnum `json:"length"`
+	Message    string       `json:"message"`
+	RetryAfter int          `json:"retry_after"`
+}
+
+type ManyAdDetails struct {
+	AdDetails []AdDetails `json:"data"`
+}
+
+// StartCommercialResponse
+type StartCommercialResponse struct {
+	ResponseCommon
+	Data ManyAdDetails
+}
+
+// StartCommercial starts a commercial on a specified channel
+// OAuth Token required
+// Requires channel:edit:commercial scope
+func (c *Client) StartCommercial(params *StartCommercialParams) (*StartCommercialResponse, error) {
+	resp, err := c.post("/channels/commercial", &ManyAdDetails{}, params)
+	if err != nil {
+		return nil, err
+	}
+
+	commercials := &StartCommercialResponse{}
+	resp.HydrateResponseCommon(&commercials.ResponseCommon)
+	commercials.Data.AdDetails = resp.Data.(*ManyAdDetails).AdDetails
+
+	return commercials, nil
+}
diff --git a/entitlement_codes.go b/entitlement_codes.go
index 8e5edc0..91b36d2 100644
--- a/entitlement_codes.go
+++ b/entitlement_codes.go
@@ -55,21 +55,3 @@ func (c *Client) GetEntitlementCodeStatus(params *CodesParams) (*CodeResponse, e
 
 	return codes, nil
 }
-
-/**
-Per https://dev.twitch.tv/docs/api/reference/#redeem-code
-Access is controlled via an app access token on the calling service. The client ID associated with the app access token must be approved by Twitch.
-Callers with an app access token are authorized to redeem codes on behalf of any Twitch user account.
-*/
-func (c *Client) RedeemEntitlementCode(params *CodesParams) (*CodeResponse, error) {
-	resp, err := c.post("/entitlements/code", &ManyCodes{}, params)
-	if err != nil {
-		return nil, err
-	}
-
-	codes := &CodeResponse{}
-	resp.HydrateResponseCommon(&codes.ResponseCommon)
-	codes.Data.Codes = resp.Data.(*ManyCodes).Codes
-
-	return codes, nil
-}


Test patch:
diff --git a/ads_test.go b/ads_test.go
new file mode 100644
index 0000000..823a514
--- /dev/null
+++ b/ads_test.go
@@ -0,0 +1,89 @@
+package helix
+
+import (
+	"net/http"
+	"testing"
+)
+
+func TestClient_StartCommercial(t *testing.T) {
+	t.Parallel()
+
+	testCases := []struct {
+		statusCode     int
+		options        *Options
+		count          int
+		broadcasterId  string
+		adLength       AdLengthEnum
+		respBody       string
+		expectedErrMsg string
+	}{
+		// TODO: expand with other test cases
+
+		// Failure - broadcaster not live
+		{
+			http.StatusBadRequest,
+			&Options{ClientID: "my-client-id"},
+			1,
+			"89754791",
+			AdLen30,
+			`{"error":"Bad Request","status":400,"message":"the channel 'codingsloth' is not currently live and needs to be in order to start commercials."}`,
+			"the channel 'codingsloth' is not currently live and needs to be in order to start commercials.",
+		},
+		// success
+		{
+			http.StatusOK,
+			&Options{ClientID: "my-client-id"},
+			1,
+			"41245072",
+			AdLen60,
+			`{"data":[{"length":60,"message":"","retry_after":480}]}`,
+			"",
+		},
+	}
+
+	for _, testCase := range testCases {
+		c := newMockClient(testCase.options, newMockHandler(testCase.statusCode, testCase.respBody, nil))
+
+		params := &StartCommercialParams{
+			BroadcasterID: testCase.broadcasterId,
+			Length:        testCase.adLength,
+		}
+
+		resp, err := c.StartCommercial(params)
+		if err != nil {
+			t.Error(err)
+		}
+
+		if resp.StatusCode != testCase.statusCode {
+			t.Errorf("expected status code to be \"%d\", got \"%d\"", testCase.statusCode, resp.StatusCode)
+		}
+
+		// Test error cases
+		if resp.StatusCode != http.StatusOK {
+			if resp.ErrorStatus != testCase.statusCode {
+				t.Errorf("expected error status to be \"%d\", got \"%d\"", testCase.statusCode, resp.ErrorStatus)
+			}
+
+			if resp.ErrorMessage != testCase.expectedErrMsg {
+				t.Errorf("expected error message to be \"%s\", got \"%s\"", testCase.expectedErrMsg, resp.ErrorMessage)
+			}
+
+			continue
+		}
+
+		// Test success cases
+		if len(resp.Data.AdDetails) != testCase.count {
+			t.Errorf("expected number of results to be \"%d\", got \"%d\"", testCase.count, len(resp.Data.AdDetails))
+		}
+
+		commercialDetails := resp.Data.AdDetails[0]
+		if commercialDetails.Length != testCase.adLength {
+			t.Error("expected ad length \"#{testCase.adLength}\", got \"#{commercialDetails.Length}\"")
+		}
+
+		if commercialDetails.Message != "" {
+			t.Error("expected an empty error message, got \"#{commercialDetails.Message}\"")
+		}
+
+	}
+}
diff --git a/entitlement_codes_test.go b/entitlement_codes_test.go
index 78ae4b7..6db74d3 100644
--- a/entitlement_codes_test.go
+++ b/entitlement_codes_test.go
@@ -60,59 +60,3 @@ func TestClient_GetEntitlementCodeStatus(t *testing.T) {
 
 	}
 }
-
-func TestClient_RedeemEntitlementCode(t *testing.T) {
-	t.Parallel()
-
-	testCases := []struct {
-		statusCode int
-		options    *Options
-		count      int
-		userId     string
-		codes      []string
-		respBody   string
-	}{
-		// TODO: expand with other test cases, including negative scenarios
-		{
-			http.StatusOK,
-			&Options{ClientID: "my-client-id"},
-			2,
-			"156900877",
-			[]string{"KUHXV-4GXYP-AKAKK", "XZDDZ-5SIQR-RT5M3"},
-			`{"data":[{"code":"KUHXV-4GXYP-AKAKK","status":"SUCCESSFULLY_REDEEMED"},{"code":"XZDDZ-5SIQR-RT5M3","status":"ALREADY_CLAIMED"}]}`,
-		},
-	}
-
-	for _, testCase := range testCases {
-		c := newMockClient(testCase.options, newMockHandler(testCase.statusCode, testCase.respBody, nil))
-
-		params := &CodesParams{
-			UserID: testCase.userId,
-			Codes:  testCase.codes,
-		}
-
-		resp, err := c.GetEntitlementCodeStatus(params)
-		if err != nil {
-			t.Error(err)
-		}
-
-		if resp.StatusCode != testCase.statusCode {
-			t.Errorf("expected status code to be \"%d\", got \"%d\"", testCase.statusCode, resp.StatusCode)
-		}
-
-		// TODO: Test error cases
-
-		// Test success cases
-		if len(resp.Data.Codes) != testCase.count {
-			t.Errorf("expected number of results to be \"%d\", got \"%d\"", testCase.count, len(resp.Data.Codes))
-		}
-
-		for index, code := range testCase.codes {
-			codes := resp.Data.Codes[index]
-			if codes.Code != code {
-				t.Error("expected entitlement code \"#{code}\", got \"#{codes.Code}\"")
-			}
-		}
-
-	}
-}