diff --git a/lib/config.js b/lib/config.js index 8198657e..9154b7f3 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,9 +1,38 @@ -import convict from 'convict'; -import yaml from 'js-yaml'; -import pino from 'pino'; import path, { join } from 'path'; import fs from 'fs'; import os from 'os'; +import Sink from '@eik/sink'; + +/** + * Configuration object + * @typedef {import('@eik/sink')} Sink + * @typedef Config + * @type {object} + * @property {string} name - Name of the application + * @property {('development' | 'production')} env - Applicaton environments + * @property {boolean} metrics - Enable metrics + * @property {object} log - Log configuration + * @property {('trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal')} log.level - Log level to log at + * @property {object} http - Http configuration + * @property {boolean} http.http2 - Enable http2 for the server + * @property {string} http.address - The address the http server should bind to + * @property {number} http.port - The port the http server should bind to + * @property {object} compression - Compression configuration + * @property {boolean} compression.global - Enable global compression for all http routes + * @property {object} jwt - JWT configuration + * @property {string} jwt.secret - Secret used for JWT signing + * @property {object} basicAuth - Basic auth configuration + * @property {('key' | 'disabled')} basicAuth.type - Type of basic auth to use + * @property {string} basicAuth.key - Key used for basic authorization + * @property {object} organization - Organization configuration + * @property {string} organization.name - Organization name - Used as a folder name in the storage of files + * @property {Array.} organization.hostnames - Hostnames the organization maps to + * @property {object | Sink} sink - Sink configuration + * @property {('fs' | 'mem' | 'test')} sink.type - Type of sink to use + * @property {string} sink.path - Absolute path to store files in when using the "fs" sink + * @property {string} notFoundCacheControl - Cache control header value for 404 responses + * @property {string} aliasCacheControl - Cache control header value for alias responses + */ const CWD = process.cwd(); @@ -14,156 +43,58 @@ try { /* empty */ } -convict.addParser({ extension: ['yml', 'yaml'], parse: yaml.load }); +/** + * @param {Config} config + * @returns {Config} + */ +const withDefaults = (config) => ({ + name: pack.name, + env: 'development', + metrics: true, + notFoundCacheControl: 'public, max-age=5', + aliasCacheControl: '', -convict.addFormat({ - name: 'secret-string', - validate: (value) => { - if (typeof value !== 'string') { - throw new Error('Value must be a String'); - } - }, - coerce: (value) => { - if (path.isAbsolute(value)) { - try { - const file = fs.readFileSync(value); - return file.toString(); - } catch (error) { - throw new Error(`Config could not load secret from path: ${value}`); - } - } - return value; - } -}); + ...config, -const conf = convict({ - name: { - doc: 'Name of the apllication', - default: pack.name, - format: String, - }, - env: { - doc: 'Applicaton environments', - format: ['development', 'production'], - default: 'development', - env: 'NODE_ENV', - arg: 'node-env', - }, - metrics: { - format: Boolean, - default: true, - env: 'METRICS', - }, log: { - level: { - doc: 'Log level to log at', - format: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'], - default: 'info', - env: 'LOG_LEVEL', - arg: 'log-level', - }, + level: 'info', + ...config.log, }, http: { - http2: { - doc: 'Enable http2 for the server', - format: Boolean, - default: false, - env: 'HTTP_HTTP2', - }, - address: { - doc: 'The address the http server should bind to', - format: String, - default: 'localhost', - env: 'HTTP_ADDRESS', - }, - port: { - doc: 'The port the http server should bind to', - format: 'port', - default: 4001, - env: 'HTTP_PORT', - }, + http2: false, + address: 'localhost', + port: 4001, + ...config.http, }, compression: { - global: { - doc: 'Enable global compression for all http routes', - format: Boolean, - default: true, - env: 'COMPRESSION_GLOBAL', - }, + global: true, + ...config.compression, }, jwt: { - secret: { - doc: 'Secret used for JWT signing', - format: 'secret-string', - default: 'change_me', - env: 'AUTH_JWT_SECRET', - sensitive: true, - }, - expire: { - doc: 'Expire time for JWT', - format: String, - default: '60d', - env: 'AUTH_JWT_EXPIRE', - }, + secret: 'change_me', + expire: '60d', + ...config.jwt, }, basicAuth: { - type: { - doc: 'Type of basic auth to use', - format: ['key', 'disabled'], - default: 'key', - env: 'BASIC_AUTH_TYPE', - }, - key: { - doc: 'Key used for basic authorization', - format: 'secret-string', - default: 'change_me', - env: 'BASIC_AUTH_KEY', - sensitive: true, - }, + type: 'key', + key: 'change_me', + ...config.basicAuth, }, organization: { - name: { - doc: 'Organization name - Used as a folder name in the storage of files', - format: String, - default: 'local', - env: 'ORG_NAME', - }, - hostnames: { - doc: 'Hostnames the organization maps to', - format: Array, - default: ['localhost', '127.0.0.1'], - env: 'ORG_HOSTNAMES', - }, + name: 'local', + hostnames: ['localhost', '127.0.0.1'], + ...config.organization, }, - sink: { - type: { - doc: 'Type of sink to use', - format: ['fs', 'mem', 'test'], - default: 'fs', - env: 'SINK_TYPE', - }, - path: { - doc: 'Absolute path to store files in when using the "fs" sink', - format: String, - default: path.join(os.tmpdir(), '/eik'), - env: 'SINK_PATH', - }, - } + sink: + config.sink instanceof Sink + ? config.sink + : { + type: 'fs', + path: path.join(os.tmpdir(), '/eik'), + ...config.sink, + }, }); -const env = conf.get('env'); - -const logger = pino({ - level: conf.get('log.level'), - name: conf.get('name'), -}); - -try { - conf.loadFile(path.join(CWD, `/config/${env}.yaml`)); -} catch (error) { - logger.error(error); -} - -conf.validate(); +const DefaultConfig = withDefaults({}); -export default conf; +export { DefaultConfig, withDefaults }; diff --git a/lib/main.js b/lib/main.js index 9e2413b8..158a3ee1 100644 --- a/lib/main.js +++ b/lib/main.js @@ -5,43 +5,67 @@ import pino from 'pino'; import cors from '@fastify/cors'; import jwt from '@fastify/jwt'; import eik from '@eik/core'; +import Sink from '@eik/sink'; - -import config from './config.js'; +import { DefaultConfig, withDefaults } from './config.js'; import * as utils from './utils.js'; const EikService = class EikService { - constructor({ - customSink, - notFoundCacheControl, - aliasCacheControl, - } = {}) { - this._notFoundCacheControl = notFoundCacheControl || 'public, max-age=5'; + /** + * @param {Config} config + */ + constructor(config) { + const cfg = withDefaults(config); + const logger = pino({ - level: config.get('log.level'), - name: config.get('name'), + level: cfg.log?.level, + name: cfg.name, }); let sink; - if (customSink) { - sink = customSink; - } else if (config.get('sink.type') === 'mem') { - logger.info(`Server is running with a in memory sink. Uploaded files will be lost on restart!`); + if (cfg.sink instanceof Sink) { + sink = cfg.sink; + } else if (cfg.sink?.type === 'mem') { + logger.info( + `Server is running with a in memory sink. Uploaded files will be lost on restart!`, + ); sink = new eik.sink.MEM(); } else { - logger.info(`Server is running with the file system sink. Uploaded files will be stored under "${config.get('sink.path')}"`); + logger.info( + `Server is running with the file system sink. Uploaded files will be stored under "${cfg.sink?.path}"`, + ); sink = new eik.sink.FS(); } // Transform organization config - const organizations = config.get('organization.hostnames').map((hostname) => [hostname, config.get('organization.name')]); - - this._versionsGet = new eik.http.VersionsGet({ organizations, sink, logger }); - this._aliasPost = new eik.http.AliasPost({ organizations, sink, logger }); + const organizations = cfg.organization?.hostnames?.map((hostname) => [ + hostname, + cfg.organization?.name, + ]); + + this._versionsGet = new eik.http.VersionsGet({ + organizations, + sink, + logger, + }); + this._aliasPost = new eik.http.AliasPost({ + organizations, + sink, + logger, + }); this._aliasDel = new eik.http.AliasDel({ organizations, sink, logger }); - this._aliasGet = new eik.http.AliasGet({ organizations, sink, logger, cacheControl: aliasCacheControl }); + this._aliasGet = new eik.http.AliasGet({ + organizations, + sink, + logger, + cacheControl: cfg.aliasCacheControl, + }); this._aliasPut = new eik.http.AliasPut({ organizations, sink, logger }); - this._authPost = new eik.http.AuthPost({ organizations, logger, authKey: config.get('basicAuth.key') }); + this._authPost = new eik.http.AuthPost({ + organizations, + logger, + authKey: cfg.basicAuth?.key, + }); this._pkgLog = new eik.http.PkgLog({ organizations, sink, logger }); this._pkgGet = new eik.http.PkgGet({ organizations, sink, logger }); this._pkgPut = new eik.http.PkgPut({ organizations, sink, logger }); @@ -62,7 +86,7 @@ const EikService = class EikService { }); for (const stm of streams) { - stm.on('error', err => { + stm.on('error', (err) => { logger.error(err); }); stm.pipe(str); @@ -86,29 +110,38 @@ const EikService = class EikService { sink.metrics, ); - metrics.on('error', err => { + metrics.on('error', (err) => { logger.error(err); }); this.metrics = metrics; - this.config = config; + this.config = cfg; this.logger = logger; this.sink = sink; // Print warnings - if (config.get('basicAuth.type') === 'key' && config.get('basicAuth.key') === config.default('basicAuth.key')) { - logger.warn('Server is running with default basic authorization key configured! For security purposes, it is highly recommended to set a custom value!') + if ( + cfg.basicAuth?.type === 'key' && + cfg.basicAuth.key === DefaultConfig.basicAuth.key + ) { + logger.warn( + 'Server is running with default basic authorization key configured! For security purposes, it is highly recommended to set a custom value!', + ); } - if (config.get('jwt.secret') === config.default('jwt.secret')) { - logger.warn('Server is running with default jwt secret configured! For security purposes, it is highly recommended to set a custom value!') + if (cfg.jwt?.secret === DefaultConfig.jwt.secret) { + logger.warn( + 'Server is running with default jwt secret configured! For security purposes, it is highly recommended to set a custom value!', + ); } // Print info - const hosts = config.get('organization.hostnames').join(', '); - logger.info(`Files for "${hosts}" will be stored in the "${config.get('organization.name')}" organization space`); + const hosts = cfg.organization?.hostnames?.join(', '); + logger.info( + `Files for "${hosts}" will be stored in the "${cfg.organization?.name}" organization space`, + ); } async health() { @@ -122,33 +155,38 @@ const EikService = class EikService { api() { return (app, options, done) => { if (!app.initialConfig.ignoreTrailingSlash) { - this.logger.warn('Fastify is configured with "ignoreTrailingSlash" set to "false". Its adviced to set "ignoreTrailingSlash" to "true"'); + this.logger.warn( + 'Fastify is configured with "ignoreTrailingSlash" set to "false". Its adviced to set "ignoreTrailingSlash" to "true"', + ); } app.register(cors); // Authentication app.register(jwt, { - secret: config.get('jwt.secret'), + secret: this.config.jwt?.secret, messages: { - badRequestErrorMessage: 'Autorization header is malformatted. Format is "Authorization: Bearer [token]"', - noAuthorizationInHeaderMessage: 'Autorization header is missing!', - authorizationTokenExpiredMessage: 'Authorization token expired', - authorizationTokenInvalid: 'Authorization token is invalid' - } + badRequestErrorMessage: + 'Autorization header is malformatted. Format is "Authorization: Bearer [token]"', + noAuthorizationInHeaderMessage: + 'Autorization header is missing!', + authorizationTokenExpiredMessage: + 'Authorization token expired', + authorizationTokenInvalid: 'Authorization token is invalid', + }, }); app.decorate('authenticate', async (request, reply) => { try { - await request.jwtVerify() + await request.jwtVerify(); } catch (error) { - reply.send(error) + reply.send(error); } }); const authOptions = { - preValidation: [app.authenticate] - } + preValidation: [app.authenticate], + }; // Handle multipart upload const _multipart = Symbol('multipart'); @@ -161,27 +199,29 @@ const EikService = class EikService { // Compression app.register(compression, { - global: config.get('compression.global'), + global: this.config.compression?.global, }); // 404 handling app.setNotFoundHandler((request, reply) => { - reply.header('cache-control', this._notFoundCacheControl); - reply.type('text/plain'); - reply.code(404); - reply.send('Not found'); + reply.header('cache-control', this.config.notFoundCacheControl); + reply.type('text/plain'); + reply.code(404); + reply.send('Not found'); }); // Error handling app.setErrorHandler((error, request, reply) => { - this.logger.debug('Error occured during request. Error is available on trace log level.'); + this.logger.debug( + 'Error occured during request. Error is available on trace log level.', + ); this.logger.trace(error); reply.header('cache-control', 'no-store'); if (error.statusCode) { if (error.statusCode === 404) { reply.header( 'cache-control', - this._notFoundCacheControl, + this.config.notFoundCacheControl, ); } reply.send(error); @@ -190,22 +230,19 @@ const EikService = class EikService { reply.send(new HttpError.InternalServerError()); }); - // // Routes // const authPostRoutes = async (request, reply) => { - const outgoing = await this._authPost.handler( - request.raw, - ); + const outgoing = await this._authPost.handler(request.raw); // Workaround due to .jwt.sign() being able to only // deal with object literals for some reason :/ const body = JSON.parse(JSON.stringify(outgoing.body)); const token = app.jwt.sign(body, { - expiresIn: config.get('jwt.expire'), + expiresIn: this.config.jwt?.expire, }); reply.header('cache-control', outgoing.cacheControl); @@ -302,7 +339,6 @@ const EikService = class EikService { reply.redirect(outgoing.location); }; - const aliasGetRoute = async (request, reply) => { const params = utils.sanitizeParameters(request.raw.url); const outgoing = await this._aliasGet.handler( @@ -363,7 +399,6 @@ const EikService = class EikService { reply.send(outgoing.body); }; - // // Authentication // @@ -372,14 +407,16 @@ const EikService = class EikService { app.post(`/${eik.prop.base_auth}/login`, authPostRoutes); - // // Packages // // Get public package - scoped // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/8.4.1/main/index.js - app.get(`/${eik.prop.base_pkg}/@:scope/:name/:version/*`, pkgGetRoute); + app.get( + `/${eik.prop.base_pkg}/@:scope/:name/:version/*`, + pkgGetRoute, + ); // Get public package - non-scoped // curl -X GET http://localhost:4001/pkg/fuzz/8.4.1/main/index.js @@ -387,7 +424,10 @@ const EikService = class EikService { // Get package overview - scoped // curl -X GET http://localhost:4001/pkg/@cuz/fuzz/8.4.1/ - app.get(`/${eik.prop.base_pkg}/@:scope/:name/:version`, pkgLogRoute); + app.get( + `/${eik.prop.base_pkg}/@:scope/:name/:version`, + pkgLogRoute, + ); // Get package overview - non-scoped // curl -X GET http://localhost:4001/pkg/fuzz/8.4.1/ @@ -403,12 +443,19 @@ const EikService = class EikService { // Put package - scoped // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/pkg/@cuz/fuzz/8.4.1/ - app.put(`/${eik.prop.base_pkg}/@:scope/:name/:version`, authOptions, pkgPutRoute); + app.put( + `/${eik.prop.base_pkg}/@:scope/:name/:version`, + authOptions, + pkgPutRoute, + ); // Put package - non-scoped // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/pkg/fuzz/8.4.1/ - app.put(`/${eik.prop.base_pkg}/:name/:version`, authOptions, pkgPutRoute); - + app.put( + `/${eik.prop.base_pkg}/:name/:version`, + authOptions, + pkgPutRoute, + ); // // NPM Packages @@ -416,7 +463,10 @@ const EikService = class EikService { // Get public NPM package - scoped // curl -X GET http://localhost:4001/npm/@cuz/fuzz/8.4.1/main/index.js - app.get(`/${eik.prop.base_npm}/@:scope/:name/:version/*`, pkgGetRoute); + app.get( + `/${eik.prop.base_npm}/@:scope/:name/:version/*`, + pkgGetRoute, + ); // Get public NPM package - non-scoped // curl -X GET http://localhost:4001/npm/fuzz/8.4.1/main/index.js @@ -424,7 +474,10 @@ const EikService = class EikService { // Get NPM package overview - scoped // curl -X GET http://localhost:4001/npm/@cuz/fuzz/8.4.1/ - app.get(`/${eik.prop.base_npm}/@:scope/:name/:version`, pkgLogRoute); + app.get( + `/${eik.prop.base_npm}/@:scope/:name/:version`, + pkgLogRoute, + ); // Get NPM package overview - non-scoped // curl -X GET http://localhost:4001/npm/fuzz/8.4.1/ @@ -440,12 +493,19 @@ const EikService = class EikService { // Put NPM package - scoped // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/npm/@cuz/fuzz/8.4.1/ - app.put(`/${eik.prop.base_npm}/@:scope/:name/:version`, authOptions, pkgPutRoute); + app.put( + `/${eik.prop.base_npm}/@:scope/:name/:version`, + authOptions, + pkgPutRoute, + ); // Put NPM package - non-scoped // curl -X PUT -i -F filedata=@archive.tgz http://localhost:4001/npm/fuzz/8.4.1/ - app.put(`/${eik.prop.base_npm}/:name/:version`, authOptions, pkgPutRoute); - + app.put( + `/${eik.prop.base_npm}/:name/:version`, + authOptions, + pkgPutRoute, + ); // // Import Maps @@ -453,7 +513,10 @@ const EikService = class EikService { // Get map - scoped // curl -X GET http://localhost:4001/map/@cuz/buzz/4.2.2 - app.get(`/${eik.prop.base_map}/@:scope/:name/:version`, mapGetRoute); + app.get( + `/${eik.prop.base_map}/@:scope/:name/:version`, + mapGetRoute, + ); // Get map - non-scoped // curl -X GET http://localhost:4001/map/buzz/4.2.2 @@ -469,114 +532,205 @@ const EikService = class EikService { // Put map - scoped // curl -X PUT -i -F map=@import-map.json http://localhost:4001/map/@cuz/buzz/4.2.2 - app.put(`/${eik.prop.base_map}/@:scope/:name/:version`, authOptions, mapPutRoute); + app.put( + `/${eik.prop.base_map}/@:scope/:name/:version`, + authOptions, + mapPutRoute, + ); // Put map - non-scoped // curl -X PUT -i -F map=@import-map.json http://localhost:4001/map/buzz/4.2.2 - app.put(`/${eik.prop.base_map}/:name/:version`, authOptions, mapPutRoute); - + app.put( + `/${eik.prop.base_map}/:name/:version`, + authOptions, + mapPutRoute, + ); // // Alias Packages // // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/v8 - app.get(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, aliasGetRoute); + app.get( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/pkg/fuzz/v8 app.get(`/${eik.prop.base_pkg}/:name/v:alias`, aliasGetRoute); // curl -X GET -L http://localhost:4001/pkg/@cuz/fuzz/v8/main/index.js - app.get(`/${eik.prop.base_pkg}/@:scope/:name/v:alias/*`, aliasGetRoute); + app.get( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias/*`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/pkg/fuzz/v8/main/index.js app.get(`/${eik.prop.base_pkg}/:name/v:alias/*`, aliasGetRoute); // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/fuzz/v8 - app.put(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X PUT -i -F version=8.4.1 http://localhost:4001/pkg/fuzz/v8 - app.put(`/${eik.prop.base_pkg}/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_pkg}/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X POST -i -F version=8.4.1 http://localhost:4001/pkg/@cuz/lit-html/v8 - app.post(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X POST -i -F version=8.4.1 http://localhost:4001/pkg/lit-html/v8 - app.post(`/${eik.prop.base_pkg}/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_pkg}/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X DELETE http://localhost:4001/pkg/@cuz/fuzz/v8 - app.delete(`/${eik.prop.base_pkg}/@:scope/:name/v:alias`, authOptions, aliasDelRoute); + app.delete( + `/${eik.prop.base_pkg}/@:scope/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // curl -X DELETE http://localhost:4001/pkg/fuzz/v8 - app.delete(`/${eik.prop.base_pkg}/:name/v:alias`, authOptions, aliasDelRoute); - + app.delete( + `/${eik.prop.base_pkg}/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // // Alias NPM Packages // // curl -X GET -L http://localhost:4001/npm/@cuz/fuzz/v8 - app.get(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, aliasGetRoute); + app.get( + `/${eik.prop.base_npm}/@:scope/:name/v:alias`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/npm/fuzz/v8 app.get(`/${eik.prop.base_npm}/:name/v:alias`, aliasGetRoute); // curl -X GET -L http://localhost:4001/npm/@cuz/fuzz/v8/main/index.js - app.get(`/${eik.prop.base_npm}/@:scope/:name/v:alias/*`, aliasGetRoute); + app.get( + `/${eik.prop.base_npm}/@:scope/:name/v:alias/*`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/npm/fuzz/v8/main/index.js app.get(`/${eik.prop.base_npm}/:name/v:alias/*`, aliasGetRoute); // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/@cuz/fuzz/v8 - app.put(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_npm}/@:scope/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X PUT -i -F version=8.4.1 http://localhost:4001/npm/fuzz/v8 - app.put(`/${eik.prop.base_npm}/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_npm}/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X POST -i -F version=8.4.1 http://localhost:4001/npm/@cuz/lit-html/v8 - app.post(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_npm}/@:scope/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X POST -i -F version=8.4.1 http://localhost:4001/npm/lit-html/v8 - app.post(`/${eik.prop.base_npm}/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_npm}/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X DELETE http://localhost:4001/npm/@cuz/fuzz/v8 - app.delete(`/${eik.prop.base_npm}/@:scope/:name/v:alias`, authOptions, aliasDelRoute); + app.delete( + `/${eik.prop.base_npm}/@:scope/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // curl -X DELETE http://localhost:4001/npm/fuzz/v8 - app.delete(`/${eik.prop.base_npm}/:name/v:alias`, authOptions, aliasDelRoute); - + app.delete( + `/${eik.prop.base_npm}/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // // Alias Import Maps // // curl -X GET -L http://localhost:4001/map/@cuz/buzz/v4 - app.get(`/${eik.prop.base_map}/@:scope/:name/v:alias`, aliasGetRoute); + app.get( + `/${eik.prop.base_map}/@:scope/:name/v:alias`, + aliasGetRoute, + ); // curl -X GET -L http://localhost:4001/map/buzz/v4 app.get(`/${eik.prop.base_map}/:name/v:alias`, aliasGetRoute); // curl -X PUT -i -F version=4.2.2 http://localhost:4001/map/@cuz/buzz/v4 - app.put(`/${eik.prop.base_map}/@:scope/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_map}/@:scope/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X PUT -i -F version=4.2.2 http://localhost:4001/map/buzz/v4 - app.put(`/${eik.prop.base_map}/:name/v:alias`, authOptions, aliasPutRoute); + app.put( + `/${eik.prop.base_map}/:name/v:alias`, + authOptions, + aliasPutRoute, + ); // curl -X POST -i -F version=4.4.2 http://localhost:4001/map/@cuz/buzz/v4 - app.post(`/${eik.prop.base_map}/@:scope/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_map}/@:scope/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X POST -i -F version=4.4.2 http://localhost:4001/map/buzz/v4 - app.post(`/${eik.prop.base_map}/:name/v:alias`, authOptions, aliasPostRoute); + app.post( + `/${eik.prop.base_map}/:name/v:alias`, + authOptions, + aliasPostRoute, + ); // curl -X DELETE http://localhost:4001/map/@cuz/buzz/v4 - app.delete(`/${eik.prop.base_map}/@:scope/:name/v:alias`, authOptions, aliasDelRoute); + app.delete( + `/${eik.prop.base_map}/@:scope/:name/v:alias`, + authOptions, + aliasDelRoute, + ); // curl -X DELETE http://localhost:4001/map/buzz/v4 - app.delete(`/${eik.prop.base_map}/:name/v:alias`, authOptions, aliasDelRoute); - + app.delete( + `/${eik.prop.base_map}/:name/v:alias`, + authOptions, + aliasDelRoute, + ); done(); - } + }; } }; diff --git a/package.json b/package.json index 1861c3cf..5f3ceb4e 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "homepage": "https://github.com/eik-lib/service#readme", "dependencies": { "@eik/core": "1.3.26", + "@eik/sink": "1.2.1", "convict": "6.2.4", "fastify": "4.17.0", "@fastify/compress": "6.4.0", diff --git a/test/404.js b/test/404.js index b3ee7a3e..d9547c35 100644 --- a/test/404.js +++ b/test/404.js @@ -8,7 +8,7 @@ import Server from '../lib/main.js'; tap.test('404 - POST request to non existing pathname', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -25,16 +25,20 @@ tap.test('404 - POST request to non existing pathname', async (t) => { body: formData, headers: formData.getHeaders(), }); - + t.equal(response.status, 404, 'server should respond with a 404 Not found'); - t.equal(response.headers.get('cache-control'), 'public, max-age=5', 'should contain "cache-control" set to "public, max-age=5"'); + t.equal( + response.headers.get('cache-control'), + 'public, max-age=5', + 'should contain "cache-control" set to "public, max-age=5"', + ); await app.close(); }); tap.test('404 - GET request to non existing pathname', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -44,9 +48,13 @@ tap.test('404 - GET request to non existing pathname', async (t) => { const address = await app.listen({ port: 0, host: '127.0.0.1' }); const response = await fetch(`${address}/non/existent`); - + t.equal(response.status, 404, 'server should respond with a 404 Not found'); - t.equal(response.headers.get('cache-control'), 'public, max-age=5', 'should contain "cache-control" set to "public, max-age=5"'); + t.equal( + response.headers.get('cache-control'), + 'public, max-age=5', + 'should contain "cache-control" set to "public, max-age=5"', + ); await app.close(); }); diff --git a/test/alias.map.js b/test/alias.map.js index 261e7335..cff1a719 100644 --- a/test/alias.map.js +++ b/test/alias.map.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -16,7 +16,7 @@ const FIXTURE_MAP_B = path.resolve(__dirname, '../fixtures/import-map-b.json'); tap.beforeEach(async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -35,9 +35,10 @@ tap.beforeEach(async (t) => { }); const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + // eslint-disable-next-line no-param-reassign + t.context = { address, headers, app, @@ -61,7 +62,11 @@ tap.test('alias map - no auth token on PUT - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on PUT - non scoped', async (t) => { @@ -77,7 +82,11 @@ tap.test('alias map - no auth token on PUT - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on POST - scoped', async (t) => { @@ -93,7 +102,11 @@ tap.test('alias map - no auth token on POST - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on POST - non scoped', async (t) => { @@ -109,7 +122,11 @@ tap.test('alias map - no auth token on POST - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on DELETE - scoped', async (t) => { @@ -121,7 +138,11 @@ tap.test('alias map - no auth token on DELETE - scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias map - no auth token on POST - non scoped', async (t) => { @@ -133,305 +154,457 @@ tap.test('alias map - no auth token on POST - non scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); -tap.test('alias map - put alias, then get map through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT map on server - const pkgFormData = new FormData(); - pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); - - const uploaded = await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/@cuz/fuzz/8.4.1`, 'on PUT of map, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/map/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET map through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of map through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/map/@cuz/fuzz/8.4.1`, 'on GET of map through alias, server should respond with a location header'); - - // GET map from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of map, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias map - put alias, then get map through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT map on server - const pkgFormData = new FormData(); - pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); - - const uploaded = await fetch(`${address}/map/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/fuzz/8.4.1`, 'on PUT of map, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/map/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/map/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of map through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/map/fuzz/8.4.1`, 'on GET of map through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of map, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias map - put alias, then update alias, then get map through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT maps on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('map', fs.createReadStream(FIXTURE_MAP)); - await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('map', fs.createReadStream(FIXTURE_MAP_B)); - await fetch(`${address}/map/@cuz/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v8', 'on PUT of alias, alias should redirect to set "version"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v9', 'on POST of alias, alias should redirect to set "version"'); -}); - -tap.test('alias map - put alias, then update alias, then get map through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT maps on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('map', fs.createReadStream(FIXTURE_MAP)); - await fetch(`${address}/map/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('map', fs.createReadStream(FIXTURE_MAP_B)); - await fetch(`${address}/map/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/map/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v8', 'on PUT of alias, alias should redirect to set "version"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/map/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v9', 'on POST of alias, alias should redirect to set "version"'); -}); - -tap.test('alias map - put alias, then delete alias, then get map through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT map on server - const pkgFormData = new FormData(); - pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); - - const uploaded = await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/@cuz/fuzz/8.4.1`, 'on PUT of map, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v8', 'on PUT of alias, alias should redirect to set "version"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET map through alias from server - const errored = await fetch(`${address}/map/@cuz/fuzz/v8`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of map through deleted alias, server should respond with a 404 Not Found'); -}); - -tap.test('alias map - put alias, then delete alias, then get map through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT map on server - const pkgFormData = new FormData(); - pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); - - const uploaded = await fetch(`${address}/map/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/fuzz/8.4.1`, 'on PUT of map, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/map/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.imports.fuzz, 'http://localhost:4001/finn/pkg/fuzz/v8', 'on PUT of alias, alias should redirect to set "version"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/map/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET map through alias from server - const errored = await fetch(`${address}/map/fuzz/v8`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of map through deleted alias, server should respond with a 404 Not Found'); -}); +tap.test( + 'alias map - put alias, then get map through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT map on server + const pkgFormData = new FormData(); + pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); + + const uploaded = await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/@cuz/fuzz/8.4.1`, + 'on PUT of map, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/map/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET map through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of map through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/map/@cuz/fuzz/8.4.1`, + 'on GET of map through alias, server should respond with a location header', + ); + + // GET map from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of map, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias map - put alias, then get map through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT map on server + const pkgFormData = new FormData(); + pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); + + const uploaded = await fetch(`${address}/map/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/fuzz/8.4.1`, + 'on PUT of map, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/map/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/map/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of map through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/map/fuzz/8.4.1`, + 'on GET of map through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of map, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias map - put alias, then update alias, then get map through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT maps on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('map', fs.createReadStream(FIXTURE_MAP)); + await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('map', fs.createReadStream(FIXTURE_MAP_B)); + await fetch(`${address}/map/@cuz/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = await aliasA.json(); + + t.equal( + aliasResponseA.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v8', + 'on PUT of alias, alias should redirect to set "version"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = await aliasB.json(); + + t.equal( + aliasResponseB.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v9', + 'on POST of alias, alias should redirect to set "version"', + ); + }, +); + +tap.test( + 'alias map - put alias, then update alias, then get map through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT maps on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('map', fs.createReadStream(FIXTURE_MAP)); + await fetch(`${address}/map/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('map', fs.createReadStream(FIXTURE_MAP_B)); + await fetch(`${address}/map/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/map/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = await aliasA.json(); + + t.equal( + aliasResponseA.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v8', + 'on PUT of alias, alias should redirect to set "version"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/map/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = await aliasB.json(); + + t.equal( + aliasResponseB.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v9', + 'on POST of alias, alias should redirect to set "version"', + ); + }, +); + +tap.test( + 'alias map - put alias, then delete alias, then get map through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT map on server + const pkgFormData = new FormData(); + pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); + + const uploaded = await fetch(`${address}/map/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/@cuz/fuzz/8.4.1`, + 'on PUT of map, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = await alias.json(); + + t.equal( + aliasResponse.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v8', + 'on PUT of alias, alias should redirect to set "version"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET map through alias from server + const errored = await fetch(`${address}/map/@cuz/fuzz/v8`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + errored.status, + 404, + 'on GET of map through deleted alias, server should respond with a 404 Not Found', + ); + }, +); + +tap.test( + 'alias map - put alias, then delete alias, then get map through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT map on server + const pkgFormData = new FormData(); + pkgFormData.append('map', fs.createReadStream(FIXTURE_MAP)); + + const uploaded = await fetch(`${address}/map/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/fuzz/8.4.1`, + 'on PUT of map, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/map/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = await alias.json(); + + t.equal( + aliasResponse.imports.fuzz, + 'http://localhost:4001/finn/pkg/fuzz/v8', + 'on PUT of alias, alias should redirect to set "version"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/map/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET map through alias from server + const errored = await fetch(`${address}/map/fuzz/v8`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + errored.status, + 404, + 'on GET of map through deleted alias, server should respond with a 404 Not Found', + ); + }, +); diff --git a/test/alias.npm.js b/test/alias.npm.js index 086c333b..4d89b8a8 100644 --- a/test/alias.npm.js +++ b/test/alias.npm.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -21,7 +21,7 @@ tap.cleanSnapshot = (s) => { tap.beforeEach(async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -40,9 +40,10 @@ tap.beforeEach(async (t) => { }); const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + // eslint-disable-next-line no-param-reassign + t.context = { address, headers, app, @@ -66,7 +67,11 @@ tap.test('alias package - no auth token on PUT - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on PUT - non scoped', async (t) => { @@ -82,7 +87,11 @@ tap.test('alias package - no auth token on PUT - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on POST - scoped', async (t) => { @@ -98,7 +107,11 @@ tap.test('alias package - no auth token on POST - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on POST - non scoped', async (t) => { @@ -114,7 +127,11 @@ tap.test('alias package - no auth token on POST - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on DELETE - scoped', async (t) => { @@ -125,7 +142,11 @@ tap.test('alias package - no auth token on DELETE - scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on DELETE of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on DELETE of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on DELETE - non scoped', async (t) => { @@ -136,413 +157,669 @@ tap.test('alias package - no auth token on DELETE - non scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on DELETE of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on DELETE of alias, server should respond with a 401 Unauthorized', + ); }); -tap.test('alias package - put alias, then get file overview through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/npm/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file overview through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/npm/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/npm/fuzz/8.4.1`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/npm/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}/npm/@cuz/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/npm/@cuz/fuzz/8.4.1/main/index.js`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/npm/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/npm/fuzz/8.4.1/main/index.js`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then update alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT packages on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/npm/@cuz/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponseA.name, '@cuz/fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.version, '8.8.9', 'on POST of alias, alias should redirect to updated "version"'); - t.equal(aliasResponseB.name, '@cuz/fuzz', 'on POST of alias, alias should redirect to set "name"'); -}); - -tap.test('alias package - put alias, then update alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT packages on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/npm/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/npm/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponseA.name, 'fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/npm/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.version, '8.8.9', 'on POST of alias, alias should redirect to updated "version"'); - t.equal(aliasResponseB.name, 'fuzz', 'on POST of alias, alias should redirect to set "name"'); -}); - -tap.test('alias package - put alias, then delete alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponse.name, '@cuz/fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/npm/@cuz/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET file through alias from server - const errored = await fetch(`${address}/npm/@cuz/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of file through deleted alias, server should respond with a 404 Not Found'); -}); - -tap.test('alias package - put alias, then delete alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/npm/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponse.name, 'fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/npm/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET file through alias from server - const errored = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of file through deleted alias, server should respond with a 404 Not Found'); -}); +tap.test( + 'alias package - put alias, then get file overview through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/npm/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file overview through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/npm/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/npm/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}/npm/@cuz/fuzz/v8/main/index.js`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1/main/index.js`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/npm/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/npm/fuzz/8.4.1/main/index.js`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then update alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT packages on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/npm/@cuz/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = await aliasA.json(); + + t.equal( + aliasResponseA.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponseA.name, + '@cuz/fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = await aliasB.json(); + + t.equal( + aliasResponseB.version, + '8.8.9', + 'on POST of alias, alias should redirect to updated "version"', + ); + t.equal( + aliasResponseB.name, + '@cuz/fuzz', + 'on POST of alias, alias should redirect to set "name"', + ); + }, +); + +tap.test( + 'alias package - put alias, then update alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT packages on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/npm/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/npm/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = await aliasA.json(); + + t.equal( + aliasResponseA.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponseA.name, + 'fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/npm/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = await aliasB.json(); + + t.equal( + aliasResponseB.version, + '8.8.9', + 'on POST of alias, alias should redirect to updated "version"', + ); + t.equal( + aliasResponseB.name, + 'fuzz', + 'on POST of alias, alias should redirect to set "name"', + ); + }, +); + +tap.test( + 'alias package - put alias, then delete alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = await alias.json(); + + t.equal( + aliasResponse.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponse.name, + '@cuz/fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/npm/@cuz/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET file through alias from server + const errored = await fetch( + `${address}/npm/@cuz/fuzz/v8/main/index.js`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + errored.status, + 404, + 'on GET of file through deleted alias, server should respond with a 404 Not Found', + ); + }, +); + +tap.test( + 'alias package - put alias, then delete alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/npm/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = await alias.json(); + + t.equal( + aliasResponse.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponse.name, + 'fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/npm/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET file through alias from server + const errored = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + errored.status, + 404, + 'on GET of file through deleted alias, server should respond with a 404 Not Found', + ); + }, +); diff --git a/test/alias.pkg.js b/test/alias.pkg.js index 1c8ac6ab..d096f2c0 100644 --- a/test/alias.pkg.js +++ b/test/alias.pkg.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -21,7 +21,7 @@ tap.cleanSnapshot = (s) => { tap.beforeEach(async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -40,9 +40,10 @@ tap.beforeEach(async (t) => { }); const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + // eslint-disable-next-line no-param-reassign + t.context = { address, headers, app, @@ -66,7 +67,11 @@ tap.test('alias package - no auth token on PUT - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on PUT - non scoped', async (t) => { @@ -82,7 +87,11 @@ tap.test('alias package - no auth token on PUT - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on PUT of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on PUT of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on POST - scoped', async (t) => { @@ -98,7 +107,11 @@ tap.test('alias package - no auth token on POST - scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on POST - non scoped', async (t) => { @@ -114,7 +127,11 @@ tap.test('alias package - no auth token on POST - non scoped', async (t) => { headers: aliasFormData.getHeaders(), }); - t.equal(alias.status, 401, 'on POST of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on POST of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on DELETE - scoped', async (t) => { @@ -125,7 +142,11 @@ tap.test('alias package - no auth token on DELETE - scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on DELETE of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on DELETE of alias, server should respond with a 401 Unauthorized', + ); }); tap.test('alias package - no auth token on DELETE - non scoped', async (t) => { @@ -136,413 +157,669 @@ tap.test('alias package - no auth token on DELETE - non scoped', async (t) => { method: 'DELETE', }); - t.equal(alias.status, 401, 'on DELETE of alias, server should respond with a 401 Unauthorized'); + t.equal( + alias.status, + 401, + 'on DELETE of alias, server should respond with a 401 Unauthorized', + ); }); -tap.test('alias package - put alias, then get file overview through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/pkg/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file overview through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/pkg/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}${alias.headers.get('location')}`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/pkg/@cuz/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}/pkg/@cuz/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1/main/index.js`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(alias.status, 303, 'on PUT of alias, server should respond with a 303 redirect'); - t.equal(alias.headers.get('location'), `/pkg/fuzz/v8`, 'on PUT of alias, server should respond with a location header'); - - // GET file through alias from server - const redirect = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(redirect.status, 302, 'on GET of file through alias, server should respond with a 302 redirect'); - t.equal(redirect.headers.get('location'), `/pkg/fuzz/8.4.1/main/index.js`, 'on GET of file through alias, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}${redirect.headers.get('location')}`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of file, response should match snapshot'); -}); - -tap.test('alias package - put alias, then update alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - // PUT packages on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/pkg/@cuz/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponseA.name, '@cuz/fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.version, '8.8.9', 'on POST of alias, alias should redirect to updated "version"'); - t.equal(aliasResponseB.name, '@cuz/fuzz', 'on POST of alias, alias should redirect to set "name"'); -}); - -tap.test('alias package - put alias, then update alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - // PUT packages on server - const pkgFormDataA = new FormData(); - pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormDataA, - headers: { ...headers, ...pkgFormDataA.getHeaders()}, - redirect: 'manual', - }); - - const pkgFormDataB = new FormData(); - pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); - await fetch(`${address}/pkg/fuzz/8.8.9`, { - method: 'PUT', - body: pkgFormDataB, - headers: { ...headers, ...pkgFormDataB.getHeaders()}, - redirect: 'manual', - }); - - // PUT alias on server - const aliasFormDataA = new FormData(); - aliasFormDataA.append('version', '8.4.1'); - - const aliasA = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'PUT', - body: aliasFormDataA, - headers: { ...headers, ...aliasFormDataA.getHeaders()}, - }); - - const aliasResponseA = await aliasA.json(); - - t.equal(aliasResponseA.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponseA.name, 'fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // POST alias on server - const aliasFormDataB = new FormData(); - aliasFormDataB.append('version', '8.8.9'); - - const aliasB = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'POST', - body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, - }); - - const aliasResponseB = await aliasB.json(); - - t.equal(aliasResponseB.version, '8.8.9', 'on POST of alias, alias should redirect to updated "version"'); - t.equal(aliasResponseB.name, 'fuzz', 'on POST of alias, alias should redirect to set "name"'); -}); - -tap.test('alias package - put alias, then delete alias, then get file through alias - scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponse.name, '@cuz/fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET file through alias from server - const errored = await fetch(`${address}/pkg/@cuz/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of file through deleted alias, server should respond with a 404 Not Found'); -}); - -tap.test('alias package - put alias, then delete alias, then get file through alias - non scoped', async (t) => { - const { headers, address } = t.context; - - const pkgFormData = new FormData(); - pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: pkgFormData, - headers: { ...headers, ...pkgFormData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // PUT alias on server - const aliasFormData = new FormData(); - aliasFormData.append('version', '8.4.1'); - - const alias = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'PUT', - body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, - }); - - const aliasResponse = await alias.json(); - - t.equal(aliasResponse.version, '8.4.1', 'on PUT of alias, alias should redirect to set "version"'); - t.equal(aliasResponse.name, 'fuzz', 'on PUT of alias, alias should redirect to set "name"'); - - // DELETE alias on server - const deleted = await fetch(`${address}/pkg/fuzz/v8`, { - method: 'DELETE', - headers, - }); - - t.equal(deleted.status, 204, 'on DELETE of alias, server should respond with a 204 Deleted'); - - // GET file through alias from server - const errored = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { - method: 'GET', - redirect: 'manual', - }); - - t.equal(errored.status, 404, 'on GET of file through deleted alias, server should respond with a 404 Not Found'); -}); +tap.test( + 'alias package - put alias, then get file overview through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/pkg/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file overview through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/pkg/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}${alias.headers.get('location')}`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/pkg/@cuz/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch( + `${address}/pkg/@cuz/fuzz/v8/main/index.js`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1/main/index.js`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + alias.status, + 303, + 'on PUT of alias, server should respond with a 303 redirect', + ); + t.equal( + alias.headers.get('location'), + `/pkg/fuzz/v8`, + 'on PUT of alias, server should respond with a location header', + ); + + // GET file through alias from server + const redirect = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + redirect.status, + 302, + 'on GET of file through alias, server should respond with a 302 redirect', + ); + t.equal( + redirect.headers.get('location'), + `/pkg/fuzz/8.4.1/main/index.js`, + 'on GET of file through alias, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}${redirect.headers.get('location')}`, + { + method: 'GET', + }, + ); + + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of file, response should match snapshot', + ); + }, +); + +tap.test( + 'alias package - put alias, then update alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT packages on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/pkg/@cuz/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = await aliasA.json(); + + t.equal( + aliasResponseA.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponseA.name, + '@cuz/fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = await aliasB.json(); + + t.equal( + aliasResponseB.version, + '8.8.9', + 'on POST of alias, alias should redirect to updated "version"', + ); + t.equal( + aliasResponseB.name, + '@cuz/fuzz', + 'on POST of alias, alias should redirect to set "name"', + ); + }, +); + +tap.test( + 'alias package - put alias, then update alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + // PUT packages on server + const pkgFormDataA = new FormData(); + pkgFormDataA.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormDataA, + headers: { ...headers, ...pkgFormDataA.getHeaders() }, + redirect: 'manual', + }); + + const pkgFormDataB = new FormData(); + pkgFormDataB.append('package', fs.createReadStream(FIXTURE_PKG)); + await fetch(`${address}/pkg/fuzz/8.8.9`, { + method: 'PUT', + body: pkgFormDataB, + headers: { ...headers, ...pkgFormDataB.getHeaders() }, + redirect: 'manual', + }); + + // PUT alias on server + const aliasFormDataA = new FormData(); + aliasFormDataA.append('version', '8.4.1'); + + const aliasA = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'PUT', + body: aliasFormDataA, + headers: { ...headers, ...aliasFormDataA.getHeaders() }, + }); + + const aliasResponseA = await aliasA.json(); + + t.equal( + aliasResponseA.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponseA.name, + 'fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // POST alias on server + const aliasFormDataB = new FormData(); + aliasFormDataB.append('version', '8.8.9'); + + const aliasB = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'POST', + body: aliasFormDataB, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, + }); + + const aliasResponseB = await aliasB.json(); + + t.equal( + aliasResponseB.version, + '8.8.9', + 'on POST of alias, alias should redirect to updated "version"', + ); + t.equal( + aliasResponseB.name, + 'fuzz', + 'on POST of alias, alias should redirect to set "name"', + ); + }, +); + +tap.test( + 'alias package - put alias, then delete alias, then get file through alias - scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = await alias.json(); + + t.equal( + aliasResponse.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponse.name, + '@cuz/fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET file through alias from server + const errored = await fetch( + `${address}/pkg/@cuz/fuzz/v8/main/index.js`, + { + method: 'GET', + redirect: 'manual', + }, + ); + + t.equal( + errored.status, + 404, + 'on GET of file through deleted alias, server should respond with a 404 Not Found', + ); + }, +); + +tap.test( + 'alias package - put alias, then delete alias, then get file through alias - non scoped', + async (t) => { + const { headers, address } = t.context; + + const pkgFormData = new FormData(); + pkgFormData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: pkgFormData, + headers: { ...headers, ...pkgFormData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // PUT alias on server + const aliasFormData = new FormData(); + aliasFormData.append('version', '8.4.1'); + + const alias = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'PUT', + body: aliasFormData, + headers: { ...headers, ...aliasFormData.getHeaders() }, + }); + + const aliasResponse = await alias.json(); + + t.equal( + aliasResponse.version, + '8.4.1', + 'on PUT of alias, alias should redirect to set "version"', + ); + t.equal( + aliasResponse.name, + 'fuzz', + 'on PUT of alias, alias should redirect to set "name"', + ); + + // DELETE alias on server + const deleted = await fetch(`${address}/pkg/fuzz/v8`, { + method: 'DELETE', + headers, + }); + + t.equal( + deleted.status, + 204, + 'on DELETE of alias, server should respond with a 204 Deleted', + ); + + // GET file through alias from server + const errored = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { + method: 'GET', + redirect: 'manual', + }); + + t.equal( + errored.status, + 404, + 'on GET of file through deleted alias, server should respond with a 404 Not Found', + ); + }, +); diff --git a/test/auth.js b/test/auth.js index b8132168..1d3ad9dd 100644 --- a/test/auth.js +++ b/test/auth.js @@ -8,7 +8,7 @@ import Server from '../lib/main.js'; tap.test('auth - authenticate - legal "key" value', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -28,15 +28,22 @@ tap.test('auth - authenticate - legal "key" value', async (t) => { const body = await response.json(); - t.equal(response.status, 200, 'on POST of valid key, server should respond with a 200 OK'); - t.ok(body.token.length > 5, 'on POST of valid key, server should respond with a body with a token'); + t.equal( + response.status, + 200, + 'on POST of valid key, server should respond with a 200 OK', + ); + t.ok( + body.token.length > 5, + 'on POST of valid key, server should respond with a body with a token', + ); await app.close(); }); tap.test('auth - authenticate - illegal "key" value', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -54,7 +61,11 @@ tap.test('auth - authenticate - illegal "key" value', async (t) => { headers: formData.getHeaders(), }); - t.equal(response.status, 401, 'on POST of valid key, server should respond with a 401 Unauthorized'); + t.equal( + response.status, + 401, + 'on POST of valid key, server should respond with a 401 Unauthorized', + ); await app.close(); }); diff --git a/test/config.js b/test/config.js new file mode 100644 index 00000000..45a8a67b --- /dev/null +++ b/test/config.js @@ -0,0 +1,68 @@ +import tap from 'tap'; +import eik from '@eik/core'; +import { withDefaults } from '../lib/config.js'; + +tap.test('config - use default simple values', async (t) => { + const config = withDefaults({}); + t.equal(config.env, 'development', 'default env should be "development"'); +}); + +tap.test('config - provided config should override defaults', async (t) => { + const config = withDefaults({ + name: 'overridden', + }); + t.equal(config.name, 'overridden', 'provided name should override default'); +}); + +tap.test('config - use default object values', async (t) => { + const config = withDefaults({}); + t.same(config.log, { level: 'info' }, 'default log level should be "info"'); +}); + +tap.test( + 'config - provided object values should override default', + async (t) => { + const config = withDefaults({ + log: { + level: 'debug', + other: 'value', + }, + }); + t.same( + config.log, + { level: 'debug', other: 'value' }, + 'default log level should be "info"', + ); + }, +); + +tap.test( + 'config - default object values should not override other object content', + async (t) => { + const config = withDefaults({ + log: { + other: 'value', + }, + }); + t.same( + config.log, + { level: 'info', other: 'value' }, + 'default log level should be "info"', + ); + }, +); + +tap.test( + "config - don't apply default value on sink when providing a custom Sink", + async (t) => { + const customSink = new eik.sink.MEM(); + const config = withDefaults({ + sink: customSink, + }); + t.equal( + config.sink, + customSink, + 'customSink should not be overridden by default value', + ); + }, +); diff --git a/test/http.cache.control.js b/test/http.cache.control.js index 5439decd..cf1c47e3 100644 --- a/test/http.cache.control.js +++ b/test/http.cache.control.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -22,7 +22,7 @@ tap.cleanSnapshot = (s) => { tap.beforeEach(async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -41,9 +41,10 @@ tap.beforeEach(async (t) => { }); const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + // eslint-disable-next-line no-param-reassign + t.context = { address, headers, app, @@ -66,7 +67,11 @@ tap.test('cache-control - auth post', async (t) => { headers: formData.getHeaders(), }); - t.equal(response.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + response.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); }); tap.test('cache-control - package - non-scoped', async (t) => { @@ -80,34 +85,56 @@ tap.test('cache-control - package - non-scoped', async (t) => { method: 'PUT', body: formData, redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET file from server const fetched = await fetch(`${address}/pkg/fuzz/1.4.8/main/index.js`, { method: 'GET', }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/pkg/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); - + const nonExisting = await fetch( + `${address}/pkg/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET package overview from server const overview = await fetch(`${address}/pkg/fuzz/1.4.8`, { method: 'GET', }); - t.equal(overview.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + overview.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); // GET package versions overview from server const versions = await fetch(`${address}/pkg/fuzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - package - scoped', async (t) => { @@ -121,33 +148,59 @@ tap.test('cache-control - package - scoped', async (t) => { method: 'PUT', body: formData, redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET file from server - const fetched = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8/main/index.js`, { - method: 'GET', - }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + const fetched = await fetch( + `${address}/pkg/@cuz/fuzz/1.4.8/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/pkg/@cuz/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/pkg/@cuz/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET package overview from server const overview = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8`, { method: 'GET', }); - t.equal(overview.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + overview.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); // GET package versions overview from server const versions = await fetch(`${address}/pkg/@cuz/fuzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - npm package - non-scoped', async (t) => { @@ -161,33 +214,56 @@ tap.test('cache-control - npm package - non-scoped', async (t) => { method: 'PUT', body: formData, redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET file from server const fetched = await fetch(`${address}/npm/fuzz/1.4.8/main/index.js`, { method: 'GET', }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/npm/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/npm/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET package overview from server const overview = await fetch(`${address}/npm/fuzz/1.4.8`, { method: 'GET', }); - t.equal(overview.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + overview.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); // GET package versions overview from server const versions = await fetch(`${address}/npm/fuzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - npm package - scoped', async (t) => { @@ -201,33 +277,59 @@ tap.test('cache-control - npm package - scoped', async (t) => { method: 'PUT', body: formData, redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET file from server - const fetched = await fetch(`${address}/npm/@cuz/fuzz/1.4.8/main/index.js`, { - method: 'GET', - }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + const fetched = await fetch( + `${address}/npm/@cuz/fuzz/1.4.8/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/pkg/@cuz/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/pkg/@cuz/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET package overview from server const overview = await fetch(`${address}/npm/@cuz/fuzz/1.4.8`, { method: 'GET', }); - t.equal(overview.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + overview.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); // GET package versions overview from server const versions = await fetch(`${address}/npm/@cuz/fuzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - map - non-scoped', async (t) => { @@ -240,28 +342,47 @@ tap.test('cache-control - map - non-scoped', async (t) => { const uploaded = await fetch(`${address}/map/buzz/4.2.2`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET map from server const fetched = await fetch(`${address}/map/buzz/4.2.2`, { method: 'GET', }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/map/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/map/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET map versions overview from server const versions = await fetch(`${address}/map/buzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - map - scoped', async (t) => { @@ -274,28 +395,47 @@ tap.test('cache-control - map - scoped', async (t) => { const uploaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + uploaded.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET map from server const fetched = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { method: 'GET', }); - t.equal(fetched.headers.get('cache-control'), 'public, max-age=31536000, immutable', 'should be "public, max-age=31536000, immutable"'); + t.equal( + fetched.headers.get('cache-control'), + 'public, max-age=31536000, immutable', + 'should be "public, max-age=31536000, immutable"', + ); // GET non-existing file from server - const nonExisting = await fetch(`${address}/map/@cuz/fuzz/1.4.99999999999/main/index.js`, { - method: 'GET', - }); - t.equal(nonExisting.headers.get('cache-control'), 'public, max-age=5', 'should be "public, max-age=5"'); + const nonExisting = await fetch( + `${address}/map/@cuz/fuzz/1.4.99999999999/main/index.js`, + { + method: 'GET', + }, + ); + t.equal( + nonExisting.headers.get('cache-control'), + 'public, max-age=5', + 'should be "public, max-age=5"', + ); // GET map versions overview from server const versions = await fetch(`${address}/map/@cuz/buzz`, { method: 'GET', }); - t.equal(versions.headers.get('cache-control'), 'no-cache', 'should be "no-cache"'); + t.equal( + versions.headers.get('cache-control'), + 'no-cache', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias package - non-scoped', async (t) => { @@ -312,7 +452,7 @@ tap.test('cache-control - alias package - non-scoped', async (t) => { method: 'PUT', body: formDataA, redirect: 'manual', - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, }); // PUT files on server @@ -320,7 +460,7 @@ tap.test('cache-control - alias package - non-scoped', async (t) => { method: 'PUT', body: formDataB, redirect: 'manual', - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, }); // PUT alias on server @@ -330,17 +470,25 @@ tap.test('cache-control - alias package - non-scoped', async (t) => { const alias = await fetch(`${address}/pkg/fuzz/v8`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/pkg/fuzz/v8/main/index.js`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -349,17 +497,25 @@ tap.test('cache-control - alias package - non-scoped', async (t) => { const updated = await fetch(`${address}/pkg/fuzz/v8`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/pkg/fuzz/v8`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias package - scoped', async (t) => { @@ -376,7 +532,7 @@ tap.test('cache-control - alias package - scoped', async (t) => { method: 'PUT', body: formDataA, redirect: 'manual', - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, }); // PUT files on server @@ -384,7 +540,7 @@ tap.test('cache-control - alias package - scoped', async (t) => { method: 'PUT', body: formDataB, redirect: 'manual', - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, }); // PUT alias on server @@ -394,17 +550,25 @@ tap.test('cache-control - alias package - scoped', async (t) => { const alias = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/pkg/@cuz/fuzz/v8/main/index.js`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -413,17 +577,25 @@ tap.test('cache-control - alias package - scoped', async (t) => { const updated = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/pkg/@cuz/fuzz/v8`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias NPM package - non-scoped', async (t) => { @@ -440,7 +612,7 @@ tap.test('cache-control - alias NPM package - non-scoped', async (t) => { method: 'PUT', body: formDataA, redirect: 'manual', - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, }); // PUT files on server @@ -448,7 +620,7 @@ tap.test('cache-control - alias NPM package - non-scoped', async (t) => { method: 'PUT', body: formDataB, redirect: 'manual', - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, }); // PUT alias on server @@ -458,17 +630,25 @@ tap.test('cache-control - alias NPM package - non-scoped', async (t) => { const alias = await fetch(`${address}/npm/fuzz/v8`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/npm/fuzz/v8/main/index.js`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -477,17 +657,25 @@ tap.test('cache-control - alias NPM package - non-scoped', async (t) => { const updated = await fetch(`${address}/npm/fuzz/v8`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/npm/fuzz/v8`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias NPM package - scoped', async (t) => { @@ -504,7 +692,7 @@ tap.test('cache-control - alias NPM package - scoped', async (t) => { method: 'PUT', body: formDataA, redirect: 'manual', - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, }); // PUT files on server @@ -512,7 +700,7 @@ tap.test('cache-control - alias NPM package - scoped', async (t) => { method: 'PUT', body: formDataB, redirect: 'manual', - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, }); // PUT alias on server @@ -522,17 +710,25 @@ tap.test('cache-control - alias NPM package - scoped', async (t) => { const alias = await fetch(`${address}/npm/@cuz/fuzz/v8`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/npm/@cuz/fuzz/v8/main/index.js`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -541,17 +737,25 @@ tap.test('cache-control - alias NPM package - scoped', async (t) => { const updated = await fetch(`${address}/npm/@cuz/fuzz/v8`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/npm/@cuz/fuzz/v8`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias map - non-scoped', async (t) => { @@ -567,14 +771,14 @@ tap.test('cache-control - alias map - non-scoped', async (t) => { await fetch(`${address}/map/buzz/4.2.2`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); await fetch(`${address}/map/buzz/4.4.2`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -585,17 +789,25 @@ tap.test('cache-control - alias map - non-scoped', async (t) => { const alias = await fetch(`${address}/map/buzz/v4`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/map/buzz/v4`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -604,17 +816,25 @@ tap.test('cache-control - alias map - non-scoped', async (t) => { const updated = await fetch(`${address}/map/buzz/v4`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/map/buzz/v4`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); tap.test('cache-control - alias map - scoped', async (t) => { @@ -630,14 +850,14 @@ tap.test('cache-control - alias map - scoped', async (t) => { await fetch(`${address}/map/@cuz/buzz/4.2.2`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); await fetch(`${address}/map/@cuz/buzz/4.4.2`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -648,17 +868,25 @@ tap.test('cache-control - alias map - scoped', async (t) => { const alias = await fetch(`${address}/map/@cuz/buzz/v4`, { method: 'PUT', body: aliasFormData, - headers: { ...headers, ...aliasFormData.getHeaders()}, + headers: { ...headers, ...aliasFormData.getHeaders() }, redirect: 'manual', }); - t.equal(alias.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + alias.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // GET alias from server const redirect = await fetch(`${address}/map/@cuz/buzz/v4`, { method: 'GET', redirect: 'manual', }); - t.equal(redirect.headers.get('cache-control'), 'public, max-age=1200', 'should be "public, max-age=1200"'); + t.equal( + redirect.headers.get('cache-control'), + 'public, max-age=1200', + 'should be "public, max-age=1200"', + ); // POST alias on server const aliasFormDataB = new FormData(); @@ -667,15 +895,23 @@ tap.test('cache-control - alias map - scoped', async (t) => { const updated = await fetch(`${address}/map/@cuz/buzz/v4`, { method: 'POST', body: aliasFormDataB, - headers: { ...headers, ...aliasFormDataB.getHeaders()}, + headers: { ...headers, ...aliasFormDataB.getHeaders() }, redirect: 'manual', }); - t.equal(updated.headers.get('cache-control'), 'no-store', 'should be "no-store"'); + t.equal( + updated.headers.get('cache-control'), + 'no-store', + 'should be "no-store"', + ); // DELETE alias on server const deleted = await fetch(`${address}/map/@cuz/buzz/v4`, { method: 'DELETE', headers, }); - t.equal(deleted.headers.get('cache-control'), 'no-store', 'should be "no-cache"'); + t.equal( + deleted.headers.get('cache-control'), + 'no-store', + 'should be "no-cache"', + ); }); diff --git a/test/http.etag.js b/test/http.etag.js index 17d650c8..f5ca5570 100644 --- a/test/http.etag.js +++ b/test/http.etag.js @@ -2,16 +2,16 @@ import Fastify from 'fastify'; import fetch from 'node-fetch'; import tap from 'tap'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; // // Package GET // -tap.test('ETag - pkg:get - ETag and "If-None-Match" is matching', async t => { +tap.test('ETag - pkg:get - ETag and "If-None-Match" is matching', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -29,8 +29,16 @@ tap.test('ETag - pkg:get - ETag and "If-None-Match" is matching', async t => { const bodyA = await resA.text(); t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); const resB = await fetch(url, { method: 'GET', @@ -41,88 +49,130 @@ tap.test('ETag - pkg:get - ETag and "If-None-Match" is matching', async t => { const bodyB = await resB.text(); t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 304, 'second response should respond with http status 304'); + t.equal( + resB.status, + 304, + 'second response should respond with http status 304', + ); t.equal(bodyB, '', 'second response should respond with empty contents'); await app.close(); }); -tap.test('ETag - pkg:get - ETag and "If-None-Match" is NOT matching', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; - sink.set('/local/pkg/fuzz/8.4.1/main/index.js', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - headers: { - 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', - }, - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); - -tap.test('ETag - pkg:get - "If-None-Match" is NOT set on request', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; - sink.set('/local/pkg/fuzz/8.4.1/main/index.js', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); +tap.test( + 'ETag - pkg:get - ETag and "If-None-Match" is NOT matching', + async (t) => { + const sink = new Sink(); + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; + sink.set('/local/pkg/fuzz/8.4.1/main/index.js', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + headers: { + 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', + }, + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); + +tap.test( + 'ETag - pkg:get - "If-None-Match" is NOT set on request', + async (t) => { + const sink = new Sink(); + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; + sink.set('/local/pkg/fuzz/8.4.1/main/index.js', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); /* tap.test('ETag - pkg:get - ETags is configured to not be set', async t => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, config: { etag: false }, logger: false }); + const service = new Server({ sink, etag: false }); const address = await service.start(); const url = `${address}/pkg/fuzz/8.4.1/main/index.js`; @@ -157,9 +207,9 @@ tap.test('ETag - pkg:get - ETags is configured to not be set', async t => { // Package LOG // -tap.test('ETag - pkg:log - ETag and "If-None-Match" is matching', async t => { +tap.test('ETag - pkg:log - ETag and "If-None-Match" is matching', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -171,15 +221,22 @@ tap.test('ETag - pkg:log - ETag and "If-None-Match" is matching', async t => { const url = `${address}/pkg/fuzz/8.4.1`; sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); - const resA = await fetch(url, { method: 'GET', }); const bodyA = await resA.text(); t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); const resB = await fetch(url, { method: 'GET', @@ -190,88 +247,130 @@ tap.test('ETag - pkg:log - ETag and "If-None-Match" is matching', async t => { const bodyB = await resB.text(); t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 304, 'second response should respond with http status 304'); + t.equal( + resB.status, + 304, + 'second response should respond with http status 304', + ); t.equal(bodyB, '', 'second response should respond with empty contents'); await app.close(); }); -tap.test('ETag - pkg:log - ETag and "If-None-Match" is NOT matching', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/pkg/fuzz/8.4.1`; - sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - headers: { - 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', - }, - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); - -tap.test('ETag - pkg:log - "If-None-Match" is NOT set on request', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/pkg/fuzz/8.4.1`; - sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); +tap.test( + 'ETag - pkg:log - ETag and "If-None-Match" is NOT matching', + async (t) => { + const sink = new Sink(); + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/pkg/fuzz/8.4.1`; + sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + headers: { + 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', + }, + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); + +tap.test( + 'ETag - pkg:log - "If-None-Match" is NOT set on request', + async (t) => { + const sink = new Sink(); + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/pkg/fuzz/8.4.1`; + sink.set('/local/pkg/fuzz/8.4.1.package.json', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); /* tap.test('ETag - pkg:log - ETags is configured to not be set', async t => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, config: { etag: false }, logger: false }); + const service = new Server({ sink, etag: false }); const address = await service.start(); const url = `${address}/pkg/fuzz/8.4.1`; @@ -306,9 +405,9 @@ tap.test('ETag - pkg:log - ETags is configured to not be set', async t => { // Map GET // -tap.test('ETag - map:get - ETag and "If-None-Match" is matching', async t => { +tap.test('ETag - map:get - ETag and "If-None-Match" is matching', async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -320,15 +419,22 @@ tap.test('ETag - map:get - ETag and "If-None-Match" is matching', async t => { const url = `${address}/map/buzz/4.2.2`; sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); - const resA = await fetch(url, { method: 'GET', }); const bodyA = await resA.text(); t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); const resB = await fetch(url, { method: 'GET', @@ -339,88 +445,130 @@ tap.test('ETag - map:get - ETag and "If-None-Match" is matching', async t => { const bodyB = await resB.text(); t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 304, 'second response should respond with http status 304'); + t.equal( + resB.status, + 304, + 'second response should respond with http status 304', + ); t.equal(bodyB, '', 'second response should respond with empty contents'); await app.close(); }); -tap.test('ETag - map:get - ETag and "If-None-Match" is NOT matching', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/map/buzz/4.2.2`; - sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - headers: { - 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', - }, - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); - -tap.test('ETag - map:get - "If-None-Match" is NOT set on request', async t => { - const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, logger: false }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const url = `${address}/map/buzz/4.2.2`; - sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); - - const resA = await fetch(url, { - method: 'GET', - }); - const bodyA = await resA.text(); - - t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); - t.equal(resA.status, 200, 'first response should respond with http status 200'); - t.equal(bodyA, 'hello world', 'first response should respond with file contents'); - - const resB = await fetch(url, { - method: 'GET', - }); - const bodyB = await resB.text(); - - t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); - t.equal(resB.status, 200, 'second response should respond with http status 200'); - t.equal(bodyB, 'hello world', 'second response should respond with file contents'); - - await app.close(); -}); +tap.test( + 'ETag - map:get - ETag and "If-None-Match" is NOT matching', + async (t) => { + const sink = new Sink(); + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/map/buzz/4.2.2`; + sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + headers: { + 'If-None-Match': '5eb63bbbe01eeed-xxxxxxxxx', + }, + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); + +tap.test( + 'ETag - map:get - "If-None-Match" is NOT set on request', + async (t) => { + const sink = new Sink(); + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const url = `${address}/map/buzz/4.2.2`; + sink.set('/local/map/buzz/4.2.2.import-map.json', 'hello world'); + + const resA = await fetch(url, { + method: 'GET', + }); + const bodyA = await resA.text(); + + t.ok(resA.headers.get('etag'), 'first response should contain a ETag'); + t.equal( + resA.status, + 200, + 'first response should respond with http status 200', + ); + t.equal( + bodyA, + 'hello world', + 'first response should respond with file contents', + ); + + const resB = await fetch(url, { + method: 'GET', + }); + const bodyB = await resB.text(); + + t.ok(resB.headers.get('etag'), 'second response should contain a ETag'); + t.equal( + resB.status, + 200, + 'second response should respond with http status 200', + ); + t.equal( + bodyB, + 'hello world', + 'second response should respond with file contents', + ); + + await app.close(); + }, +); /* tap.test('ETag - map:get - ETags is configured to not be set', async t => { const sink = new Sink(); - const service = new Server({ customSink: sink, port: 0, config: { etag: false }, logger: false }); + const service = new Server({ sink, etag: false }); const address = await service.start(); const url = `${address}/map/buzz/4.2.2`; @@ -450,4 +598,4 @@ tap.test('ETag - map:get - ETags is configured to not be set', async t => { await service.stop(); }); -*/ \ No newline at end of file +*/ diff --git a/test/http.override.cache.control.js b/test/http.override.cache.control.js index 00290071..1b5ed277 100644 --- a/test/http.override.cache.control.js +++ b/test/http.override.cache.control.js @@ -22,7 +22,7 @@ tap.cleanSnapshot = (s) => { tap.beforeEach(async (t) => { const sink = new Sink(); const service = new Server({ - customSink: sink, + sink, aliasCacheControl: 'public, max-age=600', }); diff --git a/test/http.query.params.js b/test/http.query.params.js index c982e177..d490ca95 100644 --- a/test/http.query.params.js +++ b/test/http.query.params.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -22,7 +22,7 @@ tap.cleanSnapshot = (s) => { tap.beforeEach(async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -41,9 +41,10 @@ tap.beforeEach(async (t) => { }); const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + // eslint-disable-next-line no-param-reassign + t.context = { address, headers, app, @@ -64,16 +65,23 @@ tap.test('query params - package', async (t) => { await fetch(`${address}/pkg/fuzz/8.4.1`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); // GET file from server - const downloaded = await fetch(`${address}/pkg/fuzz/8.4.1/main/index.js?foo=bar`, { - method: 'GET', - }); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); + const downloaded = await fetch( + `${address}/pkg/fuzz/8.4.1/main/index.js?foo=bar`, + { + method: 'GET', + }, + ); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); }); tap.test('query params - NPM package', async (t) => { @@ -86,16 +94,23 @@ tap.test('query params - NPM package', async (t) => { await fetch(`${address}/npm/fuzz/8.4.1`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); // GET file from server - const downloaded = await fetch(`${address}/npm/fuzz/8.4.1/main/index.js?foo=bar`, { - method: 'GET', - }); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); + const downloaded = await fetch( + `${address}/npm/fuzz/8.4.1/main/index.js?foo=bar`, + { + method: 'GET', + }, + ); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); }); tap.test('query params - map', async (t) => { @@ -108,7 +123,7 @@ tap.test('query params - map', async (t) => { await fetch(`${address}/map/buzz/4.2.2`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); @@ -117,5 +132,9 @@ tap.test('query params - map', async (t) => { method: 'GET', }); - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); }); diff --git a/test/map.js b/test/map.js index 0da3cd68..52329e2d 100644 --- a/test/map.js +++ b/test/map.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -15,7 +15,7 @@ const FIXTURE_MAP = path.resolve(__dirname, '../fixtures/import-map.json'); tap.beforeEach(async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -34,9 +34,10 @@ tap.beforeEach(async (t) => { }); const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + // eslint-disable-next-line no-param-reassign + t.context = { address, headers, app, @@ -61,7 +62,11 @@ tap.test('import-map - no auth token on PUT - scoped', async (t) => { redirect: 'manual', }); - t.equal(uploaded.status, 401, 'on PUT of map, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of map, server should respond with a 401 Unauthorized', + ); }); tap.test('import-map - no auth token on PUT - non scoped', async (t) => { @@ -78,64 +83,104 @@ tap.test('import-map - no auth token on PUT - non scoped', async (t) => { redirect: 'manual', }); - t.equal(uploaded.status, 401, 'on PUT of map, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of map, server should respond with a 401 Unauthorized', + ); }); -tap.test('import-map - put map -> get map - scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('map', fs.createReadStream(FIXTURE_MAP)); - - // PUT map on server - const uploaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/@cuz/buzz/4.2.2`, 'on PUT of map, server should respond with a location header'); - - // GET map from server - const downloaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of map, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of map, response should match snapshot'); -}); - -tap.test('import-map - put map -> get map - non scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('map', fs.createReadStream(FIXTURE_MAP)); - - // PUT map on server - const uploaded = await fetch(`${address}/map/buzz/4.2.2`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of map, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/map/buzz/4.2.2`, 'on PUT of map, server should respond with a location header'); - - // GET map from server - const downloaded = await fetch(`${address}/map/buzz/4.2.2`, { - method: 'GET', - }); - - const downloadedResponse = await downloaded.json(); - - t.equal(downloaded.status, 200, 'on GET of map, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of map, response should match snapshot'); -}); +tap.test( + 'import-map - put map -> get map - scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('map', fs.createReadStream(FIXTURE_MAP)); + + // PUT map on server + const uploaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/@cuz/buzz/4.2.2`, + 'on PUT of map, server should respond with a location header', + ); + + // GET map from server + const downloaded = await fetch(`${address}/map/@cuz/buzz/4.2.2`, { + method: 'GET', + }); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of map, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of map, response should match snapshot', + ); + }, +); + +tap.test( + 'import-map - put map -> get map - non scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('map', fs.createReadStream(FIXTURE_MAP)); + + // PUT map on server + const uploaded = await fetch(`${address}/map/buzz/4.2.2`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of map, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/map/buzz/4.2.2`, + 'on PUT of map, server should respond with a location header', + ); + + // GET map from server + const downloaded = await fetch(`${address}/map/buzz/4.2.2`, { + method: 'GET', + }); + + const downloadedResponse = await downloaded.json(); + + t.equal( + downloaded.status, + 200, + 'on GET of map, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of map, response should match snapshot', + ); + }, +); tap.test('import-map - get map versions - scoped', async (t) => { const { headers, address } = t.context; @@ -147,7 +192,7 @@ tap.test('import-map - get map versions - scoped', async (t) => { await fetch(`${address}/map/@cuz/buzz/4.2.2`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -156,7 +201,7 @@ tap.test('import-map - get map versions - scoped', async (t) => { await fetch(`${address}/map/@cuz/buzz/5.2.2`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -165,7 +210,7 @@ tap.test('import-map - get map versions - scoped', async (t) => { await fetch(`${address}/map/@cuz/buzz/4.9.2`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -176,8 +221,15 @@ tap.test('import-map - get map versions - scoped', async (t) => { const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET of map versions, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of map versions, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET of map versions, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of map versions, response should match snapshot', + ); }); tap.test('import-map - get map versions - non scoped', async (t) => { @@ -190,7 +242,7 @@ tap.test('import-map - get map versions - non scoped', async (t) => { await fetch(`${address}/map/buzz/4.2.2`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -199,7 +251,7 @@ tap.test('import-map - get map versions - non scoped', async (t) => { await fetch(`${address}/map/buzz/5.2.2`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -208,7 +260,7 @@ tap.test('import-map - get map versions - non scoped', async (t) => { await fetch(`${address}/map/buzz/4.9.2`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -219,6 +271,13 @@ tap.test('import-map - get map versions - non scoped', async (t) => { const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET of map versions, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of map versions, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET of map versions, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of map versions, response should match snapshot', + ); }); diff --git a/test/npm.js b/test/npm.js index 2da4a33d..9a54aa4e 100644 --- a/test/npm.js +++ b/test/npm.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -21,7 +21,7 @@ tap.cleanSnapshot = (s) => { tap.beforeEach(async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -40,9 +40,10 @@ tap.beforeEach(async (t) => { }); const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + // eslint-disable-next-line no-param-reassign + t.context = { address, headers, app, @@ -67,7 +68,11 @@ tap.test('npm packages - no auth token on PUT - scoped', async (t) => { headers: formData.getHeaders(), }); - t.equal(uploaded.status, 401, 'on PUT of package, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of package, server should respond with a 401 Unauthorized', + ); }); tap.test('npm packages - no auth token on PUT - non scoped', async (t) => { @@ -84,62 +89,108 @@ tap.test('npm packages - no auth token on PUT - non scoped', async (t) => { headers: formData.getHeaders(), }); - t.equal(uploaded.status, 401, 'on PUT of package, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of package, server should respond with a 401 Unauthorized', + ); }); -tap.test('npm packages - put pkg -> get file - scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/@cuz/fuzz/1.4.8`, { - method: 'PUT', - body: formData, - redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/1.4.8`, 'on PUT of package, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}/npm/@cuz/fuzz/1.4.8/main/index.js`, { - method: 'GET', - }); - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of package, response should match snapshot'); -}); - -tap.test('npm packages - put pkg -> get file - non scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}/npm/fuzz/8.4.1/main/index.js`, { - method: 'GET', - }); - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of package, response should match snapshot'); -}); +tap.test( + 'npm packages - put pkg -> get file - scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/@cuz/fuzz/1.4.8`, { + method: 'PUT', + body: formData, + redirect: 'manual', + headers: { ...headers, ...formData.getHeaders() }, + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/1.4.8`, + 'on PUT of package, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}/npm/@cuz/fuzz/1.4.8/main/index.js`, + { + method: 'GET', + }, + ); + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of package, response should match snapshot', + ); + }, +); + +tap.test( + 'npm packages - put pkg -> get file - non scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/npm/fuzz/8.4.1`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}/npm/fuzz/8.4.1/main/index.js`, + { + method: 'GET', + }, + ); + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of package, response should match snapshot', + ); + }, +); tap.test('npm packages - get package overview - scoped', async (t) => { const { headers, address } = t.context; @@ -151,12 +202,20 @@ tap.test('npm packages - get package overview - scoped', async (t) => { const uploaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1/`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); // GET package overview from server const downloaded = await fetch(`${address}/npm/@cuz/fuzz/8.4.1/`, { @@ -164,8 +223,15 @@ tap.test('npm packages - get package overview - scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('npm packages - get package overview - non scoped', async (t) => { @@ -178,12 +244,20 @@ tap.test('npm packages - get package overview - non scoped', async (t) => { const uploaded = await fetch(`${address}/npm/fuzz/8.4.1/`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/npm/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/npm/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); // GET package overview from server const downloaded = await fetch(`${address}/npm/fuzz/8.4.1/`, { @@ -191,8 +265,15 @@ tap.test('npm packages - get package overview - non scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('npm packages - get package versions - scoped', async (t) => { @@ -205,7 +286,7 @@ tap.test('npm packages - get package versions - scoped', async (t) => { await fetch(`${address}/npm/@cuz/fuzz/7.3.2/`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -214,7 +295,7 @@ tap.test('npm packages - get package versions - scoped', async (t) => { await fetch(`${address}/npm/@cuz/fuzz/8.4.1/`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -223,7 +304,7 @@ tap.test('npm packages - get package versions - scoped', async (t) => { await fetch(`${address}/npm/@cuz/fuzz/8.5.1/`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -233,8 +314,15 @@ tap.test('npm packages - get package versions - scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('npm packages - get package versions - non scoped', async (t) => { @@ -247,7 +335,7 @@ tap.test('npm packages - get package versions - non scoped', async (t) => { await fetch(`${address}/npm/fuzz/7.3.2/`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -256,7 +344,7 @@ tap.test('npm packages - get package versions - non scoped', async (t) => { await fetch(`${address}/npm/fuzz/8.4.1/`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -265,7 +353,7 @@ tap.test('npm packages - get package versions - non scoped', async (t) => { await fetch(`${address}/npm/fuzz/8.5.1/`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -275,6 +363,13 @@ tap.test('npm packages - get package versions - non scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); diff --git a/test/pkg-put-write-integrity.js b/test/pkg-put-write-integrity.js index 43a84639..20c7e479 100644 --- a/test/pkg-put-write-integrity.js +++ b/test/pkg-put-write-integrity.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -28,165 +28,197 @@ const authentication = async (address) => { }); const { token } = await res.json(); - return { 'Authorization': `Bearer ${token}` }; -} - -tap.test('Sink is slow and irregular - Writing medium sized package', async t => { - const sink = new Sink(); - - // Simulate a slow write process by delaying each chunk written - // to the sink with something between 10 and 100 + (buffer count) ms. - sink.writeDelayChunks = (count) => { - const max = 100 + count; - const min = 10; - return Math.floor(Math.random() * max) + min; - }; - - const service = new Server({ customSink: sink }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const headers = await authentication(address); - - const formData = new FormData(); - formData.append( - 'package', - fs.createReadStream(path.join(__dirname, '../fixtures/archive.tgz')), - ); - - const res = await fetch(`${address}/pkg/frazz/2.1.4`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - }); - - const obj = await res.json(); - t.matchSnapshot(obj, 'on GET of package, response should match snapshot'); - - await app.close(); -}); - -tap.test('Sink is slow and irregular - Writing small sized package', async t => { - const sink = new Sink(); - - // Simulate a slow write process by delaying each chunk written - // to the sink with something between 10 and 100 + (buffer count) ms. - sink.writeDelayChunks = (count) => { - const max = 100 + count; - const min = 10; - return Math.floor(Math.random() * max) + min; - }; - - const service = new Server({ customSink: sink }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const headers = await authentication(address); - - const formData = new FormData(); - formData.append( - 'package', - fs.createReadStream(path.join(__dirname, '../fixtures/archive-small.tgz')), - ); - - const res = await fetch(`${address}/pkg/brazz/7.1.3`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - }); - - const obj = await res.json(); - t.matchSnapshot(obj, 'on GET of package, response should match snapshot'); - - await app.close(); -}); - -tap.test('Sink is slow to construct writer - Writing medium sized package', async t => { - const sink = new Sink(); - - // Simulate a slow creation of the sink write operation by delaying - // it something between 20 and 100ms. - sink.writeDelayResolve = () => { - const max = 100; - const min = 20; - return Math.floor(Math.random() * max) + min; - }; - - const service = new Server({ customSink: sink }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const headers = await authentication(address); - - const formData = new FormData(); - formData.append( - 'package', - fs.createReadStream(path.join(__dirname, '../fixtures/archive.tgz')), - ); - - const res = await fetch(`${address}/pkg/frazz/2.1.4`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - }); - - const obj = await res.json(); - t.matchSnapshot(obj, 'on GET of package, response should match snapshot'); - - await app.close(); -}); - -tap.test('Sink is slow to construct writer - Writing small sized package', async t => { - const sink = new Sink(); - - // Simulate a slow creation of the sink write operation by delaying - // it something between 20 and 100ms. - sink.writeDelayResolve = () => { - const max = 100; - const min = 20; - return Math.floor(Math.random() * max) + min; - }; - - const service = new Server({ customSink: sink }); - - const app = Fastify({ - ignoreTrailingSlash: true, - }); - app.register(service.api()); - - const address = await app.listen({ port: 0, host: '127.0.0.1' }); - - const headers = await authentication(address); - - const formData = new FormData(); - formData.append( - 'package', - fs.createReadStream(path.join(__dirname, '../fixtures/archive-small.tgz')), - ); - - const res = await fetch(`${address}/pkg/brazz/7.1.3`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - }); - - const obj = await res.json(); - t.matchSnapshot(obj, 'on GET of package, response should match snapshot'); + return { Authorization: `Bearer ${token}` }; +}; - await app.close(); -}); +tap.test( + 'Sink is slow and irregular - Writing medium sized package', + async (t) => { + const sink = new Sink(); + + // Simulate a slow write process by delaying each chunk written + // to the sink with something between 10 and 100 + (buffer count) ms. + sink.writeDelayChunks = (count) => { + const max = 100 + count; + const min = 10; + return Math.floor(Math.random() * max) + min; + }; + + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const headers = await authentication(address); + + const formData = new FormData(); + formData.append( + 'package', + fs.createReadStream( + path.join(__dirname, '../fixtures/archive.tgz'), + ), + ); + + const res = await fetch(`${address}/pkg/frazz/2.1.4`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + }); + + const obj = await res.json(); + t.matchSnapshot( + obj, + 'on GET of package, response should match snapshot', + ); + + await app.close(); + }, +); + +tap.test( + 'Sink is slow and irregular - Writing small sized package', + async (t) => { + const sink = new Sink(); + + // Simulate a slow write process by delaying each chunk written + // to the sink with something between 10 and 100 + (buffer count) ms. + sink.writeDelayChunks = (count) => { + const max = 100 + count; + const min = 10; + return Math.floor(Math.random() * max) + min; + }; + + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const headers = await authentication(address); + + const formData = new FormData(); + formData.append( + 'package', + fs.createReadStream( + path.join(__dirname, '../fixtures/archive-small.tgz'), + ), + ); + + const res = await fetch(`${address}/pkg/brazz/7.1.3`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + }); + + const obj = await res.json(); + t.matchSnapshot( + obj, + 'on GET of package, response should match snapshot', + ); + + await app.close(); + }, +); + +tap.test( + 'Sink is slow to construct writer - Writing medium sized package', + async (t) => { + const sink = new Sink(); + + // Simulate a slow creation of the sink write operation by delaying + // it something between 20 and 100ms. + sink.writeDelayResolve = () => { + const max = 100; + const min = 20; + return Math.floor(Math.random() * max) + min; + }; + + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const headers = await authentication(address); + + const formData = new FormData(); + formData.append( + 'package', + fs.createReadStream( + path.join(__dirname, '../fixtures/archive.tgz'), + ), + ); + + const res = await fetch(`${address}/pkg/frazz/2.1.4`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + }); + + const obj = await res.json(); + t.matchSnapshot( + obj, + 'on GET of package, response should match snapshot', + ); + + await app.close(); + }, +); + +tap.test( + 'Sink is slow to construct writer - Writing small sized package', + async (t) => { + const sink = new Sink(); + + // Simulate a slow creation of the sink write operation by delaying + // it something between 20 and 100ms. + sink.writeDelayResolve = () => { + const max = 100; + const min = 20; + return Math.floor(Math.random() * max) + min; + }; + + const service = new Server({ sink }); + + const app = Fastify({ + ignoreTrailingSlash: true, + }); + app.register(service.api()); + + const address = await app.listen({ port: 0, host: '127.0.0.1' }); + + const headers = await authentication(address); + + const formData = new FormData(); + formData.append( + 'package', + fs.createReadStream( + path.join(__dirname, '../fixtures/archive-small.tgz'), + ), + ); + + const res = await fetch(`${address}/pkg/brazz/7.1.3`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + }); + + const obj = await res.json(); + t.matchSnapshot( + obj, + 'on GET of package, response should match snapshot', + ); + + await app.close(); + }, +); diff --git a/test/pkg.js b/test/pkg.js index 8601d6f5..39fd0799 100644 --- a/test/pkg.js +++ b/test/pkg.js @@ -6,7 +6,7 @@ import tap from 'tap'; import url from 'url'; import fs from 'fs'; -import Sink from "@eik/core/lib/sinks/test.js"; +import Sink from '@eik/core/lib/sinks/test.js'; import Server from '../lib/main.js'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); @@ -21,7 +21,7 @@ tap.cleanSnapshot = (s) => { tap.beforeEach(async (t) => { const sink = new Sink(); - const service = new Server({ customSink: sink }); + const service = new Server({ sink }); const app = Fastify({ ignoreTrailingSlash: true, @@ -40,9 +40,10 @@ tap.beforeEach(async (t) => { }); const { token } = await res.json(); - const headers = { 'Authorization': `Bearer ${token}` }; + const headers = { Authorization: `Bearer ${token}` }; - t.context = { // eslint-disable-line no-param-reassign + // eslint-disable-next-line no-param-reassign + t.context = { address, headers, app, @@ -67,7 +68,11 @@ tap.test('packages - no auth token on PUT - scoped', async (t) => { headers: formData.getHeaders(), }); - t.equal(uploaded.status, 401, 'on PUT of package, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of package, server should respond with a 401 Unauthorized', + ); }); tap.test('packages - no auth token on PUT - non scoped', async (t) => { @@ -84,62 +89,108 @@ tap.test('packages - no auth token on PUT - non scoped', async (t) => { headers: formData.getHeaders(), }); - t.equal(uploaded.status, 401, 'on PUT of package, server should respond with a 401 Unauthorized'); + t.equal( + uploaded.status, + 401, + 'on PUT of package, server should respond with a 401 Unauthorized', + ); }); -tap.test('packages - put pkg -> get file - scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8`, { - method: 'PUT', - body: formData, - redirect: 'manual', - headers: { ...headers, ...formData.getHeaders()}, - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/1.4.8`, 'on PUT of package, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8/main/index.js`, { - method: 'GET', - }); - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of package, response should match snapshot'); -}); - -tap.test('packages - put pkg -> get file - non scoped successfully uploaded', async (t) => { - const { headers, address } = t.context; - - const formData = new FormData(); - formData.append('package', fs.createReadStream(FIXTURE_PKG)); - - // PUT files on server - const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { - method: 'PUT', - body: formData, - headers: { ...headers, ...formData.getHeaders()}, - redirect: 'manual', - }); - - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); - - // GET file from server - const downloaded = await fetch(`${address}/pkg/fuzz/8.4.1/main/index.js`, { - method: 'GET', - }); - const downloadedResponse = await downloaded.text(); - - t.equal(downloaded.status, 200, 'on GET of file, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET of package, response should match snapshot'); -}); +tap.test( + 'packages - put pkg -> get file - scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/1.4.8`, { + method: 'PUT', + body: formData, + redirect: 'manual', + headers: { ...headers, ...formData.getHeaders() }, + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/1.4.8`, + 'on PUT of package, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}/pkg/@cuz/fuzz/1.4.8/main/index.js`, + { + method: 'GET', + }, + ); + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of package, response should match snapshot', + ); + }, +); + +tap.test( + 'packages - put pkg -> get file - non scoped successfully uploaded', + async (t) => { + const { headers, address } = t.context; + + const formData = new FormData(); + formData.append('package', fs.createReadStream(FIXTURE_PKG)); + + // PUT files on server + const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1`, { + method: 'PUT', + body: formData, + headers: { ...headers, ...formData.getHeaders() }, + redirect: 'manual', + }); + + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); + + // GET file from server + const downloaded = await fetch( + `${address}/pkg/fuzz/8.4.1/main/index.js`, + { + method: 'GET', + }, + ); + const downloadedResponse = await downloaded.text(); + + t.equal( + downloaded.status, + 200, + 'on GET of file, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET of package, response should match snapshot', + ); + }, +); tap.test('packages - get package overview - scoped', async (t) => { const { headers, address } = t.context; @@ -151,12 +202,20 @@ tap.test('packages - get package overview - scoped', async (t) => { const uploaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1/`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/@cuz/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/@cuz/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); // GET package overview from server const downloaded = await fetch(`${address}/pkg/@cuz/fuzz/8.4.1/`, { @@ -164,8 +223,15 @@ tap.test('packages - get package overview - scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('packages - get package overview - non scoped', async (t) => { @@ -178,12 +244,20 @@ tap.test('packages - get package overview - non scoped', async (t) => { const uploaded = await fetch(`${address}/pkg/fuzz/8.4.1/`, { method: 'PUT', body: formData, - headers: { ...headers, ...formData.getHeaders()}, + headers: { ...headers, ...formData.getHeaders() }, redirect: 'manual', }); - t.equal(uploaded.status, 303, 'on PUT of package, server should respond with a 303 redirect'); - t.equal(uploaded.headers.get('location'), `/pkg/fuzz/8.4.1`, 'on PUT of package, server should respond with a location header'); + t.equal( + uploaded.status, + 303, + 'on PUT of package, server should respond with a 303 redirect', + ); + t.equal( + uploaded.headers.get('location'), + `/pkg/fuzz/8.4.1`, + 'on PUT of package, server should respond with a location header', + ); // GET package overview from server const downloaded = await fetch(`${address}/pkg/fuzz/8.4.1/`, { @@ -191,8 +265,15 @@ tap.test('packages - get package overview - non scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('packages - get package versions - scoped', async (t) => { @@ -205,7 +286,7 @@ tap.test('packages - get package versions - scoped', async (t) => { await fetch(`${address}/pkg/@cuz/fuzz/7.3.2/`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -214,7 +295,7 @@ tap.test('packages - get package versions - scoped', async (t) => { await fetch(`${address}/pkg/@cuz/fuzz/8.4.1/`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -223,7 +304,7 @@ tap.test('packages - get package versions - scoped', async (t) => { await fetch(`${address}/pkg/@cuz/fuzz/8.5.1/`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -233,8 +314,15 @@ tap.test('packages - get package versions - scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); }); tap.test('packages - get package versions - non scoped', async (t) => { @@ -247,7 +335,7 @@ tap.test('packages - get package versions - non scoped', async (t) => { await fetch(`${address}/pkg/fuzz/7.3.2/`, { method: 'PUT', body: formDataA, - headers: { ...headers, ...formDataA.getHeaders()}, + headers: { ...headers, ...formDataA.getHeaders() }, redirect: 'manual', }); @@ -256,7 +344,7 @@ tap.test('packages - get package versions - non scoped', async (t) => { await fetch(`${address}/pkg/fuzz/8.4.1/`, { method: 'PUT', body: formDataB, - headers: { ...headers, ...formDataB.getHeaders()}, + headers: { ...headers, ...formDataB.getHeaders() }, redirect: 'manual', }); @@ -265,7 +353,7 @@ tap.test('packages - get package versions - non scoped', async (t) => { await fetch(`${address}/pkg/fuzz/8.5.1/`, { method: 'PUT', body: formDataC, - headers: { ...headers, ...formDataC.getHeaders()}, + headers: { ...headers, ...formDataC.getHeaders() }, redirect: 'manual', }); @@ -275,6 +363,13 @@ tap.test('packages - get package versions - non scoped', async (t) => { }); const downloadedResponse = await downloaded.json(); - t.equal(downloaded.status, 200, 'on GET, server should respond with 200 ok'); - t.matchSnapshot(downloadedResponse, 'on GET, response should match snapshot'); + t.equal( + downloaded.status, + 200, + 'on GET, server should respond with 200 ok', + ); + t.matchSnapshot( + downloadedResponse, + 'on GET, response should match snapshot', + ); });