Skip to content

Commit

Permalink
Add playback generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Ike Ku committed Sep 3, 2017
1 parent 0fad15d commit 62a92ab
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 16 deletions.
44 changes: 44 additions & 0 deletions src/common/chunks-to-body.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
type Headers = { [k: string]: string }

const isBuffer = Buffer.isBuffer
const isString = (a: any): a is string => typeof a === 'string'

const isContentEncoded = (headers: Headers) => {
const encoding = headers['content-encoding']
return isString(encoding) && encoding !== ''
}

const isBinaryBuffer = (buffer: Buffer) => {
if (!isBuffer(buffer)) return false

const reconstructedBuffer = new Buffer(buffer.toString('utf8'), 'utf8')
if (buffer.length !== reconstructedBuffer.length) return true

for (var i = 0; i < buffer.length; ++i)
if (buffer[i] !== reconstructedBuffer[i])
return true

return false
}

const mergeBuffers = (chunks: Buffer[]) => {
if (chunks.length === 0) return new Buffer(0)
if (!isBuffer(chunks[0])) return new Buffer(chunks.join(''), 'utf8')
return Buffer.concat(chunks)
}

const processEncodedBuffers = (chunks: Buffer[]) => chunks.map(c => {
if (!isBuffer(c) && isString(c)) c = new Buffer(c)
return c.toString('hex')
})

export default (chunks: Buffer[], headers: Headers = {}) => {
if (isContentEncoded(headers)) return processEncodedBuffers(chunks)
const mergedBuffers = mergeBuffers(chunks)
if (isBinaryBuffer(mergedBuffers)) return mergedBuffers.toString('hex')

const stringified = mergedBuffers.toString('utf8')
if (stringified.length === 0) return {}
try { return JSON.parse(stringified) }
catch (errr) { return stringified }
}
17 changes: 10 additions & 7 deletions src/common/normalize-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ import { Options } from '../interfaces'

const fromString = (str: string): Options => {
const { hostname, port, path } = url.parse(str)
return { hostname, method: 'GET', port: Number(port), path, __recording__: false }
}

const setProto = (options: any) => {
options.proto = options.proto || (options._https_ ? 'https' : 'http')
return {
hostname,
method: 'GET',
port: Number(port),
__recording__: false,
__https__: false,
path,
}
}

export default (raw: Options | string, protocol: string): Options => {
const options = typeof raw === 'string' ? fromString(raw) : raw
options.__https__ = protocol === 'https'
options.method = options.method || 'GET'
options.port = options.port || ((options.protocol === 'http') ? 80 : 443)
options.port = options.port || (options.__https__ ? 443 : 80)

if (options.host && !options.hostname) {
if (options.host.split(':').length === 2)
Expand All @@ -27,6 +31,5 @@ export default (raw: Options | string, protocol: string): Options => {
options.hostname = options.hostname.toLowerCase()
options.host = options.host.toLowerCase()

setProto(options)
return options
}
2 changes: 1 addition & 1 deletion src/interfaces.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { RequestOptions, IncomingMessage, ClientRequest } from 'http'

export type Request = ClientRequest
export type Options = RequestOptions & { __recording__: boolean }
export type Options = RequestOptions & { __recording__: boolean, __https__: boolean }
export type Response = IncomingMessage
export type Callback = (res: Response) => void
export type RequestMaker = (options: Options, cb?: Callback) => Request
Expand Down
2 changes: 0 additions & 2 deletions src/recorder/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import * as URL from 'url'
import record from './record'
import { Options } from '../interfaces'
import overrideNatives from '../common/override-natives'
import normalizeOptions from '../common/normalize-options'

Expand Down
32 changes: 28 additions & 4 deletions src/recorder/record.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
import * as I from '../interfaces'
import * as Request from './request'
import * as Response from './response'
import chunksToBody from '../common/chunks-to-body'

const getScope = ({ host, __https__, port }: I.Options) => {
let scope = `${__https__ ? 'https' : 'http'}://${host}`
const isDefaultPort = port.toString() === (__https__ ? '443' : '80')
const needPort = !host.includes(':') && port && isDefaultPort
return needPort ? `${scope}:${port}` : scope
}

const generatePlayback = (
req: I.Request,
res: I.Response,
options: I.Options,
requestBody: Buffer[],
responseBody: Buffer[]
) => ({
scope: getScope(options),
path: options.path,
method: options.method || 'GET',
status: res.statusCode,
body: chunksToBody(requestBody),
response: chunksToBody(responseBody, res.headers),
rawHeaders: res.rawHeaders || res.headers
})

export default async (protocol: string, options: I.Options, req: I.Request, res: I.Response) => {
const requestBody: Buffer[] = []
const responseBody: Buffer[] = []
Request.onData(req, chunk => requestBody.push(chunk))
Response.onData(res, chunk => responseBody.push(chunk))
Request.onData(req, requestBody.push.bind(requestBody))
Response.onData(res, responseBody.push.bind(responseBody))
await Response.waitEnd(res)

console.dir(Buffer.concat(requestBody).toString('utf8'))
console.dir(Buffer.concat(responseBody).toString('utf8'))
const playback = generatePlayback(req, res, options, requestBody, responseBody)
console.dir(playback, {colors: true, depth: 5})
}
3 changes: 1 addition & 2 deletions src/test/flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import record from '../recorder'
record()

test('Flow', async t => {
const response = await requet('https://api.github.com/repos/octokit/octokit.rb', {
const response = await requet.get('http://api.github.com/repos/octokit/octokit.rb', {
headers: { 'user-agent': 'ava-playback' }, json: true })
console.log(Object.keys(response))
t.true(typeof response === 'object')
})

0 comments on commit 62a92ab

Please sign in to comment.