Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

"""Test that we're meeting delicious API specifications""" 

import logging 

import os 

import StringIO 

import transaction 

import unittest 

 

from datetime import datetime 

from nose.tools import ok_ 

from nose.tools import eq_ 

from nose.tools import raises 

 

from bookie.models import DBSession 

from bookie.models import Bmark 

from bookie.models.queue import ImportQueue 

from bookie.models.queue import ImportQueueMgr 

from bookie.lib.urlhash import generate_hash 

 

from bookie.lib.importer import Importer 

from bookie.lib.importer import DelImporter 

from bookie.lib.importer import DelXMLImporter 

from bookie.lib.importer import GBookmarkImporter 

 

from bookie.tests import TestViewBase 

from bookie.tests import empty_db 

 

 

LOG = logging.getLogger(__name__) 

 

API_KEY = None 

 

 

def _delicious_data_test(): 

    """Test that we find the correct set of declicious data after import""" 

    # blatant copy/paste, but I'm ona plane right now so oh well 

    # now let's do some db sanity checks 

    res = Bmark.query.all() 

    eq_(len(res), 19, 

        "We should have 19 results, we got: " + str(len(res))) 

 

    # verify we can find a bookmark by url and check tags, etc 

    check_url = 'http://www.ndftz.com/nickelanddime.png' 

    check_url_hashed = generate_hash(check_url) 

    found = Bmark.query.filter(Bmark.hash_id == check_url_hashed).one() 

 

    ok_(found.hashed.url == check_url, "The url should match our search") 

    eq_(len(found.tags), 7, 

        "We should have gotten 7 tags, got: " + str(len(found.tags))) 

    eq_('importer', found.inserted_by, 

        "The bookmark should have come from importing: " + found.inserted_by) 

 

    # and check we have a right tag or two 

    ok_('canonical' in found.tag_string(), 

        'Canonical should be a valid tag in the bookmark') 

 

    # and check the long description field 

    ok_("description" in found.extended, 

        "The extended attrib should have a nice long string in it") 

 

 

def _delicious_xml_data_test(): 

    """Test that we find the correct google bmark data after import""" 

    res = Bmark.query.all() 

    eq_(len(res), 25, 

        "We should have 25 results, we got: " + str(len(res))) 

 

    # verify we can find a bookmark by url and check tags, etc 

    check_url = 'http://jekyllrb.com/' 

    check_url_hashed = generate_hash(check_url) 

    found = Bmark.query.filter(Bmark.hash_id == check_url_hashed).one() 

 

    ok_(found.hashed.url == check_url, "The url should match our search") 

    eq_(len(found.tags), 6, 

        "We should have gotten 6 tags, got: " + str(len(found.tags))) 

 

    # and check we have a right tag or two 

    ok_('ruby' in found.tag_string(), 

        'ruby should be a valid tag in the bookmark') 

 

    # and check the long description field 

    ok_('added for test' in found.extended, 

        "'added for test' should be in the extended description") 

 

 

def _google_data_test(): 

    """Test that we find the correct google bmark data after import""" 

    res = Bmark.query.all() 

    eq_(len(res), 10, 

        "We should have 10 results, we got: " + str(len(res))) 

 

    # verify we can find a bookmark by url and check tags, etc 

    check_url = 'http://www.alistapart.com/' 

    check_url_hashed = generate_hash(check_url) 

    found = Bmark.query.filter(Bmark.hash_id == check_url_hashed).one() 

 

    ok_(found.hashed.url == check_url, "The url should match our search") 

    eq_(len(found.tags), 4, 

        "We should have gotten 4 tags, got: " + str(len(found.tags))) 

 

    # and check we have a right tag or two 

    ok_('html' in found.tag_string(), 

        'html should be a valid tag in the bookmark') 

 

    # and check the long description field 

    ok_("make websites" in found.extended, 

        "'make websites' should be in the extended description") 

 

 

