1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package lunatask_test
6
7import (
8 "net/http"
9 "net/http/httptest"
10 "net/url"
11 "testing"
12 "time"
13
14 lunatask "git.secluded.site/go-lunatask"
15)
16
17const personID = "5999b945-b2b1-48c6-aa72-b251b75b3c2e"
18
19// --- ListPeople ---
20
21func TestListPeople_Success(t *testing.T) {
22 t.Parallel()
23
24 server := newJSONServer(t, "/people", peopleResponseBody)
25 defer server.Close()
26
27 client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))
28
29 people, err := client.ListPeople(ctx(), nil)
30 if err != nil {
31 t.Fatalf("error = %v", err)
32 }
33
34 if len(people) != 2 {
35 t.Fatalf("len = %d, want 2", len(people))
36 }
37
38 person := people[0]
39 if person.ID != personID {
40 t.Errorf("ID = %q, want %q", person.ID, personID)
41 }
42
43 if person.RelationshipStrength == nil || *person.RelationshipStrength != lunatask.RelationshipBusiness {
44 t.Errorf("RelationshipStrength = %v, want %v", person.RelationshipStrength, lunatask.RelationshipBusiness)
45 }
46
47 wantCreated := time.Date(2021, 1, 10, 10, 39, 25, 0, time.UTC)
48 if !person.CreatedAt.Equal(wantCreated) {
49 t.Errorf("CreatedAt = %v, want %v", person.CreatedAt, wantCreated)
50 }
51}
52
53func TestListPeople_Filter(t *testing.T) {
54 t.Parallel()
55
56 tests := []filterTest{
57 {
58 Name: "source_only",
59 Source: ptr("salesforce"),
60 SourceID: nil,
61 WantQuery: url.Values{"source": {"salesforce"}},
62 },
63 {
64 Name: "source_and_id",
65 Source: ptr("salesforce"),
66 SourceID: ptr("sf-123"),
67 WantQuery: url.Values{"source": {"salesforce"}, "source_id": {"sf-123"}},
68 },
69 }
70
71 runFilterTests(t, "/people", `{"people": []}`, tests, func(c *lunatask.Client, source, sourceID *string) error {
72 opts := &lunatask.ListPeopleOptions{Source: source, SourceID: sourceID}
73 _, err := c.ListPeople(ctx(), opts)
74
75 return err //nolint:wrapcheck // test helper
76 })
77}
78
79func TestListPeople_Errors(t *testing.T) {
80 t.Parallel()
81
82 testErrorCases(t, func(c *lunatask.Client) error {
83 _, err := c.ListPeople(ctx(), nil)
84
85 return err //nolint:wrapcheck // test helper
86 })
87}
88
89// --- GetPerson ---
90
91func TestGetPerson_Success(t *testing.T) {
92 t.Parallel()
93
94 server := newJSONServer(t, "/people/"+personID, singlePersonResponseBody)
95 defer server.Close()
96
97 client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))
98
99 person, err := client.GetPerson(ctx(), personID)
100 if err != nil {
101 t.Fatalf("error = %v", err)
102 }
103
104 if person == nil {
105 t.Fatal("returned nil")
106 }
107
108 if person.ID != personID {
109 t.Errorf("ID = %q, want %q", person.ID, personID)
110 }
111
112 if len(person.Sources) != 1 || person.Sources[0].Source != "salesforce" {
113 t.Errorf("Sources = %v, want salesforce source", person.Sources)
114 }
115}
116
117func TestGetPerson_Errors(t *testing.T) {
118 t.Parallel()
119
120 testErrorCases(t, func(c *lunatask.Client) error {
121 _, err := c.GetPerson(ctx(), personID)
122
123 return err //nolint:wrapcheck // test helper
124 })
125}
126
127// --- CreatePerson ---
128
129func TestCreatePerson_Success(t *testing.T) {
130 t.Parallel()
131
132 server, capture := newPOSTServer(t, "/people", singlePersonResponseBody)
133 defer server.Close()
134
135 client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))
136
137 person, err := lunatask.NewPerson("John", "Doe").
138 WithRelationshipStrength(lunatask.RelationshipBusiness).
139 FromSource("salesforce", "sf-123").
140 Create(ctx(), client)
141 if err != nil {
142 t.Fatalf("error = %v", err)
143 }
144
145 if person == nil {
146 t.Fatal("returned nil")
147 }
148
149 if person.ID != personID {
150 t.Errorf("ID = %q, want %q", person.ID, personID)
151 }
152
153 assertBodyField(t, capture.Body, "first_name", "John")
154 assertBodyField(t, capture.Body, "last_name", "Doe")
155 assertBodyField(t, capture.Body, "relationship_strength", "business-contacts")
156 assertBodyField(t, capture.Body, "source", "salesforce")
157 assertBodyField(t, capture.Body, "source_id", "sf-123")
158}
159
160func TestCreatePerson_WithCustomFields(t *testing.T) {
161 t.Parallel()
162
163 server, capture := newPOSTServer(t, "/people", singlePersonResponseBody)
164 defer server.Close()
165
166 client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))
167
168 _, err := lunatask.NewPerson("Ada", "Lovelace").
169 WithRelationshipStrength(lunatask.RelationshipCloseFriend).
170 WithCustomField("email", "ada@example.com").
171 WithCustomField("phone", "+1234567890").
172 Create(ctx(), client)
173 if err != nil {
174 t.Fatalf("error = %v", err)
175 }
176
177 assertBodyField(t, capture.Body, "first_name", "Ada")
178 assertBodyField(t, capture.Body, "last_name", "Lovelace")
179 assertBodyField(t, capture.Body, "relationship_strength", "close-friends")
180 assertBodyField(t, capture.Body, "email", "ada@example.com")
181 assertBodyField(t, capture.Body, "phone", "+1234567890")
182}
183
184func TestCreatePerson_Duplicate(t *testing.T) {
185 t.Parallel()
186
187 server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
188 writer.WriteHeader(http.StatusNoContent)
189 }))
190 defer server.Close()
191
192 client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))
193
194 person, err := lunatask.NewPerson("Dup", "Person").
195 FromSource("salesforce", "dup-123").
196 Create(ctx(), client)
197 if err != nil {
198 t.Fatalf("error = %v, want nil", err)
199 }
200
201 if person != nil {
202 t.Errorf("person = %v, want nil for duplicate", person)
203 }
204}
205
206func TestCreatePerson_Errors(t *testing.T) {
207 t.Parallel()
208
209 testErrorCases(t, func(c *lunatask.Client) error {
210 _, err := lunatask.NewPerson("Test", "User").Create(ctx(), c)
211
212 return err //nolint:wrapcheck // test helper
213 })
214}
215
216// --- DeletePerson ---
217
218func TestDeletePerson_Success(t *testing.T) {
219 t.Parallel()
220
221 server := newDELETEServer(t, "/people/"+personID, singlePersonResponseBody)
222 defer server.Close()
223
224 client := lunatask.NewClient(testToken, lunatask.BaseURL(server.URL))
225
226 person, err := client.DeletePerson(ctx(), personID)
227 if err != nil {
228 t.Fatalf("error = %v", err)
229 }
230
231 if person == nil {
232 t.Fatal("returned nil")
233 }
234
235 if person.ID != personID {
236 t.Errorf("ID = %q, want %q", person.ID, personID)
237 }
238}
239
240func TestDeletePerson_Errors(t *testing.T) {
241 t.Parallel()
242
243 testErrorCases(t, func(c *lunatask.Client) error {
244 _, err := c.DeletePerson(ctx(), personID)
245
246 return err //nolint:wrapcheck // test helper
247 })
248}
249
250// --- Test Data ---
251
252const singlePersonResponseBody = `{
253 "person": {
254 "id": "5999b945-b2b1-48c6-aa72-b251b75b3c2e",
255 "relationship_strength": "business-contacts",
256 "sources": [{"source": "salesforce", "source_id": "352fd2d7-cdc0-4e91-a0a3-9d6cc9d440e7"}],
257 "created_at": "2021-01-10T10:39:25Z",
258 "updated_at": "2021-01-10T10:39:25Z"
259 }
260}`
261
262const peopleResponseBody = `{
263 "people": [
264 {
265 "id": "5999b945-b2b1-48c6-aa72-b251b75b3c2e",
266 "relationship_strength": "business-contacts",
267 "sources": [{"source": "salesforce", "source_id": "352fd2d7-cdc0-4e91-a0a3-9d6cc9d440e7"}],
268 "created_at": "2021-01-10T10:39:25Z",
269 "updated_at": "2021-01-10T10:39:25Z"
270 },
271 {
272 "id": "109cbf01-dba9-4136-8cf1-a02084ba3977",
273 "relationship_strength": "family",
274 "sources": [],
275 "created_at": "2021-01-10T10:39:25Z",
276 "updated_at": "2021-01-10T10:39:25Z"
277 }
278 ]
279}`