1'use strict' 2 3const common = require('../common-tap.js') 4const npm = require('../../') 5const test = require('tap').test 6const mkdirp = require('mkdirp') 7const rimraf = require('rimraf') 8const path = require('path') 9const fs = require('fs') 10const cacheFile = require('npm-cache-filename') 11const mr = require('npm-registry-mock') 12const ms = require('mississippi') 13const Tacks = require('tacks') 14const File = Tacks.File 15 16const allPackageMetadata = require('../../lib/search/all-package-metadata.js') 17 18const PKG_DIR = path.resolve(common.cache, 'update-index') 19const CACHE_DIR = path.resolve(PKG_DIR, 'cache', '_cacache') 20let cacheBase 21let cachePath 22 23let server 24 25function setup () { 26 mkdirp.sync(cacheBase) 27} 28 29function cleanup (cb) { 30 rimraf(PKG_DIR, cb) 31} 32 33test('setup', function (t) { 34 mr({port: common.port, throwOnUnmatched: true}, function (err, s) { 35 t.ifError(err, 'registry mocked successfully') 36 npm.load({ cache: path.dirname(CACHE_DIR), registry: common.registry }, function (err) { 37 t.ifError(err, 'npm loaded successfully') 38 npm.config.set('cache', path.dirname(CACHE_DIR)) 39 cacheBase = cacheFile(npm.config.get('cache'))(common.registry + '/-/all') 40 cachePath = path.join(cacheBase, '.cache.json') 41 server = s 42 t.pass('all set up') 43 t.done() 44 }) 45 }) 46}) 47 48test('allPackageMetadata full request', function (t) { 49 setup() 50 var updated = Date.now() 51 server.get('/-/all').once().reply(200, { 52 '_updated': 1234, 53 'bar': { name: 'bar', version: '1.0.0' }, 54 'foo': { name: 'foo', version: '1.0.0' } 55 }, { 56 date: updated 57 }) 58 var stream = allPackageMetadata({ 59 cache: CACHE_DIR, 60 registry: common.registry, 61 staleness: 600 62 }) 63 t.ok(stream, 'returned a stream') 64 var results = [] 65 stream.on('data', function (pkg) { 66 results.push(pkg) 67 }) 68 ms.finished(stream, function (err) { 69 if (err) throw err 70 t.deepEquals(results, [{ 71 name: 'bar', 72 version: '1.0.0' 73 }, { 74 name: 'foo', 75 version: '1.0.0' 76 }]) 77 var fileData = JSON.parse(fs.readFileSync(cachePath)) 78 t.ok(fileData, 'cache contents written to the right file') 79 t.deepEquals(fileData, { 80 '_updated': 1234, 81 bar: { 82 name: 'bar', 83 version: '1.0.0' 84 }, 85 foo: { 86 name: 'foo', 87 version: '1.0.0' 88 } 89 }, 'cache contents based on what was written') 90 server.done() 91 cleanup(t.end) 92 }) 93}) 94 95test('allPackageMetadata cache only', function (t) { 96 setup() 97 var now = Date.now() 98 var cacheContents = { 99 '_updated': now, 100 bar: { name: 'bar', version: '1.0.0' }, 101 cool: { name: 'cool', version: '1.0.0' }, 102 foo: { name: 'foo', version: '2.0.0' }, 103 other: { name: 'other', version: '1.0.0' } 104 } 105 var fixture = new Tacks(File(cacheContents)) 106 fixture.create(cachePath) 107 var stream = allPackageMetadata({ 108 cache: CACHE_DIR, 109 registry: common.registry, 110 staleness: 10000000 111 }) 112 t.ok(stream, 'returned a stream') 113 var results = [] 114 stream.on('data', function (pkg) { 115 results.push(pkg) 116 }) 117 ms.finished(stream, function (err) { 118 t.ifError(err, 'stream finished without error') 119 t.deepEquals( 120 results.map(function (pkg) { return pkg.name }), 121 ['bar', 'cool', 'foo', 'other'], 122 'packages deduped and sorted, without _updated' 123 ) 124 var fileData = JSON.parse(fs.readFileSync(cachePath)) 125 t.ok(fileData, 'cache contents written to the right file') 126 t.deepEquals(fileData, cacheContents, 'cacheContents written directly') 127 server.done() 128 cleanup(t.end) 129 }) 130}) 131 132test('createEntryStream merged stream', function (t) { 133 setup() 134 var now = Date.now() 135 var cacheTime = now - 601000 136 var reqTime = (new Date(now)).toISOString() 137 server.get('/-/all/since?stale=update_after&startkey=' + cacheTime).once().reply(200, { 138 'bar': { name: 'bar', version: '2.0.0' }, 139 'car': { name: 'car', version: '1.0.0' }, 140 'foo': { name: 'foo', version: '1.0.0' } 141 }, { 142 date: reqTime 143 }) 144 var fixture = new Tacks(File({ 145 '_updated': cacheTime, 146 bar: { name: 'bar', version: '1.0.0' }, 147 cool: { name: 'cool', version: '1.0.0' }, 148 foo: { name: 'foo', version: '2.0.0' }, 149 other: { name: 'other', version: '1.0.0' } 150 })) 151 fixture.create(cachePath) 152 var stream = allPackageMetadata({ 153 cache: CACHE_DIR, 154 registry: common.registry, 155 staleness: 600 156 }) 157 t.ok(stream, 'returned a stream') 158 var results = [] 159 stream.on('data', function (pkg) { 160 results.push(pkg) 161 }) 162 ms.finished(stream, function (err) { 163 t.ifError(err, 'stream finished without error') 164 t.deepEquals( 165 results.map(function (pkg) { return pkg.name }), 166 ['bar', 'car', 'cool', 'foo', 'other'], 167 'packages deduped and sorted' 168 ) 169 t.deepEquals(results[0], { 170 name: 'bar', 171 version: '2.0.0' 172 }, 'update stream version wins on dedupe') 173 t.deepEquals(results[3], { 174 name: 'foo', 175 version: '1.0.0' 176 }, 'update stream version wins on dedupe even when the newer one has a lower semver.') 177 var cacheContents = { 178 '_updated': Date.parse(reqTime), 179 bar: { name: 'bar', version: '2.0.0' }, 180 car: { name: 'car', version: '1.0.0' }, 181 cool: { name: 'cool', version: '1.0.0' }, 182 foo: { name: 'foo', version: '1.0.0' }, 183 other: { name: 'other', version: '1.0.0' } 184 } 185 var fileData = JSON.parse(fs.readFileSync(cachePath)) 186 t.ok(fileData, 'cache contents written to the right file') 187 t.deepEquals(fileData, cacheContents, 'cache updated correctly') 188 server.done() 189 cleanup(t.end) 190 }) 191}) 192 193test('allPackageMetadata no sources', function (t) { 194 setup() 195 server.get('/-/all').once().reply(404, {}) 196 var stream = allPackageMetadata({ 197 cache: CACHE_DIR, 198 registry: common.registry, 199 staleness: 600 200 }) 201 ms.finished(stream, function (err) { 202 t.ok(err, 'no sources, got an error') 203 t.match(err.message, /No search sources available/, 'useful error message') 204 server.done() 205 cleanup(t.end) 206 }) 207}) 208 209test('cleanup', function (t) { 210 server.close() 211 cleanup(t.end) 212}) 213