~bigbes/core-go

ref: b98647b61819bf73fa43f92f5727fd58d492f13c core-go/webhooks/legacy_test.go -rw-r--r-- 2.7 KiB
b98647b6 — Drew DeVault Deduplicate webhook headers on subsequent attempts 5 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package webhooks

import (
	"context"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"

	"github.com/DATA-DOG/go-sqlmock"
	"github.com/stretchr/testify/assert"
	"github.com/vaughan0/go-ini"
	sq "github.com/Masterminds/squirrel"

	"git.sr.ht/~sircmpwn/core-go/crypto"
	"git.sr.ht/~sircmpwn/core-go/database"
)

func init() {
	conf, err := ini.Load(strings.NewReader(`
[webhooks]
private-key=ebzsjPaN6E13ln/FeNWly1C92q6bVMVdOnDo1HPl5fc=

[sr.ht]
network-key=tbuG-7Vh44vrDq1L_HKWkHnWrDOtJhEkPKPiauaLeuk=

[test::api]
internal-ipnet=127.0.0.1/24,::1/64`))
	if err != nil {
		panic(err)
	}
	crypto.InitCrypto(conf)
}

func TestDelivery(t *testing.T) {
	var called bool
	srv := httptest.NewServer(http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			defer r.Body.Close()

			called = true
			assert.Equal(t, r.Method, http.MethodPost)
			assert.Equal(t, r.URL.Path, "/webhook")

			assert.NotEqual(t, "", r.Header.Get("X-Webhook-Delivery"))
			assert.Equal(t, "profile:update", r.Header.Get("X-Webhook-Event"))
			assert.Equal(t, "application/json", r.Header.Get("Content-Type"))

			b, err := ioutil.ReadAll(r.Body)
			assert.Nil(t, err)
			assert.Equal(t, `{"hello": "world"}`, string(b))

			nonce := r.Header.Get("X-Payload-Nonce")
			signature := r.Header.Get("X-Payload-Signature")
			assert.True(t, crypto.VerifyWebhook(b, nonce, signature))

			w.Write([]byte("Thanks!"))
		}))
	defer srv.Close()

	queue := NewLegacyQueue()
	q := sq.
		Select().
		From("user_webhook_subscription sub").
		Where(`sub.user_id = ?`, 42)
	queue.Schedule(q, "user", "profile:update", []byte(`{"hello": "world"}`))

	db, mock, err := sqlmock.New()
	if err != nil {
		panic(err)
	}

	// Lookup phase
	mock.ExpectBegin()
	mock.ExpectQuery(`SELECT .* FROM user_webhook_subscription sub`).
		WillReturnRows(sqlmock.NewRows([]string{
			"sub.id", "sub.created", "sub.url", "sub.events",
		}).AddRow(1337, time.Now().UTC(),
			srv.URL + "/webhook", "profile:update")).
		WithArgs(42, sqlmock.AnyArg()) // Any => events LIKE %profile:update%
	mock.ExpectCommit()

	// Schedule phase
	mock.ExpectBegin()
	mock.ExpectQuery(`INSERT INTO user_webhook_delivery`).
		WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(4096))
	mock.ExpectCommit()

	ctx := database.Context(context.Background(), db)
	queue.Queue.Dispatch(ctx)

	assert.Nil(t, mock.ExpectationsWereMet())

	// Delivery phase
	db, mock, err = sqlmock.New()
	if err != nil {
		panic(err)
	}

	mock.ExpectBegin()
	mock.ExpectExec(`UPDATE user_webhook_delivery`).
		WithArgs("Thanks!", 200, sqlmock.AnyArg(), 4096) // Any => response headers
	mock.ExpectCommit()

	ctx = database.Context(context.Background(), db)
	queue.Queue.Dispatch(ctx)

	assert.Nil(t, mock.ExpectationsWereMet())
	assert.True(t, called)
}