class ImporterBaseTest(unittest.TestCase): 

    """Verify the base import class is working""" 

 

    @raises(NotImplementedError) 

    def test_doesnt_implement_can_handle(self): 

        """Verify we get the exception expected when running can_handle""" 

        Importer.can_handle("") 

 

    @raises(NotImplementedError) 

    def test_doesnt_implement_process(self): 

        """Verify we get the exception expected when running process""" 

        some_io = StringIO.StringIO() 

        imp = Importer(some_io) 

        imp.process() 

 

    def test_factory_gives_delicious(self): 

        """"Verify that the base importer will give DelImporter""" 

        loc = os.path.dirname(__file__) 

        del_file = os.path.join(loc, 'delicious.html') 

 

        with open(del_file) as del_io: 

            imp = Importer(del_io, username="admin") 

 

            ok_(isinstance(imp, DelImporter), 

                "Instance should be a delimporter instance") 

 

    def test_factory_gives_google(self): 

        """"Verify that the base importer will give GBookmarkImporter""" 

        loc = os.path.dirname(__file__) 

        google_file = os.path.join(loc, 'googlebookmarks.html') 

 

        with open(google_file) as google_io: 

            imp = Importer(google_io, username="admin") 

 

            ok_(isinstance(imp, GBookmarkImporter), 

                "Instance should be a GBookmarkImporter instance") 

 

 

class ImportDeliciousTest(unittest.TestCase): 

    """Test the Bookie importer for delicious""" 

 

    def _get_del_file(self): 

        """We need to get the locally found delicious.html file for tests""" 

        loc = os.path.dirname(__file__) 

        del_file = os.path.join(loc, 'delicious.html') 

 

        return open(del_file) 

 

    def setUp(self): 

        """Regular setup hooks""" 

        pass 

 

    def tearDown(self): 

        """Regular tear down method""" 

        empty_db() 

 

    def test_is_delicious_file(self): 

        """Verify that this is a delicious file""" 

        good_file = self._get_del_file() 

 

        ok_(DelImporter.can_handle(good_file), 

            "DelImporter should handle this file") 

 

        good_file.close() 

 

    def test_is_not_delicious_file(self): 

        """And that it returns false when it should""" 

        bad_file = StringIO.StringIO() 

        bad_file.write('failing tests please') 

        bad_file.seek(0) 

 

        ok_(not DelImporter.can_handle(bad_file), 

            "DelImporter cannot handle this file") 

 

        bad_file.close() 

 

    def test_import_process(self): 

        """Verify importer inserts the correct records""" 

        good_file = self._get_del_file() 

        imp = Importer(good_file, username="admin") 

        imp.process() 

 

        # now let's do some db sanity checks 

        _delicious_data_test() 

 

    def test_dupe_imports(self): 

        """If we import twice, we shouldn't end up with duplicate bmarks""" 

        good_file = self._get_del_file() 

        imp = Importer(good_file, username="admin") 

        imp.process() 

 

        good_file = self._get_del_file() 

        imp = Importer(good_file, username="admin") 

        imp.process() 

 

        # now let's do some db sanity checks 

        _delicious_data_test() 

 

 

class ImportDeliciousXMLTest(unittest.TestCase): 

    """Test the Bookie XML version importer for delicious""" 

 

    def _get_del_file(self): 

        """We need to get the locally found delicious.html file for tests""" 

        loc = os.path.dirname(__file__) 

        del_file = os.path.join(loc, 'newdelicious.xml') 

        return open(del_file) 

 

    def tearDown(self): 

        """Regular tear down method""" 

        empty_db() 

 

    def test_is_delicious_file(self): 

        """Verify that this is a delicious file""" 

        good_file = self._get_del_file() 

        ok_(DelXMLImporter.can_handle(good_file), 

            "DelXMLImporter should handle this file") 

        good_file.close() 

 

    def test_is_not_delicious_file(self): 

        """And that it returns false when it should""" 

        bad_file = StringIO.StringIO() 

        bad_file.write('failing tests please') 

        bad_file.seek(0) 

 

        ok_(not DelXMLImporter.can_handle(bad_file), 

            "DelXMLImporter cannot handle this file") 

 

        bad_file.close() 

 

    def test_import_process(self): 

        """Verify importer inserts the correct records""" 

        good_file = self._get_del_file() 

        imp = Importer(good_file, username="admin") 

        imp.process() 

 

        # now let's do some db sanity checks 

        _delicious_xml_data_test() 

 

    def test_dupe_imports(self): 

        """If we import twice, we shouldn't end up with duplicate bmarks""" 

        good_file = self._get_del_file() 

        imp = Importer(good_file, username="admin") 

        imp.process() 

 

        good_file = self._get_del_file() 

        imp = Importer(good_file, username="admin") 

        imp.process() 

 

        # Now let's do some db sanity checks. 

        _delicious_xml_data_test() 

 

 

