Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions cmd/event_patterns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package cmd

import (
"fmt"

"github.com/loops-so/cli/internal/config"
"github.com/loops-so/loops-go"
"github.com/spf13/cobra"
)

func runEventPatternsList(cfg *config.Config, params loops.PaginationParams) ([]loops.EventPatternSummary, error) {
client := newAPIClient(cfg)
if params.Cursor != "" {
patterns, _, err := client.ListEventPatterns(params)
return patterns, err
}
return loops.Paginate(func(cursor string) ([]loops.EventPatternSummary, *loops.Pagination, error) {
return client.ListEventPatterns(loops.PaginationParams{
PerPage: params.PerPage,
Cursor: cursor,
})
})
}

func runEventPatternsGet(cfg *config.Config, id, name string) (*loops.EventPattern, error) {
client := newAPIClient(cfg)
if name != "" {
return client.GetEventPatternByName(name)
}
return client.GetEventPattern(id)
}

var eventPatternsCmd = &cobra.Command{
Use: "event-patterns",
Short: "Manage event patterns",
}

var eventPatternsListCmd = &cobra.Command{
Use: "list",
Short: "List event patterns",
RunE: func(cmd *cobra.Command, args []string) error {
cfg, err := loadConfig()
if err != nil {
return err
}

patterns, err := runEventPatternsList(cfg, paginationParams(cmd))
if err != nil {
return err
}

if isJSONOutput() {
if patterns == nil {
patterns = []loops.EventPatternSummary{}
}
return printJSON(cmd.OutOrStdout(), patterns)
}

if len(patterns) == 0 {
fmt.Fprintln(cmd.OutOrStdout(), "No event patterns found.")
return nil
}

t := newStyledTable(cmd.OutOrStdout(), "ID", "EVENT NAME", "WEBHOOK PLATFORM")
for _, p := range patterns {
t.Row(p.ID, p.EventName, deref(p.IncomingWebhookPlatform))
}
return t.Render()
},
}

var eventPatternsGetCmd = &cobra.Command{
Use: "get",
Short: "Get an event pattern by id or name",
RunE: func(cmd *cobra.Command, args []string) error {
cfg, err := loadConfig()
if err != nil {
return err
}

id, _ := cmd.Flags().GetString("id")
name, _ := cmd.Flags().GetString("name")

p, err := runEventPatternsGet(cfg, id, name)
if err != nil {
return err
}

if isJSONOutput() {
return printJSON(cmd.OutOrStdout(), p)
}

t := newStyledTable(cmd.OutOrStdout(), "FIELD", "VALUE")
t.Row("id", p.ID)
t.Row("eventName", p.EventName)
t.Row("incomingWebhookPlatform", deref(p.IncomingWebhookPlatform))
t.Row("eventProperties", fmt.Sprintf("%d properties (see -o json)", len(p.EventProperties)))
return t.Render()
},
}

func init() {
addPaginationFlags(eventPatternsListCmd)
eventPatternsGetCmd.Flags().String("id", "", "Event pattern ID")
eventPatternsGetCmd.Flags().String("name", "", "Event name")
eventPatternsGetCmd.MarkFlagsMutuallyExclusive("id", "name")
eventPatternsGetCmd.MarkFlagsOneRequired("id", "name")
eventPatternsCmd.AddCommand(eventPatternsListCmd)
eventPatternsCmd.AddCommand(eventPatternsGetCmd)
rootCmd.AddCommand(eventPatternsCmd)
}
131 changes: 131 additions & 0 deletions cmd/event_patterns_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package cmd

import (
"net/http"
"testing"

"github.com/loops-so/loops-go"
)

