1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package twitter
18
19 import (
20 "encoding/json"
21 "fmt"
22 "log"
23 "net/http"
24 "os"
25 "path/filepath"
26 "strconv"
27 "time"
28
29 "perkeep.org/internal/httputil"
30 "perkeep.org/internal/osutil"
31 "perkeep.org/pkg/importer"
32 )
33
34 var _ importer.TestDataMaker = (*imp)(nil)
35
36 func (im *imp) SetTestAccount(acctNode *importer.Object) error {
37 return acctNode.SetAttrs(
38 importer.AcctAttrAccessToken, "fakeAccessToken",
39 importer.AcctAttrAccessTokenSecret, "fakeAccessSecret",
40 importer.AcctAttrUserID, "fakeUserID",
41 importer.AcctAttrName, "fakeName",
42 importer.AcctAttrUserName, "fakeScreenName",
43 )
44 }
45
46 func (im *imp) MakeTestData() http.RoundTripper {
47 const (
48 fakeMaxId = int64(486450108201201664)
49 nTweets = 300
50 )
51 fakeMinId := fakeMaxId - nTweets
52
53 timeLineURL := apiURL + userTimeLineAPIPath
54 timeLineCached := make(map[int64]string)
55 okHeader := `HTTP/1.1 200 OK
56 Content-Type: application/json; charset=UTF-8
57
58 `
59 timeLineResponse := okHeader + fakeTimeLine(fakeMaxId, fakeMinId, timeLineCached)
60
61 fakePic := fakePicture()
62 responses := map[string]func() *http.Response{
63 timeLineURL: httputil.StaticResponder(timeLineResponse),
64 fmt.Sprintf("%s?count=%d&user_id=fakeUserID", timeLineURL, tweetRequestLimit): httputil.StaticResponder(timeLineResponse),
65 "https://twitpic.com/show/large/bar": httputil.FileResponder(fakePic),
66 "https://i.imgur.com/foo.gif": httputil.FileResponder(fakePic),
67 }
68
69
70 responses[fmt.Sprintf("%s?count=%d&max_id=%d&user_id=fakeUserID", timeLineURL, tweetRequestLimit, fakeMaxId-nTweets+1)] = httputil.StaticResponder(okHeader + fakeTimeLine(fakeMaxId-nTweets+1, fakeMinId, timeLineCached))
71 if nTweets > tweetRequestLimit {
72
73 for i := fakeMaxId; i > fakeMinId; i -= tweetRequestLimit - 1 {
74 responses[fmt.Sprintf("%s?count=%d&max_id=%d&user_id=fakeUserID", timeLineURL, tweetRequestLimit, i)] = httputil.StaticResponder(okHeader + fakeTimeLine(i, fakeMinId, timeLineCached))
75 }
76 }
77
78
79 for _, scheme := range []string{"http://", "https://"} {
80 for _, picsize := range []string{"thumb", "small", "medium", "large"} {
81 responses[fmt.Sprintf("%spbs.twimg.com/media/foo.jpg:%s", scheme, picsize)] = httputil.FileResponder(fakePic)
82 responses[fmt.Sprintf("%spbs.twimg.com/media/bar.png:%s", scheme, picsize)] = httputil.FileResponder(fakePic)
83 }
84 }
85
86 return httputil.NewFakeTransport(responses)
87 }
88
89
90
91
92 func fakeTimeLine(maxId, minId int64, cached map[int64]string) string {
93 if tl, ok := cached[maxId]; ok {
94 return tl
95 }
96 min := maxId - int64(tweetRequestLimit)
97 if min <= minId {
98 min = minId
99 }
100 var tweets []*apiTweetItem
101 entitiesCounter := 0
102 geoCounter := 0
103 for i := maxId; i > min; i-- {
104 tweet := &apiTweetItem{
105 Id: strconv.FormatInt(i, 10),
106 TextStr: fmt.Sprintf("fakeText %d", i),
107 CreatedAtStr: time.Now().Format(time.RubyDate),
108 Entities: fakeEntities(entitiesCounter),
109 }
110 geo, coords := fakeGeo(geoCounter)
111 tweet.Geo = geo
112 tweet.Coordinates = coords
113 tweets = append(tweets, tweet)
114 entitiesCounter++
115 geoCounter++
116 if entitiesCounter == 10 {
117 entitiesCounter = 0
118 }
119 if geoCounter == 5 {
120 geoCounter = 0
121 }
122 }
123 userTimeLine, err := json.MarshalIndent(tweets, "", " ")
124 if err != nil {
125 log.Fatalf("%v", err)
126 }
127 cached[maxId] = string(userTimeLine)
128 return cached[maxId]
129 }
130
131 func fakeGeo(counter int) (*geo, *coords) {
132 sf := []float64{37.7447124, -122.4341914}
133 gre := []float64{45.1822842, 5.7141854}
134 switch counter {
135 case 0:
136 return nil, nil
137 case 1:
138 return &geo{sf}, nil
139 case 2:
140 return nil, &coords{[]float64{gre[1], gre[0]}}
141 case 3:
142 return &geo{gre}, &coords{[]float64{sf[1], sf[0]}}
143 default:
144 return nil, nil
145 }
146 }
147
148 func fakeEntities(counter int) entities {
149 sizes := func() map[string]mediaSize {
150 return map[string]mediaSize{
151 "medium": {W: 591, H: 332, Resize: "fit"},
152 "large": {W: 591, H: 332, Resize: "fit"},
153 "small": {W: 338, H: 190, Resize: "fit"},
154 "thumb": {W: 150, H: 150, Resize: "crop"},
155 }
156 }
157 mediaTwimg1 := func() *media {
158 return &media{
159 Id: "1",
160 IdNum: 1,
161 MediaURL: `http://pbs.twimg.com/media/foo.jpg`,
162 MediaURLHTTPS: `https://pbs.twimg.com/media/foo.jpg`,
163 Sizes: sizes(),
164 }
165 }
166 mediaTwimg2 := func() *media {
167 return &media{
168 Id: "2",
169 IdNum: 2,
170 MediaURL: `http://pbs.twimg.com/media/bar.png`,
171 MediaURLHTTPS: `https://pbs.twimg.com/media/bar.png`,
172 Sizes: sizes(),
173 }
174 }
175 notPicURL := func() *urlEntity {
176 return &urlEntity{
177 URL: `http://t.co/whatever`,
178 ExpandedURL: `http://perkeep.org`,
179 DisplayURL: `perkeep.org`,
180 }
181 }
182 imgurURL := func() *urlEntity {
183 return &urlEntity{
184 URL: `http://t.co/whatever2`,
185 ExpandedURL: `http://imgur.com/foo`,
186 DisplayURL: `imgur.com/foo`,
187 }
188 }
189 twitpicURL := func() *urlEntity {
190 return &urlEntity{
191 URL: `http://t.co/whatever3`,
192 ExpandedURL: `http://twitpic.com/bar`,
193 DisplayURL: `twitpic.com/bar`,
194 }
195 }
196
197
198
199
200
201 switch counter {
202 case 0:
203 return entities{}
204 case 1:
205 return entities{
206 Media: []*media{
207 mediaTwimg1(),
208 mediaTwimg2(),
209 },
210 }
211 case 2:
212 return entities{
213 URLs: []*urlEntity{
214 notPicURL(),
215 },
216 }
217 case 3:
218 return entities{
219 URLs: []*urlEntity{
220 notPicURL(),
221 imgurURL(),
222 },
223 }
224 case 4:
225 return entities{
226 URLs: []*urlEntity{
227 twitpicURL(),
228 imgurURL(),
229 },
230 }
231 case 5:
232 return entities{
233 Media: []*media{
234 mediaTwimg2(),
235 mediaTwimg1(),
236 },
237 URLs: []*urlEntity{
238 notPicURL(),
239 twitpicURL(),
240 },
241 }
242 case 6:
243 return entities{
244 Media: []*media{
245 mediaTwimg1(),
246 mediaTwimg2(),
247 },
248 URLs: []*urlEntity{
249 imgurURL(),
250 twitpicURL(),
251 },
252 }
253 default:
254 return entities{}
255 }
256 }
257
258 func fakePicture() string {
259 camliDir, err := osutil.GoPackagePath("perkeep.org")
260 if err == os.ErrNotExist {
261 log.Fatal("Directory \"perkeep.org\" not found under GOPATH/src; are you not running with devcam?")
262 }
263 if err != nil {
264 log.Fatalf("Error searching for \"perkeep.org\" under GOPATH: %v", err)
265 }
266 return filepath.Join(camliDir, filepath.FromSlash("clients/web/embed/glitch/npc_piggy__x1_walk_png_1354829432.png"))
267 }