github.com/google/go-github/v33@v33.0.0/github/messages_test.go (about)

     1  // Copyright 2016 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/json"
    11  	"net/http"
    12  	"net/url"
    13  	"reflect"
    14  	"strings"
    15  	"testing"
    16  )
    17  
    18  func TestValidatePayload(t *testing.T) {
    19  	const defaultBody = `{"yo":true}` // All tests below use the default request body and signature.
    20  	const defaultSignature = "sha1=126f2c800419c60137ce748d7672e77b65cf16d6"
    21  	secretKey := []byte("0123456789abcdef")
    22  	tests := []struct {
    23  		signature   string
    24  		eventID     string
    25  		event       string
    26  		wantEventID string
    27  		wantEvent   string
    28  		wantPayload string
    29  	}{
    30  		// The following tests generate expected errors:
    31  		{},                         // Missing signature
    32  		{signature: "yo"},          // Missing signature prefix
    33  		{signature: "sha1=yo"},     // Signature not hex string
    34  		{signature: "sha1=012345"}, // Invalid signature
    35  		// The following tests expect err=nil:
    36  		{
    37  			signature:   defaultSignature,
    38  			eventID:     "dead-beef",
    39  			event:       "ping",
    40  			wantEventID: "dead-beef",
    41  			wantEvent:   "ping",
    42  			wantPayload: defaultBody,
    43  		},
    44  		{
    45  			signature:   defaultSignature,
    46  			event:       "ping",
    47  			wantEvent:   "ping",
    48  			wantPayload: defaultBody,
    49  		},
    50  		{
    51  			signature:   "sha256=b1f8020f5b4cd42042f807dd939015c4a418bc1ff7f604dd55b0a19b5d953d9b",
    52  			event:       "ping",
    53  			wantEvent:   "ping",
    54  			wantPayload: defaultBody,
    55  		},
    56  		{
    57  			signature:   "sha512=8456767023c1195682e182a23b3f5d19150ecea598fde8cb85918f7281b16079471b1329f92b912c4d8bd7455cb159777db8f29608b20c7c87323ba65ae62e1f",
    58  			event:       "ping",
    59  			wantEvent:   "ping",
    60  			wantPayload: defaultBody,
    61  		},
    62  	}
    63  
    64  	for _, test := range tests {
    65  		buf := bytes.NewBufferString(defaultBody)
    66  		req, err := http.NewRequest("GET", "http://localhost/event", buf)
    67  		if err != nil {
    68  			t.Fatalf("NewRequest: %v", err)
    69  		}
    70  		if test.signature != "" {
    71  			req.Header.Set(signatureHeader, test.signature)
    72  		}
    73  		req.Header.Set("Content-Type", "application/json")
    74  
    75  		got, err := ValidatePayload(req, secretKey)
    76  		if err != nil {
    77  			if test.wantPayload != "" {
    78  				t.Errorf("ValidatePayload(%#v): err = %v, want nil", test, err)
    79  			}
    80  			continue
    81  		}
    82  		if string(got) != test.wantPayload {
    83  			t.Errorf("ValidatePayload = %q, want %q", got, test.wantPayload)
    84  		}
    85  	}
    86  }
    87  
    88  func TestValidatePayload_FormGet(t *testing.T) {
    89  	payload := `{"yo":true}`
    90  	signature := "sha1=3374ef144403e8035423b23b02e2c9d7a4c50368"
    91  	secretKey := []byte("0123456789abcdef")
    92  
    93  	form := url.Values{}
    94  	form.Add("payload", payload)
    95  	req, err := http.NewRequest("POST", "http://localhost/event", strings.NewReader(form.Encode()))
    96  	if err != nil {
    97  		t.Fatalf("NewRequest: %v", err)
    98  	}
    99  	req.PostForm = form
   100  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   101  	req.Header.Set(signatureHeader, signature)
   102  
   103  	got, err := ValidatePayload(req, secretKey)
   104  	if err != nil {
   105  		t.Errorf("ValidatePayload(%#v): err = %v, want nil", payload, err)
   106  	}
   107  	if string(got) != payload {
   108  		t.Errorf("ValidatePayload = %q, want %q", got, payload)
   109  	}
   110  
   111  	// check that if payload is invalid we get error
   112  	req.Header.Set(signatureHeader, "invalid signature")
   113  	if _, err = ValidatePayload(req, []byte{0}); err == nil {
   114  		t.Error("ValidatePayload = nil, want err")
   115  	}
   116  }
   117  
   118  func TestValidatePayload_FormPost(t *testing.T) {
   119  	payload := `{"yo":true}`
   120  	signature := "sha1=3374ef144403e8035423b23b02e2c9d7a4c50368"
   121  	secretKey := []byte("0123456789abcdef")
   122  
   123  	form := url.Values{}
   124  	form.Set("payload", payload)
   125  	buf := bytes.NewBufferString(form.Encode())
   126  	req, err := http.NewRequest("POST", "http://localhost/event", buf)
   127  	if err != nil {
   128  		t.Fatalf("NewRequest: %v", err)
   129  	}
   130  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   131  	req.Header.Set(signatureHeader, signature)
   132  
   133  	got, err := ValidatePayload(req, secretKey)
   134  	if err != nil {
   135  		t.Errorf("ValidatePayload(%#v): err = %v, want nil", payload, err)
   136  	}
   137  	if string(got) != payload {
   138  		t.Errorf("ValidatePayload = %q, want %q", got, payload)
   139  	}
   140  
   141  	// check that if payload is invalid we get error
   142  	req.Header.Set(signatureHeader, "invalid signature")
   143  	if _, err = ValidatePayload(req, []byte{0}); err == nil {
   144  		t.Error("ValidatePayload = nil, want err")
   145  	}
   146  }
   147  
   148  func TestValidatePayload_InvalidContentType(t *testing.T) {
   149  	req, err := http.NewRequest("POST", "http://localhost/event", nil)
   150  	if err != nil {
   151  		t.Fatalf("NewRequest: %v", err)
   152  	}
   153  	req.Header.Set("Content-Type", "invalid content type")
   154  	if _, err = ValidatePayload(req, nil); err == nil {
   155  		t.Error("ValidatePayload = nil, want err")
   156  	}
   157  }
   158  
   159  func TestValidatePayload_NoSecretKey(t *testing.T) {
   160  	payload := `{"yo":true}`
   161  
   162  	form := url.Values{}
   163  	form.Set("payload", payload)
   164  	buf := bytes.NewBufferString(form.Encode())
   165  	req, err := http.NewRequest("POST", "http://localhost/event", buf)
   166  	if err != nil {
   167  		t.Fatalf("NewRequest: %v", err)
   168  	}
   169  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   170  
   171  	got, err := ValidatePayload(req, nil)
   172  	if err != nil {
   173  		t.Errorf("ValidatePayload(%#v): err = %v, want nil", payload, err)
   174  	}
   175  	if string(got) != payload {
   176  		t.Errorf("ValidatePayload = %q, want %q", got, payload)
   177  	}
   178  }
   179  
   180  func TestParseWebHook(t *testing.T) {
   181  	tests := []struct {
   182  		payload     interface{}
   183  		messageType string
   184  	}{
   185  		{
   186  			payload:     &CheckRunEvent{},
   187  			messageType: "check_run",
   188  		},
   189  		{
   190  			payload:     &CheckSuiteEvent{},
   191  			messageType: "check_suite",
   192  		},
   193  		{
   194  			payload:     &CommitCommentEvent{},
   195  			messageType: "commit_comment",
   196  		},
   197  		{
   198  			payload:     &ContentReferenceEvent{},
   199  			messageType: "content_reference",
   200  		},
   201  		{
   202  			payload:     &CreateEvent{},
   203  			messageType: "create",
   204  		},
   205  		{
   206  			payload:     &DeleteEvent{},
   207  			messageType: "delete",
   208  		},
   209  		{
   210  			payload:     &DeployKeyEvent{},
   211  			messageType: "deploy_key",
   212  		},
   213  		{
   214  			payload:     &DeploymentEvent{},
   215  			messageType: "deployment",
   216  		},
   217  
   218  		{
   219  			payload:     &DeploymentStatusEvent{},
   220  			messageType: "deployment_status",
   221  		},
   222  		{
   223  			payload:     &ForkEvent{},
   224  			messageType: "fork",
   225  		},
   226  		{
   227  			payload:     &GitHubAppAuthorizationEvent{},
   228  			messageType: "github_app_authorization",
   229  		},
   230  		{
   231  			payload:     &GollumEvent{},
   232  			messageType: "gollum",
   233  		},
   234  		{
   235  			payload:     &InstallationEvent{},
   236  			messageType: "installation",
   237  		},
   238  		{
   239  			payload:     &InstallationRepositoriesEvent{},
   240  			messageType: "installation_repositories",
   241  		},
   242  		{
   243  			payload:     &IssueCommentEvent{},
   244  			messageType: "issue_comment",
   245  		},
   246  		{
   247  			payload:     &IssuesEvent{},
   248  			messageType: "issues",
   249  		},
   250  		{
   251  			payload:     &LabelEvent{},
   252  			messageType: "label",
   253  		},
   254  		{
   255  			payload:     &MarketplacePurchaseEvent{},
   256  			messageType: "marketplace_purchase",
   257  		},
   258  		{
   259  			payload:     &MemberEvent{},
   260  			messageType: "member",
   261  		},
   262  		{
   263  			payload:     &MembershipEvent{},
   264  			messageType: "membership",
   265  		},
   266  		{
   267  			payload:     &MetaEvent{},
   268  			messageType: "meta",
   269  		},
   270  		{
   271  			payload:     &MilestoneEvent{},
   272  			messageType: "milestone",
   273  		},
   274  		{
   275  			payload:     &OrganizationEvent{},
   276  			messageType: "organization",
   277  		},
   278  		{
   279  			payload:     &OrgBlockEvent{},
   280  			messageType: "org_block",
   281  		},
   282  		{
   283  			payload:     &PackageEvent{},
   284  			messageType: "package",
   285  		},
   286  		{
   287  			payload:     &PageBuildEvent{},
   288  			messageType: "page_build",
   289  		},
   290  		{
   291  			payload:     &PingEvent{},
   292  			messageType: "ping",
   293  		},
   294  		{
   295  			payload:     &ProjectEvent{},
   296  			messageType: "project",
   297  		},
   298  		{
   299  			payload:     &ProjectCardEvent{},
   300  			messageType: "project_card",
   301  		},
   302  		{
   303  			payload:     &ProjectColumnEvent{},
   304  			messageType: "project_column",
   305  		},
   306  		{
   307  			payload:     &PublicEvent{},
   308  			messageType: "public",
   309  		},
   310  		{
   311  			payload:     &PullRequestEvent{},
   312  			messageType: "pull_request",
   313  		},
   314  		{
   315  			payload:     &PullRequestReviewEvent{},
   316  			messageType: "pull_request_review",
   317  		},
   318  		{
   319  			payload:     &PullRequestReviewCommentEvent{},
   320  			messageType: "pull_request_review_comment",
   321  		},
   322  		{
   323  			payload:     &PushEvent{},
   324  			messageType: "push",
   325  		},
   326  		{
   327  			payload:     &ReleaseEvent{},
   328  			messageType: "release",
   329  		},
   330  		{
   331  			payload:     &RepositoryEvent{},
   332  			messageType: "repository",
   333  		},
   334  		{
   335  			payload:     &RepositoryVulnerabilityAlertEvent{},
   336  			messageType: "repository_vulnerability_alert",
   337  		},
   338  		{
   339  			payload:     &StarEvent{},
   340  			messageType: "star",
   341  		},
   342  		{
   343  			payload:     &StatusEvent{},
   344  			messageType: "status",
   345  		},
   346  		{
   347  			payload:     &TeamEvent{},
   348  			messageType: "team",
   349  		},
   350  		{
   351  			payload:     &TeamAddEvent{},
   352  			messageType: "team_add",
   353  		},
   354  		{
   355  			payload:     &UserEvent{},
   356  			messageType: "user",
   357  		},
   358  		{
   359  			payload:     &WatchEvent{},
   360  			messageType: "watch",
   361  		},
   362  		{
   363  			payload:     &RepositoryDispatchEvent{},
   364  			messageType: "repository_dispatch",
   365  		},
   366  		{
   367  			payload:     &WorkflowDispatchEvent{},
   368  			messageType: "workflow_dispatch",
   369  		},
   370  		{
   371  			payload:     &WorkflowRunEvent{},
   372  			messageType: "workflow_run",
   373  		},
   374  	}
   375  
   376  	for _, test := range tests {
   377  		p, err := json.Marshal(test.payload)
   378  		if err != nil {
   379  			t.Fatalf("Marshal(%#v): %v", test.payload, err)
   380  		}
   381  		got, err := ParseWebHook(test.messageType, p)
   382  		if err != nil {
   383  			t.Fatalf("ParseWebHook: %v", err)
   384  		}
   385  		if want := test.payload; !reflect.DeepEqual(got, want) {
   386  			t.Errorf("ParseWebHook(%#v, %#v) = %#v, want %#v", test.messageType, p, got, want)
   387  		}
   388  	}
   389  }
   390  
   391  func TestDeliveryID(t *testing.T) {
   392  	id := "8970a780-244e-11e7-91ca-da3aabcb9793"
   393  	req, err := http.NewRequest("POST", "http://localhost", nil)
   394  	if err != nil {
   395  		t.Fatalf("DeliveryID: %v", err)
   396  	}
   397  	req.Header.Set("X-Github-Delivery", id)
   398  
   399  	got := DeliveryID(req)
   400  	if got != id {
   401  		t.Errorf("DeliveryID(%#v) = %q, want %q", req, got, id)
   402  	}
   403  }