class ImportGoogleTest(unittest.TestCase): 

    """Test the Bookie importer for google bookmarks""" 

 

    def _get_google_file(self): 

        """We need to get the locally found delicious.html file for tests""" 

        loc = os.path.dirname(__file__) 

        del_file = os.path.join(loc, 'googlebookmarks.html') 

 

        return open(del_file) 

 

    def tearDown(self): 

        """Regular tear down method""" 

        empty_db() 

 

    def test_is_google_file(self): 

        """Verify that this is a delicious file""" 

        good_file = self._get_google_file() 

 

        ok_(GBookmarkImporter.can_handle(good_file), 

            "GBookmarkImporter should handle this file") 

 

        good_file.close() 

 

    def test_is_not_google_file(self): 

        """And that it returns false when it should""" 

        bad_file = StringIO.StringIO() 

        bad_file.write('failing tests please') 

 

    def test_import_process(self): 

        """Verify importer inserts the correct google bookmarks""" 

        good_file = self._get_google_file() 

        imp = Importer(good_file, username="admin") 

        imp.process() 

 

        # now let's do some db sanity checks 

        _google_data_test() 

 

    def test_bookmarklet_file(self): 

        """Verify we can import a file with a bookmarklet in it.""" 

        loc = os.path.dirname(__file__) 

        bmarklet_file = os.path.join(loc, 'bookmarklet_error.htm') 

        fh = open(bmarklet_file) 

 

        imp = Importer(fh, username="admin") 

        imp.process() 

 

        res = Bmark.query.all() 

        eq_(len(res), 3) 

 

 

class ImportViews(TestViewBase): 

    """Test the web import""" 

 

    def _upload(self): 

        """Make an upload to the importer""" 

        loc = os.path.dirname(__file__) 

        del_file = open(os.path.join(loc, 'delicious.html')) 

        res = self.app.post( 

            '/admin/import', 

            params={'api_key': self.api_key}, 

            upload_files=[('import_file', 

                           'delicious.html', 

                           del_file.read())], 

        ) 

        return res 

 

    def test_import_upload(self): 

        """After we upload a file, we should have an importer queue.""" 

        self._login_admin() 

 

        # verify we get the form 

        res = self.app.get('/admin/import') 

        ok_('<form' in res.body, 

            'Should have a form in the body for submitting the upload') 

 

        res = self._upload() 

 

        eq_(res.status, "302 Found", 

            msg='Import status is 302 redirect by home, ' + res.status) 

 

        # now verify that we've got our record 

        imp = ImportQueueMgr.get_ready() 

        imp = imp[0] 

        ok_(imp, 'We should have a record') 

        ok_(imp.file_path.endswith('admin.delicious.html')) 

        eq_(imp.status, 0, 'start out as default status of 0') 

 

    def test_skip_running(self): 

        """Verify that if running, it won't get returned again""" 

        self._login_admin() 

        res = self._upload() 

 

        eq_(res.status, "302 Found", 

            msg='Import status is 302 redirect by home, ' + res.status) 

 

        # now verify that we've got our record 

        imp = ImportQueueMgr.get_ready() 

        imp = imp[0] 

        imp.status = 2 

        DBSession.flush() 

 

        imp = ImportQueueMgr.get_ready() 

        ok_(not imp, 'We should get no results back') 

 

    def test_one_import(self): 

        """You should be able to only get one import running at a time""" 

        self._login_admin() 

 

        # Prep the db with 2 other imports ahead of this user's. 

        # We have to commit these since the request takes place in a new 

        # session/transaction. 

        DBSession.add(ImportQueue(username='testing', 

                                  file_path='testing.txt')) 

        DBSession.add(ImportQueue(username='testing2', 

                                  file_path='testing2.txt')) 

        DBSession.flush() 

        transaction.commit() 

 

        res = self._upload() 

        res.follow() 

 

        # now let's hit the import page, we shouldn't get a form, but instead a 

        # message about our import 

        res = self.app.get('/admin/import') 

 

        ok_('<form' not in res.body, "We shouldn't have a form") 

        ok_('waiting in the queue' in res.body, 

            "We want to display a waiting message.") 

        ok_('2 other imports' in res.body, 

            "We want to display a count message." + res.body) 

 

    def test_completed_dont_count(self): 

        """Once completed, we should get the form again""" 

        self._login_admin() 

 

        # add out completed one 

        q = ImportQueue( 

            username='admin', 

            file_path='testing.txt' 

        ) 

        q.completed = datetime.now() 

        q.status = 2 

        DBSession.add(q) 

        transaction.commit() 

 

        # now let's hit the import page, we shouldn't get a form, but instead a 

        # message about our import 

        res = self.app.get('/admin/import') 

 

        ok_('<form' in res.body, "We should have a form")