Passed
Push — master ( d13f3d...d155b0 )
by Stanislav
01:27
created

client.getTestDate   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
package client
2
3
import (
4
	"testing"
5
	"log"
6
	"github.com/viasite/planfix-toggl-server/app/config"
7
	"github.com/popstas/planfix-go/planfix"
8
	"net/http/httptest"
9
	"net/http"
10
	"io/ioutil"
11
	"encoding/xml"
12
	"github.com/popstas/go-toggl"
13
	"time"
14
	"bytes"
15
	"github.com/stretchr/testify/assert"
16
	"github.com/stretchr/testify/mock"
17
)
18
19
var output bytes.Buffer
20
21
type planfixRequestStruct struct {
22
	XMLName xml.Name `xml:"request"`
23
	Method  string   `xml:"method,attr"`
24
	Account string   `xml:"account"`
25
	Sid     string   `xml:"sid"`
26
}
27
28
func fixtureFromFile(fixtureName string) string {
29
	buf, _ := ioutil.ReadFile("../../tests/fixtures/" + fixtureName)
30
	return string(buf)
31
}
32
33
type MockedServer struct {
34
	*httptest.Server
35
	Requests  [][]byte
36
	Responses []string // fifo queue of answers
37
}
38
39
func NewMockedServer(responses []string) *MockedServer {
40
	s := &MockedServer{
41
		Requests:  [][]byte{},
42
		Responses: responses,
43
	}
44
45
	s.Server = httptest.NewServer(s)
46
	return s
47
}
48
49
func (s *MockedServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
50
	lastRequest, err := ioutil.ReadAll(req.Body)
51
	if err != nil {
52
		panic(err)
53
	}
54
55
	rs := planfixRequestStruct{}
56
	err = xml.Unmarshal(lastRequest, &rs)
57
	if err != nil {
58
		panic(err)
59
	}
60
	s.Requests = append(s.Requests, lastRequest)
61
	answer := s.Responses[0]
62
63
	s.Responses = s.Responses[1:]
64
	resp.Write([]byte(answer))
65
}
66
67
type MockedTogglSession struct {
68
	mock.Mock
69
	TogglSession
70
}
71
72
func (s *MockedTogglSession) GetAccount() (toggl.Account, error) {
73
	args := s.Called()
74
	return args.Get(0).(toggl.Account), args.Error(1)
75
}
76
77
func (s *MockedTogglSession) GetDetailedReport(workspace int, since, until string, page int) (toggl.DetailedReport, error) {
78
	args := s.Called(workspace, since, until, page)
79
	return args.Get(0).(toggl.DetailedReport), args.Error(1)
80
}
81
82
func (s *MockedTogglSession) AddRemoveTag(entryID int, tag string, add bool) (toggl.TimeEntry, error) {
83
	args := s.Called(entryID, tag, add)
84
	return args.Get(0).(toggl.TimeEntry), args.Error(1)
85
}
86
87
func newClient() TogglClient {
88
	cfg := config.Config{
89
		TogglSentTag: "sent",
90
	}
91
	api := planfix.New("", "apiKey", "account", "user", "password")
92
	api.Sid = "123"
93
94
	sess := &MockedTogglSession{}
95
	return TogglClient{
96
		Session:    sess,
97
		Config:     &cfg,
98
		PlanfixAPI: api,
99
		Logger:     log.New(&output, "", log.LstdFlags),
100
	}
101
}
102
103
func getTestEntries() []TogglPlanfixEntry {
104
	return []TogglPlanfixEntry{
105
		{
106
			toggl.DetailedTimeEntry{Duration: 1},
107
			PlanfixEntryData{TaskID: 1, GroupCount: 1},
108
		},
109
		{
110
			toggl.DetailedTimeEntry{Duration: 2},
111
			PlanfixEntryData{TaskID: 1, GroupCount: 1},
112
		},
113
		{
114
			toggl.DetailedTimeEntry{Duration: 3},
115
			PlanfixEntryData{TaskID: 2, GroupCount: 1},
116
		},
117
		{
118
			toggl.DetailedTimeEntry{Duration: 4},
119
			PlanfixEntryData{TaskID: 2, GroupCount: 1},
120
		},
121
		{
122
			toggl.DetailedTimeEntry{Duration: 5},
123
			PlanfixEntryData{TaskID: 2, GroupCount: 1},
124
		},
125
		{
126
			toggl.DetailedTimeEntry{Duration: 6},
127
			PlanfixEntryData{TaskID: 3, GroupCount: 1},
128
		},
129
	}
130
}
131
132
func getTestGroupedEntries() map[int][]TogglPlanfixEntry {
133
	return map[int][]TogglPlanfixEntry{
134
		1: {
135
			{
136
				toggl.DetailedTimeEntry{Duration: 1},
137
				PlanfixEntryData{TaskID: 1, GroupCount: 1},
138
			},
139
			{
140
				toggl.DetailedTimeEntry{Duration: 2},
141
				PlanfixEntryData{TaskID: 1, GroupCount: 1},
142
			},
143
		},
144
		2: {
145
			{
146
				toggl.DetailedTimeEntry{Duration: 3},
147
				PlanfixEntryData{TaskID: 2, GroupCount: 1},
148
			},
149
			{
150
				toggl.DetailedTimeEntry{Duration: 4},
151
				PlanfixEntryData{TaskID: 2, GroupCount: 1},
152
			},
153
			{
154
				toggl.DetailedTimeEntry{Duration: 5},
155
				PlanfixEntryData{TaskID: 2, GroupCount: 1},
156
			},
157
		},
158
		3: {
159
			{
160
				toggl.DetailedTimeEntry{Duration: 6},
161
				PlanfixEntryData{TaskID: 3, GroupCount: 1},
162
			},
163
		},
164
	}
165
}
166
167
func getTestDate() time.Time {
168
	return time.Date(2018, 3, 4, 1, 2, 3, 0, time.Local)
169
}
170
171
func getTestDetailedReport() toggl.DetailedReport {
172
	date := getTestDate()
173
	return toggl.DetailedReport{Data: []toggl.DetailedTimeEntry{
174
		// will be filtered by sent tag
175
		{
176
			ID:          1,
177
			Project:     "project1",
178
			Description: "description1",
179
			Tags:        []string{"12345", "sent"},
180
			Start:       &date,
181
		},
182
		{
183
			ID:          2,
184
			Project:     "project1",
185
			Description: "description1",
186
			Tags:        []string{"12345"},
187
			Start:       &date,
188
		},
189
		// will be filtered by taskID tag
190
		{
191
			ID:          3,
192
			Project:     "project1",
193
			Description: "description1",
194
			Tags:        []string{},
195
			Start:       &date,
196
		},
197
		{
198
			ID:          4,
199
			Project:     "project1",
200
			Description: "description1",
201
			Tags:        []string{"12345"},
202
			Start:       &date,
203
		},
204
	}}
205
}
206
207
func TestTogglClient_SumEntriesGroup(t *testing.T) {
208
	c := newClient()
209
	groupedEntries := getTestGroupedEntries()
210
	expected := []TogglPlanfixEntry{
211
		{
212
			toggl.DetailedTimeEntry{Duration: 3},
213
			PlanfixEntryData{TaskID: 1, GroupCount: 2},
214
		},
215
		{
216
			toggl.DetailedTimeEntry{Duration: 12},
217
			PlanfixEntryData{TaskID: 2, GroupCount: 3},
218
		},
219
		{
220
			toggl.DetailedTimeEntry{Duration: 6},
221
			PlanfixEntryData{TaskID: 3, GroupCount: 1},
222
		},
223
	}
224
225
	summed := c.SumEntriesGroup(groupedEntries)
226
	assert.Equal(t, expected, summed)
227
}
228
229
func TestTogglClient_GroupEntriesByTask(t *testing.T) {
230
	c := newClient()
231
	entries := getTestEntries()
232
	expected := getTestGroupedEntries()
233
234
	grouped := c.GroupEntriesByTask(entries)
235
	assert.Equal(t, expected, grouped)
236
}
237
238
func TestTogglClient_GroupEntriesByTask_empty(t *testing.T) {
239
	c := newClient()
240
	entries := []TogglPlanfixEntry{}
241
	expected := map[int][]TogglPlanfixEntry{}
242
243
	grouped := c.GroupEntriesByTask(entries)
244
	assert.Equal(t, expected, grouped)
245
}
246
247
func TestTogglClient_sendEntries_dryRun(t *testing.T) {
248
	c := newClient()
249
	c.Config.DryRun = true
250
	date := getTestDate()
251
	entries := []TogglPlanfixEntry{
252
		{
253
			toggl.DetailedTimeEntry{
254
				Duration:    60000,
255
				Start:       &date,
256
				Project:     "project",
257
				Description: "description",
258
			},
259
			PlanfixEntryData{TaskID: 1, GroupCount: 1},
260
		},
261
		{
262
			toggl.DetailedTimeEntry{Duration: 120000},
263
			PlanfixEntryData{TaskID: 1, GroupCount: 1},
264
		},
265
	}
266
267
	c.sendEntries(1, entries)
268
	assert.Contains(t, output.String(), "[DEBUG] sending [project] description (3)")
269
	assert.Contains(t, output.String(), "[DEBUG] dry-run")
270
}
271
272
func TestTogglClient_GetTogglUserID(t *testing.T) {
273
	c := newClient()
274
	sess := &MockedTogglSession{}
275
	c.Session = sess
276
277
	togglUser := toggl.Account{Data: struct {
278
		APIToken        string            `json:"api_token"`
279
		Timezone        string            `json:"timezone"`
280
		ID              int               `json:"id"`
281
		Workspaces      []toggl.Workspace `json:"workspaces"`
282
		Clients         []toggl.Client    `json:"clients"`
283
		Projects        []toggl.Project   `json:"projects"`
284
		Tasks           []toggl.Task      `json:"tasks"`
285
		Tags            []toggl.Tag       `json:"tags"`
286
		TimeEntries     []toggl.TimeEntry `json:"time_entries"`
287
		BeginningOfWeek int               `json:"beginning_of_week"`
288
	}{ID: 123}}
289
	sess.On("GetAccount").Return(togglUser, nil)
290
291
	togglUserID := c.GetTogglUserID()
292
	assert.Equal(t, 123, togglUserID)
293
}
294
295
func TestTogglClient_GetPlanfixUserID(t *testing.T) {
296
	c := newClient()
297
	ms := NewMockedServer([]string{
298
		fixtureFromFile("user.get.xml"),
299
		//fixtureFromFile("error.xml"),
300
	})
301
	c.PlanfixAPI.URL = ms.URL
302
303
	planfixUserID := c.GetPlanfixUserID()
304
	assert.Equal(t, 9230, planfixUserID)
305
}
306
307
func TestTogglClient_GetEntries(t *testing.T) {
308
	c := newClient()
309
	sess := &MockedTogglSession{}
310
	c.Session = sess
311
312
	since := time.Now().AddDate(0, 0, -30).Format("2006-01-02")
313
	until := time.Now().AddDate(0, 0, 1).Format("2006-01-02")
314
	report := toggl.DetailedReport{Data: []toggl.DetailedTimeEntry{
315
		{
316
			ID:          1,
317
			Project:     "project1",
318
			Description: "description1",
319
			Tags:        []string{"12345", "sent"},
320
		},
321
	}}
322
323
	sess.On("GetDetailedReport", 234, since, until, 1).Return(report, nil)
324
325
	report, _ = c.Session.GetDetailedReport(234, since, until, 1)
326
	entries, _ := c.GetEntries(234, since, until)
327
328
	expected := []TogglPlanfixEntry{
329
		{
330
			DetailedTimeEntry: report.Data[0],
331
			Planfix:           PlanfixEntryData{GroupCount: 1, Sent: true, TaskID: 12345},
332
		},
333
	}
334
	assert.Equal(t, expected, entries)
335
}
336
337
func TestTogglClient_GetPendingEntries(t *testing.T) {
338
	c := newClient()
339
	sess := &MockedTogglSession{}
340
	c.Session = sess
341
342
	since := time.Now().AddDate(0, 0, -30).Format("2006-01-02")
343
	until := time.Now().AddDate(0, 0, 1).Format("2006-01-02")
344
	date := getTestDate()
345
	report := getTestDetailedReport()
346
347
	sess.On("GetDetailedReport", c.Config.TogglWorkspaceID, since, until, 1).Return(report, nil)
348
349
	entries, _ := c.GetPendingEntries()
350
351
	expected := []TogglPlanfixEntry{
352
		{
353
			DetailedTimeEntry: toggl.DetailedTimeEntry{
354
				ID:          2,
355
				Project:     "project1",
356
				Description: "description1",
357
				Tags:        []string{"12345"},
358
				Start:       &date,
359
			},
360
			Planfix: PlanfixEntryData{GroupCount: 1, Sent: false, TaskID: 12345},
361
		},
362
		{
363
			DetailedTimeEntry: toggl.DetailedTimeEntry{
364
				ID:          4,
365
				Project:     "project1",
366
				Description: "description1",
367
				Tags:        []string{"12345"},
368
				Start:       &date,
369
			},
370
			Planfix: PlanfixEntryData{GroupCount: 1, Sent: false, TaskID: 12345},
371
		},
372
	}
373
	assert.Equal(t, expected, entries)
374
}
375
376
func TestTogglClient_markAsSent(t *testing.T) {
377
	c := newClient()
378
	sess := &MockedTogglSession{}
379
	c.Session = sess
380
381
	planfixEntries := []TogglPlanfixEntry{
382
		{
383
			DetailedTimeEntry: toggl.DetailedTimeEntry{
384
				ID:          2,
385
				Project:     "project1",
386
				Description: "description1",
387
				Tags:        []string{"12345"},
388
			},
389
			Planfix: PlanfixEntryData{GroupCount: 1, Sent: false, TaskID: 12345},
390
		},
391
		{
392
			DetailedTimeEntry: toggl.DetailedTimeEntry{
393
				ID:          4,
394
				Project:     "project1",
395
				Description: "description1",
396
				Tags:        []string{"12345"},
397
			},
398
			Planfix: PlanfixEntryData{GroupCount: 1, Sent: false, TaskID: 12345},
399
		},
400
	}
401
	togglEntries := []toggl.TimeEntry{
402
		{
403
			ID:          2,
404
			Description: "description1",
405
			Tags:        []string{"12345"},
406
		},
407
		{
408
			ID:          4,
409
			Description: "description1",
410
			Tags:        []string{"12345"},
411
		},
412
	}
413
	sess.On("AddRemoveTag", 2, c.Config.TogglSentTag, true).Return(togglEntries[0], nil)
414
	sess.On("AddRemoveTag", 4, c.Config.TogglSentTag, true).Return(togglEntries[1], nil)
415
416
	err := c.markAsSent(planfixEntries)
417
	assert.NoError(t, err)
418
}
419
420
func TestTogglClient_getTaskEmail(t *testing.T) {
421
	c := newClient()
422
	c.Config.PlanfixAccount = "mycompany"
423
424
	taskEmail := c.getTaskEmail(123)
425
	assert.Equal(t, "[email protected]", taskEmail)
426
}
427
428
func TestTogglClient_getEmailBody(t *testing.T) {
429
	c := newClient()
430
	c.Config.PlanfixAccount = "mycompany"
431
	c.Config.SMTPEmailFrom = "[email protected]"
432
	c.Config.PlanfixAnaliticTypeValue = "Название аналитики"
433
	c.Config.PlanfixAuthorName = "Имя Фамилия"
434
435
	expectedBody := "Content-Type: text/plain; charset=\"utf-8\"\r\n" +
436
		"From: [email protected]\r\n" +
437
		"To: [email protected]\r\n" +
438
		"Subject: @toggl @nonotify\r\n" +
439
		"\r\n" +
440
		"Вид работы: Название аналитики\r\n" +
441
		"time: 234\r\n" +
442
		"Автор: Имя Фамилия\r\n" +
443
		"Дата: 2018-03-04\r\n"
444
445
	body := c.getEmailBody(123, "2018-03-04", 234)
446
	assert.Equal(t, expectedBody, body)
447
}
448
449
func TestTogglClient_GetAnaliticData(t *testing.T) {
450
	c := newClient()
451
	ms := NewMockedServer([]string{
452
		fixtureFromFile("analitic.getList.xml"),
453
		fixtureFromFile("analitic.getOptions.xml"),
454
		fixtureFromFile("analitic.getHandbook.xml"),
455
	})
456
	c.PlanfixAPI.URL = ms.URL
457
	c.Config.PlanfixUserID = 123
458
	c.Config.PlanfixAnaliticName = "Выработка"
459
	c.Config.PlanfixAnaliticTypeName = "Вид работы"
460
	c.Config.PlanfixAnaliticTypeValue = "Поминутная работа программиста"
461
	c.Config.PlanfixAnaliticCountName = "Кол-во"
462
	c.Config.PlanfixAnaliticCommentName = "Комментарий / ссылка"
463
	c.Config.PlanfixAnaliticDateName = "Дата"
464
	c.Config.PlanfixAnaliticUsersName = "Сотрудник"
465
466
	// нормальное поведение
467
	analiticData, err := c.GetAnaliticData(
468
		c.Config.PlanfixAnaliticName,
469
		c.Config.PlanfixAnaliticTypeName,
470
		c.Config.PlanfixAnaliticTypeValue,
471
		c.Config.PlanfixAnaliticCountName,
472
		c.Config.PlanfixAnaliticCommentName,
473
		c.Config.PlanfixAnaliticDateName,
474
		c.Config.PlanfixAnaliticUsersName,
475
	)
476
	assert.NoError(t, err)
477
	assert.Equal(t, 725, analiticData.TypeValueID)
478
479
	// тест кеша
480
	analiticData, err = c.GetAnaliticData("", "", "", "", "", "", "")
481
	assert.NoError(t, err)
482
	assert.Equal(t, 725, analiticData.TypeValueID)
483
484
	// неправильный вид работы
485
	c.analiticData = PlanfixAnaliticData{} // сброс кеша
486
	ms = NewMockedServer([]string{
487
		fixtureFromFile("analitic.getList.xml"),
488
		fixtureFromFile("analitic.getOptions.xml"),
489
		fixtureFromFile("analitic.getHandbook.xml"),
490
	})
491
	c.PlanfixAPI.URL = ms.URL
492
	c.Config.PlanfixAnaliticTypeValue = "Какой-то неизвестный вид работы"
493
	analiticData, err = c.GetAnaliticData(
494
		c.Config.PlanfixAnaliticName,
495
		c.Config.PlanfixAnaliticTypeName,
496
		c.Config.PlanfixAnaliticTypeValue,
497
		c.Config.PlanfixAnaliticCountName,
498
		c.Config.PlanfixAnaliticCommentName,
499
		c.Config.PlanfixAnaliticDateName,
500
		c.Config.PlanfixAnaliticUsersName,
501
	)
502
	assert.Error(t, err)
503
	assert.Equal(t, 0, analiticData.TypeValueID)
504
	assert.Equal(t, 749, analiticData.CommentID)
505
}
506
507
// TODO: проходит метод полностью, но непонятно что проверяет
508
func TestTogglClient_sendWithPlanfixAPI(t *testing.T) {
509
	c := newClient()
510
	c.Config.PlanfixAnaliticName = "Выработка"
511
	c.Config.PlanfixAnaliticTypeName = "Вид работы"
512
	c.Config.PlanfixAnaliticTypeValue = "Поминутная работа программиста"
513
	c.Config.PlanfixAnaliticCountName = "Кол-во"
514
	c.Config.PlanfixAnaliticCommentName = "Комментарий / ссылка"
515
	c.Config.PlanfixAnaliticDateName = "Дата"
516
	c.Config.PlanfixAnaliticUsersName = "Сотрудник"
517
518
	ms := NewMockedServer([]string{
519
		fixtureFromFile("analitic.getList.xml"),
520
		fixtureFromFile("analitic.getOptions.xml"),
521
		fixtureFromFile("analitic.getHandbook.xml"),
522
		fixtureFromFile("action.add.xml"),
523
	})
524
	c.PlanfixAPI.URL = ms.URL
525
	c.Config.PlanfixUserID = 123
526
	c.Config.PlanfixAnaliticName = "Выработка"
527
528
	err := c.sendWithPlanfixAPI(123, "2018-03-04", 234, "comment")
529
	assert.NoError(t, err)
530
}
531
532
// TODO: проходит метод полностью, но непонятно что проверяет
533
func TestTogglClient_SendToPlanfix(t *testing.T) {
534
	c := newClient()
535
	sess := &MockedTogglSession{}
536
	c.Session = sess
537
538
	c.Config.PlanfixAnaliticName = "Выработка"
539
	c.Config.PlanfixAnaliticTypeName = "Вид работы"
540
	c.Config.PlanfixAnaliticTypeValue = "Поминутная работа программиста"
541
	c.Config.PlanfixAnaliticCountName = "Кол-во"
542
	c.Config.PlanfixAnaliticCommentName = "Комментарий / ссылка"
543
	c.Config.PlanfixAnaliticDateName = "Дата"
544
	c.Config.PlanfixAnaliticUsersName = "Сотрудник"
545
546
	ms := NewMockedServer([]string{
547
		fixtureFromFile("analitic.getList.xml"),
548
		fixtureFromFile("analitic.getOptions.xml"),
549
		fixtureFromFile("analitic.getHandbook.xml"),
550
		fixtureFromFile("action.add.xml"),
551
	})
552
	c.PlanfixAPI.URL = ms.URL
553
	c.Config.PlanfixUserID = 123
554
	c.Config.PlanfixAnaliticName = "Выработка"
555
556
	since := time.Now().AddDate(0, 0, -30).Format("2006-01-02")
557
	until := time.Now().AddDate(0, 0, 1).Format("2006-01-02")
558
	report := getTestDetailedReport()
559
	sess.On("GetDetailedReport", c.Config.TogglWorkspaceID, since, until, 1).Return(report, nil)
560
561
	sess.On("AddRemoveTag", 2, c.Config.TogglSentTag, true).Return(toggl.TimeEntry{}, nil)
562
	sess.On("AddRemoveTag", 4, c.Config.TogglSentTag, true).Return(toggl.TimeEntry{}, nil)
563
564
	pending, _ := c.GetPendingEntries()
565
	grouped := c.GroupEntriesByTask(pending)
566
	summedExpected := c.SumEntriesGroup(grouped)
567
568
	summed, err := c.SendToPlanfix()
569
	assert.NoError(t, err)
570
	assert.Equal(t, summedExpected, summed)
571
}
572