Skip to content

Commit 5b0ad9a

Browse files
committed
fix(integrations): sync public API contract and skill commands
1 parent ec0922a commit 5b0ad9a

7 files changed

Lines changed: 339 additions & 45 deletions

File tree

‎go.mod‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module github.com/flashcatcloud/flashduty-cli
33
go 1.26.0
44

55
require (
6-
github.com/flashcatcloud/go-flashduty v0.15.14
6+
github.com/flashcatcloud/go-flashduty v0.15.13-0.20261012034738-577bf0504904
77
github.com/mattn/go-runewidth v0.0.30
88
github.com/spf13/cobra v1.10.2
99
github.com/spf13/pflag v1.0.10

‎go.sum‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=
22
github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
33
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
4-
github.com/flashcatcloud/go-flashduty v0.15.14 h1:185WAkgahlRnLBk3jI6kYL2t8IoH5YtQ9Pd4ckEPRWM=
5-
github.com/flashcatcloud/go-flashduty v0.15.14/go.mod h1:YpHiTYXR5NXBI/rGRZfUy537XMkhdCkwA8NW1QoRHwk=
4+
github.com/flashcatcloud/go-flashduty v0.15.13-0.20261012034738-577bf0504904 h1:5ldIZhq/PKdJaZ/CX5Pafa5hJCNcYIWFFJz2R9R+Xp0=
5+
github.com/flashcatcloud/go-flashduty v0.15.13-0.20261012034738-577bf0504904/go.mod h1:YpHiTYXR5NXBI/rGRZfUy537XMkhdCkwA8NW1QoRHwk=
66
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
77
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
88
github.com/mattn/go-runewidth v0.0.30 h1:+KUuiDA4fF0R1p5FeueHefjDm+GIM+kWfFnDjybOPgk=
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package cli
2+
3+
import (
4+
"encoding/json"
5+
"reflect"
6+
"testing"
7+
)
8+
9+
func integrationContractFixture() map[string]any {
10+
return map[string]any{
11+
"integration_id": 42, "data_source_id": 42, "account_id": 100, "exclusive_data_source_id": 0,
12+
"name": "Contract fixture", "description": "", "team_id": 7,
13+
"category": "im", "plugin_type": "slack_app", "plugin_type_name": "Slack", "plugin_id": 9,
14+
"ref_id": "a_100", "status": "enabled", "created_at": 1700000000, "updated_at": 1700000001, "last_time": 0,
15+
"creator_id": 11, "updated_by": 12, "no_editable": false, "editable": true,
16+
"settings": map[string]any{"headers": map[string]any{"Authorization": "fixture-not-a-real-secret"}},
17+
"integration_key": "fixture-not-a-real-key",
18+
}
19+
}
20+
21+
func TestIntegrationListPreservesConfigurationAndPermissions(t *testing.T) {
22+
saveAndResetGlobals(t)
23+
stub := newGFStub(t)
24+
fixture := integrationContractFixture()
25+
stub.data = map[string]any{"p": 1, "limit": 100, "total": 1, "items": []any{fixture}}
26+
out, err := execCommand("integration", "list", "--json")
27+
if err != nil {
28+
t.Fatal(err)
29+
}
30+
var result map[string]any
31+
if err := json.Unmarshal([]byte(out), &result); err != nil {
32+
t.Fatal(err)
33+
}
34+
items, ok := result["items"].([]any)
35+
if !ok || len(items) != 1 {
36+
t.Fatalf("unexpected list output: %s", out)
37+
}
38+
item := items[0].(map[string]any)
39+
for field := range fixture {
40+
if _, ok := item[field]; !ok {
41+
t.Errorf("list dropped backend field %s", field)
42+
}
43+
}
44+
for _, field := range []string{"settings", "integration_key", "editable", "no_editable"} {
45+
if !reflect.DeepEqual(item[field], fixture[field]) {
46+
t.Errorf("%s changed: got %#v, want %#v", field, item[field], fixture[field])
47+
}
48+
}
49+
if stub.lastPath != "/integration/list" {
50+
t.Fatalf("request path = %s", stub.lastPath)
51+
}
52+
}
53+
54+
func TestIntegrationInfoPreservesConfigurationAndTestResult(t *testing.T) {
55+
for _, withTest := range []bool{false, true} {
56+
t.Run(map[bool]string{false: "absent test", true: "failed test"}[withTest], func(t *testing.T) {
57+
saveAndResetGlobals(t)
58+
stub := newGFStub(t)
59+
fixture := integrationContractFixture()
60+
for _, field := range []string{"account_id", "data_source_id", "exclusive_data_source_id"} {
61+
delete(fixture, field)
62+
}
63+
if withTest {
64+
fixture["test"] = map[string]any{"success": false, "message": "fixture plugin test failed"}
65+
}
66+
stub.data = fixture
67+
out, err := execCommand("integration", "info", "42", "--json")
68+
if err != nil {
69+
t.Fatal(err)
70+
}
71+
var result map[string]any
72+
if err := json.Unmarshal([]byte(out), &result); err != nil {
73+
t.Fatal(err)
74+
}
75+
for _, field := range []string{"settings", "integration_key", "plugin_id", "editable", "creator_id", "updated_by", "no_editable"} {
76+
if _, ok := result[field]; !ok {
77+
t.Errorf("info dropped backend field %s", field)
78+
}
79+
}
80+
if !reflect.DeepEqual(result["settings"], fixture["settings"]) || result["integration_key"] != fixture["integration_key"] {
81+
t.Errorf("info changed configuration or key: %s", out)
82+
}
83+
if !reflect.DeepEqual(result["test"], fixture["test"]) {
84+
t.Errorf("test result changed: %s", out)
85+
}
86+
if !withTest {
87+
if _, ok := result["test"]; ok {
88+
t.Errorf("absent test was fabricated: %s", out)
89+
}
90+
}
91+
})
92+
}
93+
}
94+
95+
func TestIntegrationCreatePreservesKeyAndPluginTest(t *testing.T) {
96+
for _, mode := range []string{"data", "flags"} {
97+
t.Run(mode, func(t *testing.T) {
98+
saveAndResetGlobals(t)
99+
stub := newGFStub(t)
100+
stub.data = map[string]any{"integration_id": 42, "integration_key": "fixture-key", "test": map[string]any{"success": false, "message": "fixture plugin test failed"}}
101+
args := []string{"integration", "create", "--json", "--data", `{"plugin_type":"standard.alert","integration_key":"00000000000000000000000000000000100","is_test":true}`}
102+
if mode == "flags" {
103+
args = []string{"integration", "create", "--json", "--plugin-type", "standard.alert", "--integration-key", "00000000000000000000000000000000100", "--is-test"}
104+
}
105+
out, err := execCommand(args...)
106+
if err != nil {
107+
t.Fatal(err)
108+
}
109+
if stub.lastBody["integration_key"] != "00000000000000000000000000000000100" || stub.lastBody["is_test"] != true {
110+
t.Errorf("create dropped key or test flag: %#v", stub.lastBody)
111+
}
112+
var result map[string]any
113+
if err := json.Unmarshal([]byte(out), &result); err != nil {
114+
t.Fatal(err)
115+
}
116+
if !reflect.DeepEqual(result["test"], stub.data.(map[string]any)["test"]) {
117+
t.Errorf("create lost failed plugin test: %s", out)
118+
}
119+
})
120+
}
121+
}
122+
123+
func TestIntegrationUpdatePreservesTestAndExplicitEmptyHeaders(t *testing.T) {
124+
saveAndResetGlobals(t)
125+
stub := newGFStub(t)
126+
_, err := execCommand("integration", "update", "42", "--team-id", "0", "--is-test", "--data", `{"settings":{"headers":{}}}`)
127+
if err != nil {
128+
t.Fatal(err)
129+
}
130+
if stub.lastBody["is_test"] != true || stub.lastBody["team_id"] != float64(0) {
131+
t.Errorf("update lost test flag or explicit team clear: %#v", stub.lastBody)
132+
}
133+
want := map[string]any{"headers": map[string]any{}}
134+
if !reflect.DeepEqual(stub.lastBody["settings"], want) {
135+
t.Errorf("update changed explicit empty headers: %#v", stub.lastBody)
136+
}
137+
}

0 commit comments

Comments
 (0)