-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathhelpers.ts
151 lines (132 loc) · 4.5 KB
/
helpers.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import getPort from 'get-port'
import { getDeployStore } from '@netlify/blobs'
import { BlobsServer } from '@netlify/blobs/server'
import type { NetlifyPluginUtils } from '@netlify/build'
import IncrementalCache from 'next/dist/server/lib/incremental-cache/index.js'
import { Buffer } from 'node:buffer'
import { mkdtemp } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { assert, vi } from 'vitest'
import { BLOB_TOKEN } from './constants'
import { type FixtureTestContext } from './contexts'
/**
* Uses next.js incremental cache to compute the same cache key for a URL that is automatically generated
* This is needed for mocking out fetch calls to test them
*/
export const getFetchCacheKey = async (url: string) => {
const incCache = new IncrementalCache.IncrementalCache({
requestHeaders: {},
getPrerenderManifest: () => ({}),
} as any)
const key = await incCache.fetchCacheKey(url)
return key
}
/**
* Generates a 24char deploy ID (this is validated in the blob storage so we cant use a uuidv4)
* @returns
*/
export const generateRandomObjectID = () => {
const characters = 'abcdef0123456789'
let objectId = ''
for (let i = 0; i < 24; i++) {
objectId += characters[Math.floor(Math.random() * characters.length)]
}
return objectId
}
export const createBlobContext = (ctx: FixtureTestContext) =>
Buffer.from(
JSON.stringify({
edgeURL: `http://${ctx.blobStoreHost}`,
uncachedEdgeURL: `http://${ctx.blobStoreHost}`,
token: BLOB_TOKEN,
siteID: ctx.siteID,
deployID: ctx.deployID,
primaryRegion: 'us-test-1',
}),
).toString('base64')
/**
* Starts a new mock blob storage
* @param ctx
*/
export const startMockBlobStore = async (ctx: FixtureTestContext) => {
const port = await getPort()
// create new blob store server
ctx.blobServer = new BlobsServer({
port,
token: BLOB_TOKEN,
directory: await mkdtemp(join(tmpdir(), 'netlify-next-runtime-blob-')),
})
await ctx.blobServer.start()
ctx.blobServerGetSpy = vi.spyOn(ctx.blobServer, 'get')
ctx.blobStoreHost = `localhost:${port}`
ctx.blobStorePort = port
vi.stubEnv('NETLIFY_BLOBS_CONTEXT', createBlobContext(ctx))
ctx.blobStore = getDeployStore({
apiURL: `http://${ctx.blobStoreHost}`,
deployID: ctx.deployID,
experimentalRegion: 'context',
siteID: ctx.siteID,
token: BLOB_TOKEN,
})
}
/**
* Retrieves an array of blob store entries
*/
export const getBlobEntries = async (ctx: FixtureTestContext) => {
ctx.blobStore = ctx.blobStore
? ctx.blobStore
: getDeployStore({
apiURL: `http://${ctx.blobStoreHost}`,
deployID: ctx.deployID,
experimentalRegion: 'context',
siteID: ctx.siteID,
token: BLOB_TOKEN,
})
const { blobs } = await ctx.blobStore.list()
return blobs
}
export function getBlobServerGets(ctx: FixtureTestContext, predicate?: (key: string) => boolean) {
const isString = (arg: unknown): arg is string => typeof arg === 'string'
return ctx.blobServerGetSpy.mock.calls
.map(([request]) => {
if (typeof request.url !== 'string') {
return undefined
}
let urlSegments = request.url.split('/').slice(1)
// ignore region url component when using `experimentalRegion`
const REGION_PREFIX = 'region:'
if (urlSegments[0].startsWith(REGION_PREFIX)) {
urlSegments = urlSegments.slice(1)
}
const [_siteID, _deployID, key] = urlSegments
return key && decodeBlobKey(key)
})
.filter(isString)
.filter((key) => !predicate || predicate(key))
}
export function countOfBlobServerGetsForKey(ctx: FixtureTestContext, key: string) {
return getBlobServerGets(ctx).reduce((acc, curr) => (curr === key ? acc + 1 : acc), 0)
}
/**
* Converts a string to base64 blob key
*/
export const encodeBlobKey = (key: string) => Buffer.from(key).toString('base64url')
/**
* Converts a base64 blob key to a string
*/
export const decodeBlobKey = (key: string) => Buffer.from(key, 'base64url').toString('utf-8')
/**
* Fake build utils that are passed to a build plugin execution
*/
export const mockBuildUtils = {
failBuild: (message: string, options: { error?: Error }) => {
assert.fail(`${message}: ${options?.error || ''}`)
},
failPlugin: (message: string, options: { error?: Error }) => {
assert.fail(`${message}: ${options?.error || ''}`)
},
cancelBuild: (message: string, options: { error?: Error }) => {
assert.fail(`${message}: ${options?.error || ''}`)
},
} as unknown as NetlifyPluginUtils