-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathstore_test.go
210 lines (179 loc) · 5.67 KB
/
store_test.go
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package scuttlebutt_test
import (
"errors"
"io/ioutil"
"os"
"reflect"
"testing"
"github.com/benbjohnson/scuttlebutt"
"github.com/davecgh/go-spew/spew"
)
// Ensure that duplicate messages are only recorded once.
func TestStore_AddMessage_Duplicate(t *testing.T) {
s := OpenStore()
defer s.Close()
// Mock remote store.
s.RemoteStore.RepositoryFn = func(id string) (*scuttlebutt.Repository, error) {
return &scuttlebutt.Repository{ID: id}, nil
}
// Add duplicate messages.
if err := s.AddMessage(&scuttlebutt.Message{ID: 1, Text: "A", RepositoryID: "github.com/user/repo"}); err != nil {
t.Fatal(err)
} else if err := s.AddMessage(&scuttlebutt.Message{ID: 1, Text: "A", RepositoryID: "github.com/user/repo"}); err != nil {
t.Fatal(err)
}
// Verify that only one message was added.
if r, err := s.Repository("github.com/user/repo"); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(r, &scuttlebutt.Repository{
ID: "github.com/user/repo",
Messages: []*scuttlebutt.Message{{ID: 1, Text: "A"}},
}) {
t.Fatalf("unexpected repository: %s", spew.Sdump(r))
}
}
// Ensure that an error on the remote store is passed back.
func TestStore_AddMessage_ErrRemoteStore(t *testing.T) {
s := OpenStore()
defer s.Close()
// Mock remote store.
s.RemoteStore.RepositoryFn = func(id string) (*scuttlebutt.Repository, error) {
return nil, errors.New("marker")
}
// Add messages.
err := s.AddMessage(&scuttlebutt.Message{ID: 1, Text: "A", RepositoryID: "github.com/benbjohnson/go1"})
if err == nil || err.Error() != `remote: marker` {
t.Fatalf("unexpected error: %s", err)
}
}
// Ensure that a non-existent repository is ignored.
func TestStore_AddMessage_ErrRepositoryNotFound(t *testing.T) {
s := OpenStore()
defer s.Close()
// Mock remote store.
s.RemoteStore.RepositoryFn = func(id string) (*scuttlebutt.Repository, error) {
return nil, nil
}
// Add message to
err := s.AddMessage(&scuttlebutt.Message{ID: 1, Text: "A", RepositoryID: "github.com/benbjohnson/no-such-repo"})
if err != scuttlebutt.ErrRepositoryNotFound {
t.Fatalf("unexpected error: %s", err)
}
}
// Ensure that a repository can be marked as notified.
func TestStore_MarkNotified(t *testing.T) {
s := OpenStore()
defer s.Close()
// Mock remote store.
s.RemoteStore.RepositoryFn = func(id string) (*scuttlebutt.Repository, error) {
return &scuttlebutt.Repository{ID: id}, nil
}
// Add message to pull in repository from remote store.
if err := s.AddMessage(&scuttlebutt.Message{ID: 1, Text: "A", RepositoryID: "github.com/user/repo"}); err != nil {
t.Fatal(err)
}
// Mark repository as notified.
if err := s.MarkNotified("github.com/user/repo"); err != nil {
t.Fatal(err)
}
// Verify that repository has been updated.
if r, err := s.Repository("github.com/user/repo"); err != nil {
t.Fatal(err)
} else if !r.Notified {
t.Fatal("expected notified")
}
}
// Ensure that messages can be added and then top repositories computed.
func TestStore_TopRepositories(t *testing.T) {
s := OpenStore()
defer s.Close()
// Mock remote store.
s.RemoteStore.RepositoryFn = func(id string) (*scuttlebutt.Repository, error) {
r := &scuttlebutt.Repository{
ID: id,
Description: "lorem ipsum",
}
switch id {
case "github.com/benbjohnson/go1":
r.Language = "go"
case "github.com/benbjohnson/go2":
r.Language = "go"
case "github.com/benbjohnson/js1":
r.Language = "javascript"
}
return r, nil
}
// Add messages.
if err := s.AddMessage(&scuttlebutt.Message{ID: 1, Text: "A", RepositoryID: "github.com/benbjohnson/go1"}); err != nil {
t.Fatal(err)
} else if err := s.AddMessage(&scuttlebutt.Message{ID: 2, Text: "B", RepositoryID: "github.com/benbjohnson/go2"}); err != nil {
t.Fatal(err)
} else if err := s.AddMessage(&scuttlebutt.Message{ID: 3, Text: "C", RepositoryID: "github.com/benbjohnson/go2"}); err != nil {
t.Fatal(err)
} else if err := s.AddMessage(&scuttlebutt.Message{ID: 4, Text: "D", RepositoryID: "github.com/benbjohnson/js1"}); err != nil {
t.Fatal(err)
}
// Compute top repositories by language.
m, err := s.TopRepositories()
if err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(m, map[string]*scuttlebutt.Repository{
"go": &scuttlebutt.Repository{
ID: "github.com/benbjohnson/go2",
Description: "lorem ipsum",
Language: "go",
Messages: []*scuttlebutt.Message{
{ID: 2, Text: "B"},
{ID: 3, Text: "C"},
},
},
"javascript": &scuttlebutt.Repository{
ID: "github.com/benbjohnson/js1",
Description: "lorem ipsum",
Language: "javascript",
Messages: []*scuttlebutt.Message{
{ID: 4, Text: "D"},
},
},
}) {
t.Fatalf("unexpected repositories: %s", spew.Sdump(m))
}
}
// Store represents a test wrapper for scuttlebutt.Store.
type Store struct {
*scuttlebutt.Store
RemoteStore RemoteStore
}
// NewStore returns a new instance of Store at a temporary location.
func NewStore() *Store {
// Create temporary path.
f, _ := ioutil.TempFile("", "scuttlebutt-")
f.Close()
os.Remove(f.Name())
// Create test store.
s := &Store{
Store: scuttlebutt.NewStore(f.Name()),
}
s.Store.RemoteStore = &s.RemoteStore
return s
}
// OpenStore returns a new, open instance of Store.
func OpenStore() *Store {
s := NewStore()
if err := s.Open(); err != nil {
panic(err)
}
return s
}
// Close closes the store and removes the underlying data.
func (s *Store) Close() error {
defer os.RemoveAll(s.Store.Path())
return s.Store.Close()
}
// RemoteStore represents a mock implementation of Store.RemoteStore.
type RemoteStore struct {
RepositoryFn func(id string) (*scuttlebutt.Repository, error)
}
func (s *RemoteStore) Repository(id string) (*scuttlebutt.Repository, error) {
return s.RepositoryFn(id)
}