github.com/twilio/twilio-go@v1.20.1/webhook_cluster_test.go (about)

     1  //go:build webhook_cluster
     2  // +build webhook_cluster
     3  
     4  package twilio
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"net/http"
    10  	"os"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/localtunnel/go-localtunnel"
    15  	"github.com/stretchr/testify/assert"
    16  	twilio "github.com/twilio/twilio-go/client"
    17  	StudioV2 "github.com/twilio/twilio-go/rest/studio/v2"
    18  )
    19  
    20  var testClient *RestClient
    21  var authToken string
    22  
    23  func TestMain(m *testing.M) {
    24  	var apiKey = os.Getenv("TWILIO_API_KEY")
    25  	var secret = os.Getenv("TWILIO_API_SECRET")
    26  	var accountSid = os.Getenv("TWILIO_ACCOUNT_SID")
    27  	authToken = os.Getenv("TWILIO_AUTH_TOKEN")
    28  	testClient = NewRestClientWithParams(ClientParams{apiKey, secret, accountSid, nil})
    29  	ret := m.Run()
    30  	os.Exit(ret)
    31  }
    32  
    33  func createValidationServer(channel chan bool) *http.Server {
    34  	server := &http.Server{}
    35  	server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    36  		url := r.Header["X-Forwarded-Proto"][0] + "://" + r.Header["X-Forwarded-Host"][0] + r.URL.RequestURI()
    37  		signatureHeader := r.Header["X-Twilio-Signature"]
    38  		r.ParseForm()
    39  		params := make(map[string]string)
    40  		for k, v := range r.PostForm {
    41  			params[k] = v[0]
    42  		}
    43  		requestValidator := twilio.NewRequestValidator(authToken)
    44  		if len(signatureHeader) != 0 {
    45  			channel <- requestValidator.Validate(url, params, r.Header["X-Twilio-Signature"][0])
    46  		} else {
    47  			channel <- false
    48  		}
    49  	})
    50  	return server
    51  }
    52  
    53  func createStudioFlowParams(url string, method string) *StudioV2.CreateFlowParams {
    54  	jsonStr := fmt.Sprintf(`{
    55  		"description": "Studio Flow",
    56  		"states": [
    57  		  {
    58  			"name": "Trigger",
    59  			"type": "trigger",
    60  			"transitions": [
    61  			  {
    62  				"next": "httpRequest",
    63  				"event": "incomingRequest"
    64  			  }
    65  			],
    66  			"properties": {
    67  			}
    68  		  },
    69  		  {
    70  			"name": "httpRequest",
    71  			"type": "make-http-request",
    72  			"transitions": [],
    73  			"properties": {
    74  			  "method": "%s",
    75  			  "content_type": "application/x-www-form-urlencoded;charset=utf-8",
    76  			  "url": "%s"
    77  			}
    78  		  }
    79  		],
    80  		"initial_state": "Trigger",
    81  		"flags": {
    82  		  "allow_concurrent_calls": true
    83  		}
    84  	  }`, method, url)
    85  
    86  	var definition interface{}
    87  	_ = json.Unmarshal([]byte(jsonStr), &definition)
    88  
    89  	params := &StudioV2.CreateFlowParams{
    90  		Definition: &definition,
    91  	}
    92  	params.SetFriendlyName("Go Cluster Test Flow")
    93  	params.SetStatus("published")
    94  	return params
    95  }
    96  
    97  func createStudioExecutionParams() *StudioV2.CreateExecutionParams {
    98  	executionParams := &StudioV2.CreateExecutionParams{}
    99  	executionParams.SetTo("To")
   100  	executionParams.SetFrom("From")
   101  	return executionParams
   102  }
   103  
   104  func executeFlow(t *testing.T, flowSid string) {
   105  	_, exeErr := testClient.StudioV2.CreateExecution(flowSid, createStudioExecutionParams())
   106  	if exeErr != nil {
   107  		t.Fatal("Error with Studio Execution Creation: ", exeErr)
   108  	}
   109  }
   110  
   111  func requestValidation(t *testing.T, method string) {
   112  	//Invoke Localtunnel
   113  	listener, ltErr := localtunnel.Listen(localtunnel.Options{})
   114  	if ltErr != nil {
   115  		t.Fatal("Error with Localtunnel: ", ltErr)
   116  	}
   117  	//Create Validation Server & Listen
   118  	channel := make(chan bool)
   119  	server := createValidationServer(channel)
   120  	go server.Serve(listener)
   121  
   122  	//Extra time for server to set up
   123  	time.Sleep(1 * time.Second)
   124  
   125  	//Create Studio Flow
   126  	params := createStudioFlowParams(listener.URL(), method)
   127  	resp, flowErr := testClient.StudioV2.CreateFlow(params)
   128  	if flowErr != nil {
   129  		t.Fatal("Error with Studio Flow Creation: ", flowErr)
   130  	}
   131  	flowSid := *resp.Sid
   132  	executeFlow(t, flowSid)
   133  
   134  	//Await for Request Validation
   135  	afterCh := time.After(5 * time.Second)
   136  	select {
   137  	case validate := <-channel:
   138  		assert.True(t, validate)
   139  	case <-afterCh:
   140  		t.Fatal("No request was sent to validation server")
   141  	}
   142  	defer testClient.StudioV2.DeleteFlow(flowSid)
   143  	defer server.Close()
   144  }
   145  
   146  func TestRequestValidation_GETMethod(t *testing.T) {
   147  	requestValidation(t, "GET")
   148  }
   149  
   150  func TestRequestValidation_POSTMethod(t *testing.T) {
   151  	requestValidation(t, "POST")
   152  }