func TestRunEventPatternsList(t *testing.T) {
t.Run("returns event patterns", func(t *testing.T) {
body := `{
"pagination":{"nextCursor":""},
"data":[
{"id":"ep_1","eventName":"purchase.completed","incomingWebhookPlatform":"stripe"},
{"id":"ep_2","eventName":"signed_up","incomingWebhookPlatform":null}
]
}`
cap := serveJSONCapture(t, http.StatusOK, body)

patterns, err := runEventPatternsList(cfg(t), loops.PaginationParams{PerPage: "10"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(patterns) != 2 {
t.Fatalf("expected 2 patterns, got %d", len(patterns))
}
if patterns[0].ID != "ep_1" {
t.Errorf("ID = %q, want ep_1", patterns[0].ID)
}
if deref(patterns[0].IncomingWebhookPlatform) != "stripe" {
t.Errorf("IncomingWebhookPlatform = %q, want stripe", deref(patterns[0].IncomingWebhookPlatform))
}
if patterns[1].IncomingWebhookPlatform != nil {
t.Errorf("IncomingWebhookPlatform = %v, want nil", patterns[1].IncomingWebhookPlatform)
}
if cap.Method != http.MethodGet {
t.Errorf("Method = %q, want GET", cap.Method)
}
if cap.Path != "/event-patterns?perPage=10" {
t.Errorf("Path = %q, want /event-patterns?perPage=10", cap.Path)
}
})

t.Run("single page when cursor set", func(t *testing.T) {
body := `{"pagination":{"nextCursor":"next"},"data":[{"id":"ep_1","eventName":"purchase.completed","incomingWebhookPlatform":null}]}`
cap := serveJSONCapture(t, http.StatusOK, body)

patterns, err := runEventPatternsList(cfg(t), loops.PaginationParams{Cursor: "abc"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(patterns) != 1 {
t.Fatalf("expected 1 pattern, got %d", len(patterns))
}
if cap.Path != "/event-patterns?cursor=abc" {
t.Errorf("Path = %q, want /event-patterns?cursor=abc", cap.Path)
}
})

t.Run("returns error on api failure", func(t *testing.T) {
serveJSON(t, http.StatusUnauthorized, `{"error":"unauthorized"}`)
_, err := runEventPatternsList(cfg(t), loops.PaginationParams{})
if err == nil {
t.Fatal("expected error, got nil")
}
})
}

func TestRunEventPatternsGet(t *testing.T) {
body := `{
"id": "ep_123",
"eventName": "purchase.completed",
"incomingWebhookPlatform": "stripe",
"eventProperties": [
{"name": "amount", "type": "number"},
{"name": "currency", "type": "string"}
]
}`

t.Run("by id", func(t *testing.T) {
cap := serveJSONCapture(t, http.StatusOK, body)
p, err := runEventPatternsGet(cfg(t), "ep_123", "")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if p.ID != "ep_123" {
t.Errorf("ID = %q, want ep_123", p.ID)
}
if p.EventName != "purchase.completed" {
t.Errorf("EventName = %q, want purchase.completed", p.EventName)
}
if deref(p.IncomingWebhookPlatform) != "stripe" {
t.Errorf("IncomingWebhookPlatform = %q, want stripe", deref(p.IncomingWebhookPlatform))
}
if len(p.EventProperties) != 2 {
t.Fatalf("expected 2 event properties, got %d", len(p.EventProperties))
}
if p.EventProperties[0].Name != "amount" || p.EventProperties[0].Type != "number" {
t.Errorf("EventProperties[0] = %+v, want {amount number}", p.EventProperties[0])
}
if cap.Method != http.MethodGet {
t.Errorf("Method = %q, want GET", cap.Method)
}
if cap.Path != "/event-patterns/ep_123" {
t.Errorf("Path = %q, want /event-patterns/ep_123", cap.Path)
}
})

t.Run("by name", func(t *testing.T) {
cap := serveJSONCapture(t, http.StatusOK, body)
p, err := runEventPatternsGet(cfg(t), "", "purchase.completed")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if p.ID != "ep_123" {
t.Errorf("ID = %q, want ep_123", p.ID)
}
if cap.Path != "/event-patterns/by-name/purchase.completed" {
t.Errorf("Path = %q, want /event-patterns/by-name/purchase.completed", cap.Path)
}
})

t.Run("returns error on non-200 response", func(t *testing.T) {
serveJSON(t, http.StatusNotFound, `{"success":false,"message":"Event pattern not found"}`)
_, err := runEventPatternsGet(cfg(t), "ep_missing", "")
if err == nil {
t.Fatal("expected error, got nil")
}
})
}