Revamp dev env (#1031)
* wip * wip * fully refactor * msgs & ports * revamp appview tests * revamp pds tests * ensure plc close * ensure pds appview is hooked up when not running appview * move service setup to dev env * move admin auth headers to dev-env * fix service headers * missing port * fixing ports * start services in order * startup plc immediately * rm dead code * fix up build * rm log
This commit is contained in:
parent
231729db72
commit
47d30c1796
packages
bsky
src
tests
dev-env
pds/tests/proxied
@ -50,6 +50,7 @@ export class BskyAppView {
|
||||
config: ServerConfig
|
||||
imgInvalidator?: ImageInvalidator
|
||||
}): BskyAppView {
|
||||
console.log('CREATING bsky')
|
||||
const { db, config } = opts
|
||||
let maybeImgInvalidator = opts.imgInvalidator
|
||||
const app = express()
|
||||
@ -103,6 +104,7 @@ export class BskyAppView {
|
||||
})
|
||||
}
|
||||
|
||||
console.log('services')
|
||||
const services = createServices({
|
||||
imgUriBuilder,
|
||||
imgInvalidator,
|
||||
@ -120,6 +122,8 @@ export class BskyAppView {
|
||||
labeler,
|
||||
})
|
||||
|
||||
console.log('server')
|
||||
|
||||
let server = createServer({
|
||||
validateResponse: config.debugMode,
|
||||
payload: {
|
||||
@ -139,6 +143,7 @@ export class BskyAppView {
|
||||
app.use(server.xrpc.router)
|
||||
app.use(error.handler)
|
||||
|
||||
console.log('PROVIDER: ', config.repoProvider)
|
||||
const sub = config.repoProvider
|
||||
? new RepoSubscription(ctx, config.repoProvider, config.repoSubLockId)
|
||||
: undefined
|
||||
|
@ -1,36 +1,12 @@
|
||||
import { wait } from '@atproto/common'
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import { lexToJson } from '@atproto/lexicon'
|
||||
import { TestEnvInfo } from '@atproto/dev-env'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import * as uint8arrays from 'uint8arrays'
|
||||
import {
|
||||
FeedViewPost,
|
||||
PostView,
|
||||
isThreadViewPost,
|
||||
} from '../src/lexicon/types/app/bsky/feed/defs'
|
||||
import { isViewRecord } from '../src/lexicon/types/app/bsky/embed/record'
|
||||
import { createServiceJwt } from '@atproto/xrpc-server'
|
||||
|
||||
// for pds
|
||||
export const adminAuth = () => {
|
||||
return (
|
||||
'Basic ' +
|
||||
uint8arrays.toString(
|
||||
uint8arrays.fromString('admin:admin-pass', 'utf8'),
|
||||
'base64pad',
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const appViewHeaders = async (did: string, env: TestEnvInfo) => {
|
||||
const jwt = await createServiceJwt({
|
||||
iss: did,
|
||||
aud: env.bsky.ctx.cfg.serverDid,
|
||||
keypair: env.pds.ctx.repoSigningKey,
|
||||
})
|
||||
return { authorization: `Bearer ${jwt}` }
|
||||
}
|
||||
|
||||
// Swap out identifiers and dates with stable
|
||||
// values for the purpose of snapshot testing
|
||||
@ -166,25 +142,6 @@ export const paginateAll = async <T extends { cursor?: string }>(
|
||||
return results
|
||||
}
|
||||
|
||||
export const processAll = async (server: TestEnvInfo, timeout = 5000) => {
|
||||
const { bsky, pds } = server
|
||||
const sub = bsky.sub
|
||||
if (!sub) return
|
||||
const { db } = pds.ctx.db
|
||||
const start = Date.now()
|
||||
while (Date.now() - start < timeout) {
|
||||
await wait(50)
|
||||
if (!sub) return
|
||||
const state = await sub.getState()
|
||||
const { lastSeq } = await db
|
||||
.selectFrom('repo_seq')
|
||||
.select(db.fn.max('repo_seq.seq').as('lastSeq'))
|
||||
.executeTakeFirstOrThrow()
|
||||
if (state.cursor === lastSeq) return
|
||||
}
|
||||
throw new Error(`Sequence was not processed within ${timeout}ms`)
|
||||
}
|
||||
|
||||
// @NOTE mutates
|
||||
export const stripViewer = <T extends { viewer?: Record<string, unknown> }>(
|
||||
val: T,
|
||||
|
@ -1,37 +1,35 @@
|
||||
import axios, { AxiosInstance } from 'axios'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { AtpAgent } from '@atproto/api'
|
||||
import { verifyCidForBytes } from '@atproto/common'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { SeedClient } from './seeds/client'
|
||||
import basicSeed from './seeds/basic'
|
||||
import { randomBytes } from '@atproto/crypto'
|
||||
import { processAll } from './_util'
|
||||
|
||||
describe('blob resolver', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let client: AxiosInstance
|
||||
let fileDid: string
|
||||
let fileCid: CID
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_blob_resolver',
|
||||
})
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
const pdsAgent = network.pds.getClient()
|
||||
const sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
fileDid = sc.dids.carol
|
||||
fileCid = sc.posts[fileDid][0].images[0].image.ref
|
||||
client = axios.create({
|
||||
baseURL: testEnv.bsky.url,
|
||||
baseURL: network.bsky.url,
|
||||
validateStatus: () => true,
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('resolves blob with good signature check.', async () => {
|
||||
@ -80,8 +78,8 @@ describe('blob resolver', () => {
|
||||
})
|
||||
|
||||
it('fails on blob with bad signature check.', async () => {
|
||||
await testEnv.pds.ctx.blobstore.delete(fileCid)
|
||||
await testEnv.pds.ctx.blobstore.putPermanent(fileCid, randomBytes(100))
|
||||
await network.pds.ctx.blobstore.delete(fileCid)
|
||||
await network.pds.ctx.blobstore.putPermanent(fileCid, randomBytes(100))
|
||||
const tryGetBlob = client.get(`/blob/${fileDid}/${fileCid.toString()}`)
|
||||
await expect(tryGetBlob).rejects.toThrow(
|
||||
'maxContentLength size of -1 exceeded',
|
||||
|
@ -1,22 +1,22 @@
|
||||
import { once } from 'events'
|
||||
import { wait } from '@atproto/common'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { Database } from '../src'
|
||||
import { Leader } from '../src/db/leader'
|
||||
|
||||
describe('db', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let db: Database
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_db',
|
||||
})
|
||||
db = testEnv.bsky.ctx.db
|
||||
db = network.bsky.ctx.db
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
describe('transaction()', () => {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import { processAll } from './_util'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { SeedClient } from './seeds/client'
|
||||
import userSeed from './seeds/users'
|
||||
import { DidResolver } from '@atproto/did-resolver'
|
||||
@ -8,7 +7,7 @@ import DidSqlCache from '../src/did-cache'
|
||||
import { wait } from '@atproto/common'
|
||||
|
||||
describe('did cache', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let sc: SeedClient
|
||||
let didResolver: DidResolver
|
||||
let didCache: DidSqlCache
|
||||
@ -19,15 +18,15 @@ describe('did cache', () => {
|
||||
let dan: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_did_cache',
|
||||
})
|
||||
didResolver = testEnv.bsky.ctx.didResolver
|
||||
didCache = testEnv.bsky.ctx.didCache
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
didResolver = network.bsky.ctx.didResolver
|
||||
didCache = network.bsky.ctx.didCache
|
||||
const pdsAgent = new AtpAgent({ service: network.pds.url })
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await userSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
carol = sc.dids.carol
|
||||
@ -35,7 +34,7 @@ describe('did cache', () => {
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('caches dids on lookup', async () => {
|
||||
@ -85,9 +84,9 @@ describe('did cache', () => {
|
||||
})
|
||||
|
||||
it('accurately reports expired dids & refreshes the cache', async () => {
|
||||
const didCache = new DidSqlCache(testEnv.bsky.ctx.db, 1, 60000)
|
||||
const didCache = new DidSqlCache(network.bsky.ctx.db, 1, 60000)
|
||||
const shortCacheResolver = new DidResolver(
|
||||
{ plcUrl: testEnv.bsky.ctx.cfg.didPlcUrl },
|
||||
{ plcUrl: network.bsky.ctx.cfg.didPlcUrl },
|
||||
didCache,
|
||||
)
|
||||
const doc = await shortCacheResolver.resolveDid(alice)
|
||||
@ -114,9 +113,9 @@ describe('did cache', () => {
|
||||
})
|
||||
|
||||
it('does not return expired dids & refreshes the cache', async () => {
|
||||
const didCache = new DidSqlCache(testEnv.bsky.ctx.db, 0, 1)
|
||||
const didCache = new DidSqlCache(network.bsky.ctx.db, 0, 1)
|
||||
const shortExpireResolver = new DidResolver(
|
||||
{ plcUrl: testEnv.bsky.ctx.cfg.didPlcUrl },
|
||||
{ plcUrl: network.bsky.ctx.cfg.didPlcUrl },
|
||||
didCache,
|
||||
)
|
||||
const doc = await shortExpireResolver.resolveDid(alice)
|
||||
|
@ -1,28 +1,28 @@
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import { cidForCbor, TID } from '@atproto/common'
|
||||
import { WriteOpAction } from '@atproto/repo'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { Database } from '../src'
|
||||
import * as lex from '../src/lexicon/lexicons'
|
||||
import { Services } from '../src/services'
|
||||
|
||||
describe('duplicate record', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let did: string
|
||||
let db: Database
|
||||
let services: Services
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_duplicates',
|
||||
})
|
||||
db = testEnv.bsky.ctx.db
|
||||
services = testEnv.bsky.ctx.services
|
||||
db = network.bsky.ctx.db
|
||||
services = network.bsky.ctx.services
|
||||
did = 'did:example:alice'
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
const countRecords = async (db: Database, table: string) => {
|
||||
|
@ -2,20 +2,19 @@ import axios, { AxiosInstance } from 'axios'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { AtpAgent } from '@atproto/api'
|
||||
import { cidForCbor } from '@atproto/common'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { getInfo } from '../../src/image/sharp'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
import { processAll } from '../_util'
|
||||
|
||||
describe('image processing server', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let client: AxiosInstance
|
||||
let fileDid: string
|
||||
let fileCid: CID
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_image_processing_server',
|
||||
bsky: {
|
||||
imgUriKey:
|
||||
@ -23,25 +22,25 @@ describe('image processing server', () => {
|
||||
imgUriSalt: '9dd04221f5755bce5f55f47464c27e1e',
|
||||
},
|
||||
})
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
const pdsAgent = new AtpAgent({ service: network.pds.url })
|
||||
const sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
fileDid = sc.dids.carol
|
||||
fileCid = sc.posts[fileDid][0].images[0].image.ref
|
||||
client = axios.create({
|
||||
baseURL: `${testEnv.bsky.url}/image`,
|
||||
baseURL: `${network.bsky.url}/image`,
|
||||
validateStatus: () => true,
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('processes image from blob resolver.', async () => {
|
||||
const res = await client.get(
|
||||
testEnv.bsky.ctx.imgUriBuilder.getSignedPath({
|
||||
network.bsky.ctx.imgUriBuilder.getSignedPath({
|
||||
did: fileDid,
|
||||
cid: fileCid,
|
||||
format: 'jpeg',
|
||||
@ -71,7 +70,7 @@ describe('image processing server', () => {
|
||||
})
|
||||
|
||||
it('caches results.', async () => {
|
||||
const path = testEnv.bsky.ctx.imgUriBuilder.getSignedPath({
|
||||
const path = network.bsky.ctx.imgUriBuilder.getSignedPath({
|
||||
did: fileDid,
|
||||
cid: fileCid,
|
||||
format: 'jpeg',
|
||||
@ -89,7 +88,7 @@ describe('image processing server', () => {
|
||||
})
|
||||
|
||||
it('errors on bad signature.', async () => {
|
||||
const path = testEnv.bsky.ctx.imgUriBuilder.getSignedPath({
|
||||
const path = network.bsky.ctx.imgUriBuilder.getSignedPath({
|
||||
did: fileDid,
|
||||
cid: fileCid,
|
||||
format: 'jpeg',
|
||||
@ -106,7 +105,7 @@ describe('image processing server', () => {
|
||||
it('errors on missing file.', async () => {
|
||||
const missingCid = await cidForCbor('missing-file')
|
||||
const res = await client.get(
|
||||
testEnv.bsky.ctx.imgUriBuilder.getSignedPath({
|
||||
network.bsky.ctx.imgUriBuilder.getSignedPath({
|
||||
did: fileDid,
|
||||
cid: missingCid,
|
||||
format: 'jpeg',
|
||||
|
@ -6,8 +6,8 @@ import { WriteOpAction } from '@atproto/repo'
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import { Client } from '@did-plc/lib'
|
||||
import AtpAgent, { AppBskyActorProfile, AppBskyFeedPost } from '@atproto/api'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { appViewHeaders, forSnapshot, processAll } from './_util'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot } from './_util'
|
||||
import { SeedClient } from './seeds/client'
|
||||
import usersSeed from './seeds/users'
|
||||
import basicSeed from './seeds/basic'
|
||||
@ -15,30 +15,30 @@ import { ids } from '../src/lexicon/lexicons'
|
||||
import { Database } from '../src/db'
|
||||
|
||||
describe('indexing', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let pdsAgent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_indexing',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await usersSeed(sc)
|
||||
// Data in tests is not processed from subscription
|
||||
await processAll(testEnv)
|
||||
await testEnv.bsky.sub.destroy()
|
||||
await network.processAll()
|
||||
await network.bsky.sub.destroy()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('indexes posts.', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
const createdAt = new Date().toISOString()
|
||||
const createRecord = await prepareCreate({
|
||||
did: sc.dids.alice,
|
||||
@ -95,7 +95,7 @@ describe('indexing', () => {
|
||||
|
||||
const getAfterCreate = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: uri.toString() },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
expect(forSnapshot(getAfterCreate.data)).toMatchSnapshot()
|
||||
const createNotifications = await getNotifications(db, uri)
|
||||
@ -107,7 +107,7 @@ describe('indexing', () => {
|
||||
|
||||
const getAfterUpdate = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: uri.toString() },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
expect(forSnapshot(getAfterUpdate.data)).toMatchSnapshot()
|
||||
const updateNotifications = await getNotifications(db, uri)
|
||||
@ -119,7 +119,7 @@ describe('indexing', () => {
|
||||
|
||||
const getAfterDelete = agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: uri.toString() },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
await expect(getAfterDelete).rejects.toThrow(/Post not found:/)
|
||||
const deleteNotifications = await getNotifications(db, uri)
|
||||
@ -134,7 +134,7 @@ describe('indexing', () => {
|
||||
})
|
||||
|
||||
it('indexes profiles.', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
const createRecord = await prepareCreate({
|
||||
did: sc.dids.dan,
|
||||
collection: ids.AppBskyActorProfile,
|
||||
@ -167,7 +167,7 @@ describe('indexing', () => {
|
||||
|
||||
const getAfterCreate = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.dan },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
expect(forSnapshot(getAfterCreate.data)).toMatchSnapshot()
|
||||
|
||||
@ -178,7 +178,7 @@ describe('indexing', () => {
|
||||
|
||||
const getAfterUpdate = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.dan },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
expect(forSnapshot(getAfterUpdate.data)).toMatchSnapshot()
|
||||
|
||||
@ -189,33 +189,33 @@ describe('indexing', () => {
|
||||
|
||||
const getAfterDelete = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.dan },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
expect(forSnapshot(getAfterDelete.data)).toMatchSnapshot()
|
||||
})
|
||||
|
||||
describe('indexRepo', () => {
|
||||
beforeAll(async () => {
|
||||
testEnv.bsky.sub.resume()
|
||||
network.bsky.sub.resume()
|
||||
await basicSeed(sc, false)
|
||||
await processAll(testEnv)
|
||||
await testEnv.bsky.sub.destroy()
|
||||
await network.processAll()
|
||||
await network.bsky.sub.destroy()
|
||||
})
|
||||
|
||||
it('preserves indexes when no record changes.', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
// Mark originals
|
||||
const { data: origProfile } = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
const { data: origFeed } = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
const { data: origFollows } = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
// Index
|
||||
const { data: head } = await pdsAgent.api.com.atproto.sync.getHead({
|
||||
@ -227,15 +227,15 @@ describe('indexing', () => {
|
||||
// Check
|
||||
const { data: profile } = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
const { data: feed } = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
const { data: follows } = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
expect(forSnapshot([origProfile, origFeed, origFollows])).toEqual(
|
||||
forSnapshot([profile, feed, follows]),
|
||||
@ -243,7 +243,7 @@ describe('indexing', () => {
|
||||
})
|
||||
|
||||
it('updates indexes when records change.', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
// Update profile
|
||||
await pdsAgent.api.com.atproto.repo.putRecord(
|
||||
{
|
||||
@ -272,15 +272,15 @@ describe('indexing', () => {
|
||||
// Check
|
||||
const { data: profile } = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
const { data: feed } = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
const { data: follows } = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
expect(profile.description).toEqual('freshening things up')
|
||||
expect(feed.feed[0].post.uri).toEqual(newPost.ref.uriStr)
|
||||
@ -290,8 +290,8 @@ describe('indexing', () => {
|
||||
})
|
||||
|
||||
it('skips invalid records.', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db: pdsDb, services: pdsServices } = testEnv.pds.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
const { db: pdsDb, services: pdsServices } = network.pds.ctx
|
||||
// Create a good and a bad post record
|
||||
const writes = await Promise.all([
|
||||
pdsRepo.prepareCreate({
|
||||
@ -319,12 +319,12 @@ describe('indexing', () => {
|
||||
// Check
|
||||
const getGoodPost = agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: writes[0].uri.toString(), depth: 0 },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
await expect(getGoodPost).resolves.toBeDefined()
|
||||
const getBadPost = agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: writes[1].uri.toString(), depth: 0 },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
await expect(getBadPost).rejects.toThrow('Post not found')
|
||||
})
|
||||
@ -334,15 +334,15 @@ describe('indexing', () => {
|
||||
const getIndexedHandle = async (did) => {
|
||||
const res = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: did },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
return res.data.handle
|
||||
}
|
||||
|
||||
it('indexes handle for a fresh did', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
const now = new Date().toISOString()
|
||||
const sessionAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
const sessionAgent = new AtpAgent({ service: network.pds.url })
|
||||
const {
|
||||
data: { did },
|
||||
} = await sessionAgent.createAccount({
|
||||
@ -356,9 +356,9 @@ describe('indexing', () => {
|
||||
})
|
||||
|
||||
it('reindexes handle for existing did when forced', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
const now = new Date().toISOString()
|
||||
const sessionAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
const sessionAgent = new AtpAgent({ service: network.pds.url })
|
||||
const {
|
||||
data: { did },
|
||||
} = await sessionAgent.createAccount({
|
||||
@ -382,10 +382,10 @@ describe('indexing', () => {
|
||||
|
||||
describe('tombstoneActor', () => {
|
||||
it('does not unindex actor when their did is not tombstoned', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
const { data: profileBefore } = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.bob) },
|
||||
)
|
||||
// Attempt indexing tombstone
|
||||
await db.transaction((tx) =>
|
||||
@ -393,28 +393,28 @@ describe('indexing', () => {
|
||||
)
|
||||
const { data: profileAfter } = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.bob) },
|
||||
)
|
||||
expect(profileAfter).toEqual(profileBefore)
|
||||
})
|
||||
|
||||
it('unindexes actor when their did is tombstoned', async () => {
|
||||
const { db, services } = testEnv.bsky.ctx
|
||||
const { db, services } = network.bsky.ctx
|
||||
const getProfileBefore = agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.bob) },
|
||||
)
|
||||
await expect(getProfileBefore).resolves.toBeDefined()
|
||||
// Tombstone alice's did
|
||||
const plcClient = new Client(testEnv.plc.url)
|
||||
await plcClient.tombstone(sc.dids.alice, testEnv.pds.ctx.plcRotationKey)
|
||||
const plcClient = new Client(network.plc.url)
|
||||
await plcClient.tombstone(sc.dids.alice, network.pds.ctx.plcRotationKey)
|
||||
// Index tombstone
|
||||
await db.transaction((tx) =>
|
||||
services.indexing(tx).tombstoneActor(sc.dids.alice),
|
||||
)
|
||||
const getProfileAfter = agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(sc.dids.bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.bob) },
|
||||
)
|
||||
await expect(getProfileAfter).rejects.toThrow('Profile not found')
|
||||
})
|
||||
|
@ -7,14 +7,13 @@ import { keywordLabeling } from '../../src/labeler/util'
|
||||
import { cidForCbor, streamToBytes, TID } from '@atproto/common'
|
||||
import * as ui8 from 'uint8arrays'
|
||||
import { LabelService } from '../../src/services/label'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { DidResolver } from '@atproto/did-resolver'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import usersSeed from '../seeds/users'
|
||||
import { processAll } from '../_util'
|
||||
|
||||
describe('labeler', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let labeler: Labeler
|
||||
let labelSrvc: LabelService
|
||||
let ctx: AppContext
|
||||
@ -27,18 +26,18 @@ describe('labeler', () => {
|
||||
const profileUri = () => AtUri.make(alice, 'app.bsky.actor.profile', 'self')
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'labeler',
|
||||
})
|
||||
ctx = testEnv.bsky.ctx
|
||||
const pdsCtx = testEnv.pds.ctx
|
||||
ctx = network.bsky.ctx
|
||||
const pdsCtx = network.pds.ctx
|
||||
labelerDid = ctx.cfg.labelerDid
|
||||
labeler = new TestLabeler(ctx)
|
||||
labelSrvc = ctx.services.label(ctx.db)
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
const pdsAgent = new AtpAgent({ service: network.pds.url })
|
||||
const sc = new SeedClient(pdsAgent)
|
||||
await usersSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
const repoSvc = pdsCtx.services.repo(pdsCtx.db)
|
||||
const storeBlob = async (bytes: Uint8Array) => {
|
||||
@ -70,7 +69,7 @@ describe('labeler', () => {
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('labels text in posts', async () => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import AtpAgent, { ComAtprotoAdminTakeModerationAction } from '@atproto/api'
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import { adminAuth, appViewHeaders, forSnapshot, processAll } from './_util'
|
||||
import { forSnapshot } from './_util'
|
||||
import { ImageRef, RecordRef, SeedClient } from './seeds/client'
|
||||
import basicSeed from './seeds/basic'
|
||||
import {
|
||||
@ -15,23 +15,23 @@ import {
|
||||
} from '../src/lexicon/types/com/atproto/moderation/defs'
|
||||
|
||||
describe('moderation', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'moderation',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
describe('reporting', () => {
|
||||
@ -46,7 +46,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.alice, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.alice),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -61,7 +61,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.carol, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.carol),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -78,7 +78,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.alice, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.alice),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -99,7 +99,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.alice, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.alice),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -115,7 +115,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.carol, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.carol),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -138,7 +138,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.alice, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.alice),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -155,7 +155,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.carol, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.carol),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -175,7 +175,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.alice, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.alice),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -192,7 +192,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.carol, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.carol),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -209,7 +209,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const { data: actionResolvedReports } =
|
||||
@ -221,7 +221,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
@ -236,7 +236,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -252,7 +252,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.alice, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.alice),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -269,7 +269,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
@ -281,7 +281,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
@ -298,7 +298,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -317,7 +317,7 @@ describe('moderation', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: await appViewHeaders(sc.dids.alice, testEnv),
|
||||
headers: await network.serviceHeaders(sc.dids.alice),
|
||||
encoding: 'application/json',
|
||||
},
|
||||
)
|
||||
@ -335,7 +335,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
@ -347,7 +347,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
@ -364,7 +364,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -386,7 +386,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
expect(action1).toEqual(
|
||||
@ -413,7 +413,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
expect(action2).toEqual(
|
||||
@ -435,7 +435,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
await agent.api.com.atproto.admin.reverseModerationAction(
|
||||
@ -446,7 +446,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -467,7 +467,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const flagPromise = agent.api.com.atproto.admin.takeModerationAction(
|
||||
@ -483,7 +483,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
await expect(flagPromise).rejects.toThrow(
|
||||
@ -499,7 +499,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const { data: flag } =
|
||||
@ -516,7 +516,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
@ -529,7 +529,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -548,7 +548,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const flagPromise = agent.api.com.atproto.admin.takeModerationAction(
|
||||
@ -563,7 +563,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
await expect(flagPromise).rejects.toThrow(
|
||||
@ -579,7 +579,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const { data: flag } =
|
||||
@ -595,7 +595,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
@ -608,7 +608,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -632,7 +632,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const flagPromise = agent.api.com.atproto.admin.takeModerationAction(
|
||||
@ -649,7 +649,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
await expect(flagPromise).rejects.toThrow(
|
||||
@ -664,7 +664,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const { data: flag } =
|
||||
@ -682,7 +682,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
@ -695,13 +695,13 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
it('negates an existing label and reverses.', async () => {
|
||||
const { ctx } = testEnv.bsky
|
||||
const { ctx } = network.bsky
|
||||
const post = sc.posts[sc.dids.bob][0].ref
|
||||
const labelingService = ctx.services.label(ctx.db)
|
||||
await labelingService.formatAndCreate(
|
||||
@ -731,7 +731,7 @@ describe('moderation', () => {
|
||||
})
|
||||
|
||||
it('no-ops when negating an already-negated label and reverses.', async () => {
|
||||
const { ctx } = testEnv.bsky
|
||||
const { ctx } = network.bsky
|
||||
const post = sc.posts[sc.dids.bob][0].ref
|
||||
const labelingService = ctx.services.label(ctx.db)
|
||||
const action = await actionWithLabels({
|
||||
@ -774,7 +774,7 @@ describe('moderation', () => {
|
||||
})
|
||||
|
||||
it('no-ops when creating an existing label and reverses.', async () => {
|
||||
const { ctx } = testEnv.bsky
|
||||
const { ctx } = network.bsky
|
||||
const post = sc.posts[sc.dids.bob][0].ref
|
||||
const labelingService = ctx.services.label(ctx.db)
|
||||
await labelingService.formatAndCreate(
|
||||
@ -814,7 +814,7 @@ describe('moderation', () => {
|
||||
})
|
||||
|
||||
it('creates and negates labels on a repo and reverses.', async () => {
|
||||
const { ctx } = testEnv.bsky
|
||||
const { ctx } = network.bsky
|
||||
const labelingService = ctx.services.label(ctx.db)
|
||||
await labelingService.formatAndCreate(
|
||||
ctx.cfg.labelerDid,
|
||||
@ -849,7 +849,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
return result.data
|
||||
@ -864,7 +864,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -872,7 +872,7 @@ describe('moderation', () => {
|
||||
async function getRecordLabels(uri: string) {
|
||||
const result = await agent.api.com.atproto.admin.getRecord(
|
||||
{ uri },
|
||||
{ headers: { authorization: adminAuth() } },
|
||||
{ headers: network.pds.adminAuthHeaders() },
|
||||
)
|
||||
const labels = result.data.labels ?? []
|
||||
return labels.map((l) => l.val)
|
||||
@ -881,7 +881,7 @@ describe('moderation', () => {
|
||||
async function getRepoLabels(did: string) {
|
||||
const result = await agent.api.com.atproto.admin.getRepo(
|
||||
{ did },
|
||||
{ headers: { authorization: adminAuth() } },
|
||||
{ headers: network.pds.adminAuthHeaders() },
|
||||
)
|
||||
const labels = result.data.labels ?? []
|
||||
return labels.map((l) => l.val)
|
||||
@ -894,7 +894,7 @@ describe('moderation', () => {
|
||||
let imageUri: string
|
||||
let actionId: number
|
||||
beforeAll(async () => {
|
||||
const { ctx } = testEnv.bsky
|
||||
const { ctx } = network.bsky
|
||||
post = sc.posts[sc.dids.carol][0]
|
||||
blob = post.images[1]
|
||||
imageUri = ctx.imgUriBuilder
|
||||
@ -903,7 +903,7 @@ describe('moderation', () => {
|
||||
sc.dids.carol,
|
||||
blob.image.ref.toString(),
|
||||
)
|
||||
.replace(ctx.cfg.publicUrl || '', testEnv.bsky.url)
|
||||
.replace(ctx.cfg.publicUrl || '', network.bsky.url)
|
||||
// Warm image server cache
|
||||
await fetch(imageUri)
|
||||
const cached = await fetch(imageUri)
|
||||
@ -922,7 +922,7 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
actionId = takeAction.data.id
|
||||
@ -930,7 +930,7 @@ describe('moderation', () => {
|
||||
|
||||
it('prevents resolution of blob', async () => {
|
||||
const blobPath = `/blob/${sc.dids.carol}/${blob.image.ref.toString()}`
|
||||
const resolveBlob = await fetch(`${testEnv.bsky.url}${blobPath}`)
|
||||
const resolveBlob = await fetch(`${network.bsky.url}${blobPath}`)
|
||||
expect(resolveBlob.status).toEqual(404)
|
||||
expect(await resolveBlob.json()).toEqual({
|
||||
error: 'NotFoundError',
|
||||
@ -953,13 +953,13 @@ describe('moderation', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
// Can resolve blob
|
||||
const blobPath = `/blob/${sc.dids.carol}/${blob.image.ref.toString()}`
|
||||
const resolveBlob = await fetch(`${testEnv.bsky.url}${blobPath}`)
|
||||
const resolveBlob = await fetch(`${network.bsky.url}${blobPath}`)
|
||||
expect(resolveBlob.status).toEqual(200)
|
||||
|
||||
// Can fetch through image server
|
||||
|
@ -1,27 +1,27 @@
|
||||
import { AddressInfo } from 'net'
|
||||
import express from 'express'
|
||||
import axios, { AxiosError } from 'axios'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { handler as errorHandler } from '../src/error'
|
||||
import { Database } from '../src'
|
||||
|
||||
describe('server', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let db: Database
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_server',
|
||||
})
|
||||
db = testEnv.bsky.ctx.db
|
||||
db = network.bsky.ctx.db
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('preserves 404s.', async () => {
|
||||
const promise = axios.get(`${testEnv.bsky.url}/unknown`)
|
||||
const promise = axios.get(`${network.bsky.url}/unknown`)
|
||||
await expect(promise).rejects.toThrow('failed with status code 404')
|
||||
})
|
||||
|
||||
@ -49,7 +49,7 @@ describe('server', () => {
|
||||
})
|
||||
|
||||
it('healthcheck succeeds when database is available.', async () => {
|
||||
const { data, status } = await axios.get(`${testEnv.bsky.url}/xrpc/_health`)
|
||||
const { data, status } = await axios.get(`${network.bsky.url}/xrpc/_health`)
|
||||
expect(status).toEqual(200)
|
||||
expect(data).toEqual({ version: '0.0.0' })
|
||||
})
|
||||
@ -59,7 +59,7 @@ describe('server', () => {
|
||||
let error: AxiosError
|
||||
try {
|
||||
await axios.post(
|
||||
`${testEnv.bsky.url}/xrpc/com.atproto.repo.createRecord`,
|
||||
`${network.bsky.url}/xrpc/com.atproto.repo.createRecord`,
|
||||
{
|
||||
data: 'x'.repeat(100 * 1024), // 100kb
|
||||
},
|
||||
@ -81,11 +81,11 @@ describe('server', () => {
|
||||
})
|
||||
|
||||
it('healthcheck fails when database is unavailable.', async () => {
|
||||
await testEnv.bsky.sub.destroy()
|
||||
await network.bsky.sub.destroy()
|
||||
await db.close()
|
||||
let error: AxiosError
|
||||
try {
|
||||
await axios.get(`${testEnv.bsky.url}/xrpc/_health`)
|
||||
await axios.get(`${network.bsky.url}/xrpc/_health`)
|
||||
throw new Error('Healthcheck should have failed')
|
||||
} catch (err) {
|
||||
if (axios.isAxiosError(err)) {
|
||||
|
@ -1,30 +1,30 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import basicSeed from '../seeds/basic'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { forSnapshot, processAll } from '../_util'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot } from '../_util'
|
||||
import { AppContext, Database } from '../../src'
|
||||
import { DatabaseSchemaType } from '../../src/db/database-schema'
|
||||
import { ids } from '../../src/lexicon/lexicons'
|
||||
|
||||
describe('sync', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let ctx: AppContext
|
||||
let pdsAgent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_subscription_repo',
|
||||
})
|
||||
ctx = testEnv.bsky.ctx
|
||||
pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
ctx = network.bsky.ctx
|
||||
pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('indexes permit history being replayed.', async () => {
|
||||
@ -41,7 +41,7 @@ describe('sync', () => {
|
||||
await updateProfile(pdsAgent, alice, { displayName: 'ali!' })
|
||||
await updateProfile(pdsAgent, bob, { displayName: 'robert!' })
|
||||
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
// Table comparator
|
||||
const getTableDump = async () => {
|
||||
@ -60,10 +60,10 @@ describe('sync', () => {
|
||||
const originalTableDump = await getTableDump()
|
||||
|
||||
// Reprocess repos via sync subscription, on top of existing indices
|
||||
await testEnv.bsky.sub?.destroy()
|
||||
await testEnv.bsky.sub?.resetState()
|
||||
testEnv.bsky.sub?.resume()
|
||||
await processAll(testEnv)
|
||||
await network.bsky.sub?.destroy()
|
||||
await network.bsky.sub?.resetState()
|
||||
network.bsky.sub?.resume()
|
||||
await network.processAll()
|
||||
|
||||
// Permissive of indexedAt times changing
|
||||
expect(forSnapshot(await getTableDump())).toEqual(
|
||||
|
@ -1,39 +1,31 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { wait } from '@atproto/common'
|
||||
import { CloseFn, runTestEnv } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
|
||||
import {
|
||||
adminAuth,
|
||||
forSnapshot,
|
||||
paginateAll,
|
||||
processAll,
|
||||
stripViewer,
|
||||
} from '../_util'
|
||||
import { forSnapshot, paginateAll, stripViewer } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import usersBulkSeed from '../seeds/users-bulk'
|
||||
import { appViewHeaders } from '../_util'
|
||||
|
||||
describe('pds actor search views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
let headers: { [s: string]: string }
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_actor_search',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
|
||||
await wait(50) // allow pending sub to be established
|
||||
await testEnv.bsky.sub.destroy()
|
||||
await network.bsky.sub?.destroy()
|
||||
await usersBulkSeed(sc)
|
||||
|
||||
// Skip did/handle resolution for expediency
|
||||
const { db } = testEnv.bsky.ctx
|
||||
const { db } = network.bsky.ctx
|
||||
const now = new Date().toISOString()
|
||||
await db.db
|
||||
.insertInto('actor')
|
||||
@ -48,13 +40,13 @@ describe('pds actor search views', () => {
|
||||
.execute()
|
||||
|
||||
// Process remaining profiles
|
||||
testEnv.bsky.sub.resume()
|
||||
await processAll(testEnv, 50000)
|
||||
headers = await appViewHeaders(Object.values(sc.dids)[0], testEnv)
|
||||
network.bsky.sub?.resume()
|
||||
await network.processAll(50000)
|
||||
headers = await network.serviceHeaders(Object.values(sc.dids)[0])
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('typeahead gives relevant results', async () => {
|
||||
@ -237,7 +229,7 @@ describe('pds actor search views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const result = await agent.api.app.bsky.actor.searchActorsTypeahead(
|
||||
|
@ -1,20 +1,13 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import {
|
||||
appViewHeaders,
|
||||
adminAuth,
|
||||
forSnapshot,
|
||||
paginateAll,
|
||||
processAll,
|
||||
stripViewerFromPost,
|
||||
} from '../_util'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, paginateAll, stripViewerFromPost } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
|
||||
|
||||
describe('pds author feed views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -24,15 +17,15 @@ describe('pds author feed views', () => {
|
||||
let dan: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_author_feed',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await testEnv.bsky.ctx.labeler.processAll()
|
||||
await network.processAll()
|
||||
await network.bsky.ctx.labeler.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
carol = sc.dids.carol
|
||||
@ -40,7 +33,7 @@ describe('pds author feed views', () => {
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
// @TODO(bsky) blocked by actor takedown via labels.
|
||||
@ -49,28 +42,28 @@ describe('pds author feed views', () => {
|
||||
it('fetches full author feeds for self (sorted, minimal viewer state).', async () => {
|
||||
const aliceForAlice = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.accounts[alice].handle },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(aliceForAlice.data.feed)).toMatchSnapshot()
|
||||
|
||||
const bobForBob = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.accounts[bob].handle },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(bobForBob.data.feed)).toMatchSnapshot()
|
||||
|
||||
const carolForCarol = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.accounts[carol].handle },
|
||||
{ headers: await appViewHeaders(carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(carol) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(carolForCarol.data.feed)).toMatchSnapshot()
|
||||
|
||||
const danForDan = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.accounts[dan].handle },
|
||||
{ headers: await appViewHeaders(dan, testEnv) },
|
||||
{ headers: await network.serviceHeaders(dan) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(danForDan.data.feed)).toMatchSnapshot()
|
||||
@ -79,7 +72,7 @@ describe('pds author feed views', () => {
|
||||
it("reflects fetching user's state in the feed.", async () => {
|
||||
const aliceForCarol = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.accounts[alice].handle },
|
||||
{ headers: await appViewHeaders(carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(carol) },
|
||||
)
|
||||
|
||||
aliceForCarol.data.feed.forEach((postView) => {
|
||||
@ -100,7 +93,7 @@ describe('pds author feed views', () => {
|
||||
cursor,
|
||||
limit: 2,
|
||||
},
|
||||
{ headers: await appViewHeaders(dan, testEnv) },
|
||||
{ headers: await network.serviceHeaders(dan) },
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
@ -112,7 +105,7 @@ describe('pds author feed views', () => {
|
||||
|
||||
const full = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.accounts[alice].handle },
|
||||
{ headers: await appViewHeaders(dan, testEnv) },
|
||||
{ headers: await network.serviceHeaders(dan) },
|
||||
)
|
||||
|
||||
expect(full.data.feed.length).toEqual(4)
|
||||
@ -122,7 +115,7 @@ describe('pds author feed views', () => {
|
||||
it('fetches results unauthed.', async () => {
|
||||
const { data: authed } = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: sc.accounts[alice].handle },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.feed.getAuthorFeed({
|
||||
actor: sc.accounts[alice].handle,
|
||||
@ -148,7 +141,7 @@ describe('pds author feed views', () => {
|
||||
it('blocked by actor takedown.', async () => {
|
||||
const { data: preBlock } = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(carol) },
|
||||
)
|
||||
|
||||
expect(preBlock.feed.length).toBeGreaterThan(0)
|
||||
@ -166,13 +159,13 @@ describe('pds author feed views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
const { data: postBlock } = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(carol) },
|
||||
)
|
||||
|
||||
expect(postBlock.feed.length).toEqual(0)
|
||||
@ -186,7 +179,7 @@ describe('pds author feed views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -194,7 +187,7 @@ describe('pds author feed views', () => {
|
||||
it('blocked by record takedown.', async () => {
|
||||
const { data: preBlock } = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(carol) },
|
||||
)
|
||||
|
||||
expect(preBlock.feed.length).toBeGreaterThan(0)
|
||||
@ -215,13 +208,13 @@ describe('pds author feed views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
const { data: postBlock } = await agent.api.app.bsky.feed.getAuthorFeed(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(carol) },
|
||||
)
|
||||
|
||||
expect(postBlock.feed.length).toEqual(preBlock.feed.length - 1)
|
||||
@ -236,7 +229,7 @@ describe('pds author feed views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
@ -1,39 +1,32 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import {
|
||||
adminAuth,
|
||||
appViewHeaders,
|
||||
forSnapshot,
|
||||
paginateAll,
|
||||
processAll,
|
||||
stripViewer,
|
||||
} from '../_util'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, paginateAll, stripViewer } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import followsSeed from '../seeds/follows'
|
||||
import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
|
||||
|
||||
describe('pds follow views', () => {
|
||||
let agent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
let alice: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_follows',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await followsSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
// TODO(bsky) blocks followers by actor takedown via labels
|
||||
@ -42,35 +35,35 @@ describe('pds follow views', () => {
|
||||
it('fetches followers', async () => {
|
||||
const aliceFollowers = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(aliceFollowers.data)).toMatchSnapshot()
|
||||
|
||||
const bobFollowers = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.bob },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(bobFollowers.data)).toMatchSnapshot()
|
||||
|
||||
const carolFollowers = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.carol },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(carolFollowers.data)).toMatchSnapshot()
|
||||
|
||||
const danFollowers = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.dan },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(danFollowers.data)).toMatchSnapshot()
|
||||
|
||||
const eveFollowers = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.eve },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(eveFollowers.data)).toMatchSnapshot()
|
||||
@ -79,11 +72,11 @@ describe('pds follow views', () => {
|
||||
it('fetches followers by handle', async () => {
|
||||
const byDid = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const byHandle = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.accounts[alice].handle },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
expect(byHandle.data).toEqual(byDid.data)
|
||||
})
|
||||
@ -97,7 +90,7 @@ describe('pds follow views', () => {
|
||||
cursor,
|
||||
limit: 2,
|
||||
},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
@ -109,7 +102,7 @@ describe('pds follow views', () => {
|
||||
|
||||
const full = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(full.data.followers.length).toEqual(4)
|
||||
@ -119,7 +112,7 @@ describe('pds follow views', () => {
|
||||
it('fetches followers unauthed', async () => {
|
||||
const { data: authed } = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.graph.getFollowers({
|
||||
actor: sc.dids.alice,
|
||||
@ -142,13 +135,13 @@ describe('pds follow views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
const aliceFollowers = await agent.api.app.bsky.graph.getFollowers(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(aliceFollowers.data.followers.map((f) => f.did)).not.toContain(
|
||||
@ -163,7 +156,7 @@ describe('pds follow views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -171,35 +164,35 @@ describe('pds follow views', () => {
|
||||
it('fetches follows', async () => {
|
||||
const aliceFollowers = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(aliceFollowers.data)).toMatchSnapshot()
|
||||
|
||||
const bobFollowers = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.bob },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(bobFollowers.data)).toMatchSnapshot()
|
||||
|
||||
const carolFollowers = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.carol },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(carolFollowers.data)).toMatchSnapshot()
|
||||
|
||||
const danFollowers = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.dan },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(danFollowers.data)).toMatchSnapshot()
|
||||
|
||||
const eveFollowers = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.eve },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(eveFollowers.data)).toMatchSnapshot()
|
||||
@ -208,11 +201,11 @@ describe('pds follow views', () => {
|
||||
it('fetches follows by handle', async () => {
|
||||
const byDid = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const byHandle = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.accounts[alice].handle },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
expect(byHandle.data).toEqual(byDid.data)
|
||||
})
|
||||
@ -226,7 +219,7 @@ describe('pds follow views', () => {
|
||||
cursor,
|
||||
limit: 2,
|
||||
},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
@ -238,7 +231,7 @@ describe('pds follow views', () => {
|
||||
|
||||
const full = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(full.data.follows.length).toEqual(4)
|
||||
@ -248,7 +241,7 @@ describe('pds follow views', () => {
|
||||
it('fetches follows unauthed', async () => {
|
||||
const { data: authed } = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.graph.getFollows({
|
||||
actor: sc.dids.alice,
|
||||
@ -271,13 +264,13 @@ describe('pds follow views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
const aliceFollows = await agent.api.app.bsky.graph.getFollows(
|
||||
{ actor: sc.dids.alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(aliceFollows.data.follows.map((f) => f.did)).not.toContain(
|
||||
@ -292,7 +285,7 @@ describe('pds follow views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
@ -1,20 +1,13 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import likesSeed from '../seeds/likes'
|
||||
import {
|
||||
appViewHeaders,
|
||||
constantDate,
|
||||
forSnapshot,
|
||||
paginateAll,
|
||||
processAll,
|
||||
stripViewer,
|
||||
} from '../_util'
|
||||
import { constantDate, forSnapshot, paginateAll, stripViewer } from '../_util'
|
||||
|
||||
describe('pds like views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let pdsAgent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -22,20 +15,20 @@ describe('pds like views', () => {
|
||||
let bob: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_likes',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await likesSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
const getCursors = (items: { createdAt?: string }[]) =>
|
||||
@ -49,7 +42,7 @@ describe('pds like views', () => {
|
||||
it('fetches post likes', async () => {
|
||||
const alicePost = await agent.api.app.bsky.feed.getLikes(
|
||||
{ uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(alicePost.data)).toMatchSnapshot()
|
||||
@ -61,7 +54,7 @@ describe('pds like views', () => {
|
||||
it('fetches reply likes', async () => {
|
||||
const bobReply = await agent.api.app.bsky.feed.getLikes(
|
||||
{ uri: sc.replies[bob][0].ref.uriStr },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(bobReply.data)).toMatchSnapshot()
|
||||
@ -79,7 +72,7 @@ describe('pds like views', () => {
|
||||
cursor,
|
||||
limit: 2,
|
||||
},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
@ -91,7 +84,7 @@ describe('pds like views', () => {
|
||||
|
||||
const full = await agent.api.app.bsky.feed.getLikes(
|
||||
{ uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(full.data.likes.length).toEqual(4)
|
||||
@ -101,7 +94,7 @@ describe('pds like views', () => {
|
||||
it('fetches post likes unauthed', async () => {
|
||||
const { data: authed } = await agent.api.app.bsky.feed.getLikes(
|
||||
{ uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.feed.getLikes({
|
||||
uri: sc.posts[alice][1].ref.uriStr,
|
||||
|
@ -1,19 +1,13 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
|
||||
import {
|
||||
adminAuth,
|
||||
appViewHeaders,
|
||||
forSnapshot,
|
||||
paginateAll,
|
||||
processAll,
|
||||
} from '../_util'
|
||||
import { forSnapshot, paginateAll } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
import { Notification } from '../../src/lexicon/types/app/bsky/notification/listNotifications'
|
||||
|
||||
describe('notification views', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
@ -21,20 +15,20 @@ describe('notification views', () => {
|
||||
let alice: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_notifications',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await testEnv.bsky.ctx.labeler.processAll()
|
||||
await network.processAll()
|
||||
await network.bsky.ctx.labeler.processAll()
|
||||
alice = sc.dids.alice
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
const sort = (notifs: Notification[]) => {
|
||||
@ -59,14 +53,14 @@ describe('notification views', () => {
|
||||
const notifCountAlice =
|
||||
await agent.api.app.bsky.notification.getUnreadCount(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(notifCountAlice.data.count).toBe(11)
|
||||
|
||||
const notifCountBob = await agent.api.app.bsky.notification.getUnreadCount(
|
||||
{},
|
||||
{ headers: await appViewHeaders(sc.dids.bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.bob) },
|
||||
)
|
||||
|
||||
expect(notifCountBob.data.count).toBe(4)
|
||||
@ -81,19 +75,19 @@ describe('notification views', () => {
|
||||
sc.replies[alice][0].ref,
|
||||
'indeed',
|
||||
)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const notifCountAlice =
|
||||
await agent.api.app.bsky.notification.getUnreadCount(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(notifCountAlice.data.count).toBe(12)
|
||||
|
||||
const notifCountBob = await agent.api.app.bsky.notification.getUnreadCount(
|
||||
{},
|
||||
{ headers: await appViewHeaders(sc.dids.bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.bob) },
|
||||
)
|
||||
|
||||
expect(notifCountBob.data.count).toBe(5)
|
||||
@ -104,11 +98,11 @@ describe('notification views', () => {
|
||||
const first = await sc.reply(sc.dids.bob, root.ref, root.ref, 'first')
|
||||
await sc.deletePost(sc.dids.alice, root.ref.uri)
|
||||
const second = await sc.reply(sc.dids.carol, root.ref, first.ref, 'second')
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const notifsAlice = await agent.api.app.bsky.notification.listNotifications(
|
||||
{},
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
const hasNotif = notifsAlice.data.notifications.some(
|
||||
(notif) => notif.uri === second.ref.uriStr,
|
||||
@ -118,14 +112,14 @@ describe('notification views', () => {
|
||||
// cleanup
|
||||
await sc.deletePost(sc.dids.bob, first.ref.uri)
|
||||
await sc.deletePost(sc.dids.carol, second.ref.uri)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
})
|
||||
|
||||
it('generates notifications for quotes', async () => {
|
||||
// Dan was quoted by alice
|
||||
const notifsDan = await agent.api.app.bsky.notification.listNotifications(
|
||||
{},
|
||||
{ headers: await appViewHeaders(sc.dids.dan, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.dan) },
|
||||
)
|
||||
expect(forSnapshot(sort(notifsDan.data.notifications))).toMatchSnapshot()
|
||||
})
|
||||
@ -133,7 +127,7 @@ describe('notification views', () => {
|
||||
it('fetches notifications without a last-seen', async () => {
|
||||
const notifRes = await agent.api.app.bsky.notification.listNotifications(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
const notifs = notifRes.data.notifications
|
||||
@ -151,7 +145,7 @@ describe('notification views', () => {
|
||||
const paginator = async (cursor?: string) => {
|
||||
const res = await agent.api.app.bsky.notification.listNotifications(
|
||||
{ cursor, limit: 6 },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
@ -163,7 +157,7 @@ describe('notification views', () => {
|
||||
|
||||
const full = await agent.api.app.bsky.notification.listNotifications(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(full.data.notifications.length).toEqual(12)
|
||||
@ -173,12 +167,12 @@ describe('notification views', () => {
|
||||
it('fetches notification count with a last-seen', async () => {
|
||||
const full = await agent.api.app.bsky.notification.listNotifications(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const seenAt = full.data.notifications[3].indexedAt
|
||||
const notifCount = await agent.api.app.bsky.notification.getUnreadCount(
|
||||
{ seenAt },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(notifCount.data.count).toBe(
|
||||
@ -190,12 +184,12 @@ describe('notification views', () => {
|
||||
it('fetches notifications with a last-seen', async () => {
|
||||
const full = await agent.api.app.bsky.notification.listNotifications(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const seenAt = full.data.notifications[3].indexedAt
|
||||
const notifRes = await agent.api.app.bsky.notification.listNotifications(
|
||||
{ seenAt },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
const notifs = notifRes.data.notifications
|
||||
@ -223,7 +217,7 @@ describe('notification views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -231,11 +225,11 @@ describe('notification views', () => {
|
||||
|
||||
const notifRes = await agent.api.app.bsky.notification.listNotifications(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const notifCount = await agent.api.app.bsky.notification.getUnreadCount(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
const notifs = sort(notifRes.data.notifications)
|
||||
@ -254,7 +248,7 @@ describe('notification views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -1,11 +1,10 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
import { appViewHeaders, processAll } from '../_util'
|
||||
|
||||
describe('popular views', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
@ -23,11 +22,11 @@ describe('popular views', () => {
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_popular',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await sc.createAccount('eve', {
|
||||
@ -42,7 +41,7 @@ describe('popular views', () => {
|
||||
handle: 'frank.test',
|
||||
password: 'frank-pass',
|
||||
})
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
carol = sc.dids.carol
|
||||
@ -52,7 +51,7 @@ describe('popular views', () => {
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('returns well liked posts', async () => {
|
||||
@ -79,11 +78,11 @@ describe('popular views', () => {
|
||||
await sc.like(dan, three.ref)
|
||||
await sc.like(eve, three.ref)
|
||||
await sc.like(frank, three.ref)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const res = await agent.api.app.bsky.unspecced.getPopular(
|
||||
{},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const feedUris = res.data.feed.map((i) => i.post.uri).sort()
|
||||
const expected = [one.ref.uriStr, two.ref.uriStr, three.ref.uriStr].sort()
|
||||
|
@ -1,32 +1,27 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import {
|
||||
appViewHeaders,
|
||||
forSnapshot,
|
||||
processAll,
|
||||
stripViewerFromPost,
|
||||
} from '../_util'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, stripViewerFromPost } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('pds posts views', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_posts',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches posts', async () => {
|
||||
@ -40,7 +35,7 @@ describe('pds posts views', () => {
|
||||
]
|
||||
const posts = await agent.api.app.bsky.feed.getPosts(
|
||||
{ uris },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
|
||||
expect(posts.data.posts.length).toBe(uris.length)
|
||||
@ -59,7 +54,7 @@ describe('pds posts views', () => {
|
||||
|
||||
const authed = await agent.api.app.bsky.feed.getPosts(
|
||||
{ uris },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
const unauthed = await agent.api.app.bsky.feed.getPosts({
|
||||
uris,
|
||||
|
@ -1,20 +1,14 @@
|
||||
import fs from 'fs/promises'
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
|
||||
import {
|
||||
adminAuth,
|
||||
appViewHeaders,
|
||||
forSnapshot,
|
||||
processAll,
|
||||
stripViewer,
|
||||
} from '../_util'
|
||||
import { forSnapshot, stripViewer } from '../_util'
|
||||
import { ids } from '../../src/lexicon/lexicons'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('pds profile views', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let pdsAgent: AtpAgent
|
||||
let sc: SeedClient
|
||||
@ -25,21 +19,21 @@ describe('pds profile views', () => {
|
||||
let dan: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_profile',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
dan = sc.dids.dan
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
// @TODO(bsky) blocked by actor takedown via labels.
|
||||
@ -47,7 +41,7 @@ describe('pds profile views', () => {
|
||||
it('fetches own profile', async () => {
|
||||
const aliceForAlice = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(aliceForAlice.data)).toMatchSnapshot()
|
||||
@ -56,7 +50,7 @@ describe('pds profile views', () => {
|
||||
it("fetches other's profile, with a follow", async () => {
|
||||
const aliceForBob = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(aliceForBob.data)).toMatchSnapshot()
|
||||
@ -65,7 +59,7 @@ describe('pds profile views', () => {
|
||||
it("fetches other's profile, without a follow", async () => {
|
||||
const danForBob = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: dan },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(danForBob.data)).toMatchSnapshot()
|
||||
@ -85,7 +79,7 @@ describe('pds profile views', () => {
|
||||
'missing.test',
|
||||
],
|
||||
},
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(profiles.map((p) => p.handle)).toEqual([
|
||||
@ -126,11 +120,11 @@ describe('pds profile views', () => {
|
||||
avatar: avatarRes.data.blob,
|
||||
banner: bannerRes.data.blob,
|
||||
})
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const aliceForAlice = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(aliceForAlice.data)).toMatchSnapshot()
|
||||
@ -140,13 +134,13 @@ describe('pds profile views', () => {
|
||||
const byDid = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: alice },
|
||||
{
|
||||
headers: await appViewHeaders(bob, testEnv),
|
||||
headers: await network.serviceHeaders(bob),
|
||||
},
|
||||
)
|
||||
|
||||
const byHandle = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: sc.accounts[alice].handle },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(byHandle.data).toEqual(byDid.data)
|
||||
@ -155,7 +149,7 @@ describe('pds profile views', () => {
|
||||
it('fetches profile unauthed', async () => {
|
||||
const { data: authed } = await agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.actor.getProfile({
|
||||
actor: alice,
|
||||
@ -168,7 +162,7 @@ describe('pds profile views', () => {
|
||||
{
|
||||
actors: [alice, 'bob.test', 'missing.test'],
|
||||
},
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.actor.getProfiles({
|
||||
actors: [alice, 'bob.test', 'missing.test'],
|
||||
@ -191,12 +185,12 @@ describe('pds profile views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
const promise = agent.api.app.bsky.actor.getProfile(
|
||||
{ actor: alice },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
await expect(promise).rejects.toThrow('Account has been taken down')
|
||||
@ -210,7 +204,7 @@ describe('pds profile views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
@ -1,18 +1,12 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import {
|
||||
appViewHeaders,
|
||||
forSnapshot,
|
||||
paginateAll,
|
||||
processAll,
|
||||
stripViewer,
|
||||
} from '../_util'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, paginateAll, stripViewer } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import repostsSeed from '../seeds/reposts'
|
||||
|
||||
describe('pds repost views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -20,26 +14,26 @@ describe('pds repost views', () => {
|
||||
let bob: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_reposts',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await repostsSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches reposted-by for a post', async () => {
|
||||
const view = await agent.api.app.bsky.feed.getRepostedBy(
|
||||
{ uri: sc.posts[alice][2].ref.uriStr },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
expect(view.data.uri).toEqual(sc.posts[sc.dids.alice][2].ref.uriStr)
|
||||
expect(forSnapshot(view.data.repostedBy)).toMatchSnapshot()
|
||||
@ -48,7 +42,7 @@ describe('pds repost views', () => {
|
||||
it('fetches reposted-by for a reply', async () => {
|
||||
const view = await agent.api.app.bsky.feed.getRepostedBy(
|
||||
{ uri: sc.replies[bob][0].ref.uriStr },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
expect(view.data.uri).toEqual(sc.replies[sc.dids.bob][0].ref.uriStr)
|
||||
expect(forSnapshot(view.data.repostedBy)).toMatchSnapshot()
|
||||
@ -63,7 +57,7 @@ describe('pds repost views', () => {
|
||||
cursor,
|
||||
limit: 2,
|
||||
},
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
@ -75,7 +69,7 @@ describe('pds repost views', () => {
|
||||
|
||||
const full = await agent.api.app.bsky.feed.getRepostedBy(
|
||||
{ uri: sc.posts[alice][2].ref.uriStr },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(full.data.repostedBy.length).toEqual(4)
|
||||
@ -85,7 +79,7 @@ describe('pds repost views', () => {
|
||||
it('fetches reposted-by unauthed', async () => {
|
||||
const { data: authed } = await agent.api.app.bsky.feed.getRepostedBy(
|
||||
{ uri: sc.posts[alice][2].ref.uriStr },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.feed.getRepostedBy({
|
||||
uri: sc.posts[alice][2].ref.uriStr,
|
||||
|
@ -1,33 +1,33 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import { appViewHeaders, processAll, stripViewer } from '../_util'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { stripViewer } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('pds user search views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let sc: SeedClient
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_suggestions',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('actor suggestion gives users', async () => {
|
||||
const result = await agent.api.app.bsky.actor.getSuggestions(
|
||||
{ limit: 3 },
|
||||
{ headers: await appViewHeaders(sc.dids.carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.carol) },
|
||||
)
|
||||
|
||||
const handles = result.data.actors.map((u) => u.handle)
|
||||
@ -49,7 +49,7 @@ describe('pds user search views', () => {
|
||||
it('does not suggest followed users', async () => {
|
||||
const result = await agent.api.app.bsky.actor.getSuggestions(
|
||||
{ limit: 3 },
|
||||
{ headers: await appViewHeaders(sc.dids.alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.alice) },
|
||||
)
|
||||
|
||||
// alice follows everyone
|
||||
@ -59,11 +59,11 @@ describe('pds user search views', () => {
|
||||
it('paginates', async () => {
|
||||
const result1 = await agent.api.app.bsky.actor.getSuggestions(
|
||||
{ limit: 1 },
|
||||
{ headers: await appViewHeaders(sc.dids.carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.carol) },
|
||||
)
|
||||
const result2 = await agent.api.app.bsky.actor.getSuggestions(
|
||||
{ limit: 1, cursor: result1.data.cursor },
|
||||
{ headers: await appViewHeaders(sc.dids.carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.carol) },
|
||||
)
|
||||
|
||||
expect(result1.data.actors.length).toBe(1)
|
||||
@ -78,7 +78,7 @@ describe('pds user search views', () => {
|
||||
it('fetches suggestions unauthed', async () => {
|
||||
const { data: authed } = await agent.api.app.bsky.actor.getSuggestions(
|
||||
{},
|
||||
{ headers: await appViewHeaders(sc.dids.carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(sc.dids.carol) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.actor.getSuggestions({})
|
||||
const omitViewerFollows = ({ did }) => {
|
||||
|
@ -1,20 +1,14 @@
|
||||
import AtpAgent, { AppBskyFeedGetPostThread } from '@atproto/api'
|
||||
import { runTestEnv, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
|
||||
import { Database } from '../../src'
|
||||
import {
|
||||
adminAuth,
|
||||
appViewHeaders,
|
||||
forSnapshot,
|
||||
processAll,
|
||||
stripViewerFromThread,
|
||||
} from '../_util'
|
||||
import { forSnapshot, stripViewerFromThread } from '../_util'
|
||||
import { RecordRef, SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
import threadSeed, { walk, item, Item } from '../seeds/thread'
|
||||
|
||||
describe('pds thread views', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let db: Database
|
||||
let sc: SeedClient
|
||||
@ -25,12 +19,12 @@ describe('pds thread views', () => {
|
||||
let carol: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_thread',
|
||||
})
|
||||
db = testEnv.bsky.ctx.db
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
db = network.bsky.ctx.db
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
alice = sc.dids.alice
|
||||
@ -41,18 +35,18 @@ describe('pds thread views', () => {
|
||||
beforeAll(async () => {
|
||||
// Add a repost of a reply so that we can confirm myState in the thread
|
||||
await sc.repost(bob, sc.replies[alice][0].ref)
|
||||
await processAll(testEnv)
|
||||
await testEnv.bsky.ctx.labeler.processAll()
|
||||
await network.processAll()
|
||||
await network.bsky.ctx.labeler.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches deep post thread', async () => {
|
||||
const thread = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(thread.data.thread)).toMatchSnapshot()
|
||||
@ -61,7 +55,7 @@ describe('pds thread views', () => {
|
||||
it('fetches shallow post thread', async () => {
|
||||
const thread = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ depth: 1, uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(thread.data.thread)).toMatchSnapshot()
|
||||
@ -70,7 +64,7 @@ describe('pds thread views', () => {
|
||||
it('fetches ancestors', async () => {
|
||||
const thread = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ depth: 1, uri: sc.replies[alice][0].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(thread.data.thread)).toMatchSnapshot()
|
||||
@ -79,7 +73,7 @@ describe('pds thread views', () => {
|
||||
it('fails for an unknown post', async () => {
|
||||
const promise = agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: 'at://did:example:fake/does.not.exist/self' },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
await expect(promise).rejects.toThrow(
|
||||
@ -90,7 +84,7 @@ describe('pds thread views', () => {
|
||||
it('fetches post thread unauthed', async () => {
|
||||
const { data: authed } = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
const { data: unauthed } = await agent.api.app.bsky.feed.getPostThread({
|
||||
uri: sc.posts[alice][1].ref.uriStr,
|
||||
@ -125,26 +119,26 @@ describe('pds thread views', () => {
|
||||
'Reply reply',
|
||||
)
|
||||
indexes.aliceReplyReply = sc.replies[alice].length - 1
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const thread1 = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][indexes.aliceRoot].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
expect(forSnapshot(thread1.data.thread)).toMatchSnapshot()
|
||||
|
||||
await sc.deletePost(bob, sc.replies[bob][indexes.bobReply].ref.uri)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const thread2 = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][indexes.aliceRoot].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
expect(forSnapshot(thread2.data.thread)).toMatchSnapshot()
|
||||
|
||||
const thread3 = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.replies[alice][indexes.aliceReplyReply].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
expect(forSnapshot(thread3.data.thread)).toMatchSnapshot()
|
||||
})
|
||||
@ -157,7 +151,7 @@ describe('pds thread views', () => {
|
||||
]
|
||||
|
||||
await threadSeed(sc, sc.dids.alice, threads)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
let closureSize = 0
|
||||
const itemByUri: Record<string, Item> = {}
|
||||
@ -222,14 +216,14 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
// Same as shallow post thread test, minus alice
|
||||
const promise = agent.api.app.bsky.feed.getPostThread(
|
||||
{ depth: 1, uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
await expect(promise).rejects.toThrow(
|
||||
@ -245,7 +239,7 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -264,14 +258,14 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
// Same as deep post thread test, minus carol
|
||||
const thread = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(thread.data.thread)).toMatchSnapshot()
|
||||
@ -285,7 +279,7 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -304,14 +298,14 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
// Same as ancestor post thread test, minus bob
|
||||
const thread = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ depth: 1, uri: sc.replies[alice][0].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(thread.data.thread)).toMatchSnapshot()
|
||||
@ -325,7 +319,7 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -346,13 +340,13 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
const promise = agent.api.app.bsky.feed.getPostThread(
|
||||
{ depth: 1, uri: postRef.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
await expect(promise).rejects.toThrow(
|
||||
@ -368,7 +362,7 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -376,7 +370,7 @@ describe('pds thread views', () => {
|
||||
it('blocks ancestors by record', async () => {
|
||||
const threadPreTakedown = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ depth: 1, uri: sc.replies[alice][0].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
const parent = threadPreTakedown.data.thread.parent?.['post']
|
||||
@ -395,14 +389,14 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
|
||||
// Same as ancestor post thread test, minus parent post
|
||||
const thread = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ depth: 1, uri: sc.replies[alice][0].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(thread.data.thread)).toMatchSnapshot()
|
||||
@ -416,7 +410,7 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -424,7 +418,7 @@ describe('pds thread views', () => {
|
||||
it('blocks replies by record', async () => {
|
||||
const threadPreTakedown = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
const post1 = threadPreTakedown.data.thread.replies?.[0].post
|
||||
const post2 = threadPreTakedown.data.thread.replies?.[1].replies[0].post
|
||||
@ -444,7 +438,7 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -453,7 +447,7 @@ describe('pds thread views', () => {
|
||||
// Same as deep post thread test, minus some replies
|
||||
const thread = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][1].ref.uriStr },
|
||||
{ headers: await appViewHeaders(bob, testEnv) },
|
||||
{ headers: await network.serviceHeaders(bob) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(thread.data.thread)).toMatchSnapshot()
|
||||
@ -469,7 +463,7 @@ describe('pds thread views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -1,22 +1,15 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, runTestEnv } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
|
||||
import {
|
||||
adminAuth,
|
||||
appViewHeaders,
|
||||
forSnapshot,
|
||||
getOriginator,
|
||||
paginateAll,
|
||||
processAll,
|
||||
} from '../_util'
|
||||
import { forSnapshot, getOriginator, paginateAll } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
import { FeedAlgorithm } from '../../src/api/app/bsky/util/feed'
|
||||
import { FeedViewPost } from '../../src/lexicon/types/app/bsky/feed/defs'
|
||||
|
||||
describe('timeline views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -26,15 +19,15 @@ describe('timeline views', () => {
|
||||
let dan: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_home_feed',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.bsky.url })
|
||||
const pdsAgent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.bsky.getClient()
|
||||
const pdsAgent = network.pds.getClient()
|
||||
sc = new SeedClient(pdsAgent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await testEnv.bsky.ctx.labeler.processAll()
|
||||
await network.processAll()
|
||||
await network.bsky.ctx.labeler.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
carol = sc.dids.carol
|
||||
@ -42,27 +35,27 @@ describe('timeline views', () => {
|
||||
// Label posts as "kind" to check labels on embed views
|
||||
const labelPostA = sc.posts[bob][0].ref
|
||||
const labelPostB = sc.posts[carol][0].ref
|
||||
await testEnv.bsky.ctx.services
|
||||
.label(testEnv.bsky.ctx.db)
|
||||
await network.bsky.ctx.services
|
||||
.label(network.bsky.ctx.db)
|
||||
.formatAndCreate(
|
||||
testEnv.bsky.ctx.cfg.labelerDid,
|
||||
network.bsky.ctx.cfg.labelerDid,
|
||||
labelPostA.uriStr,
|
||||
labelPostA.cidStr,
|
||||
{ create: ['kind'] },
|
||||
)
|
||||
await testEnv.bsky.ctx.services
|
||||
.label(testEnv.bsky.ctx.db)
|
||||
await network.bsky.ctx.services
|
||||
.label(network.bsky.ctx.db)
|
||||
.formatAndCreate(
|
||||
testEnv.bsky.ctx.cfg.labelerDid,
|
||||
network.bsky.ctx.cfg.labelerDid,
|
||||
labelPostB.uriStr,
|
||||
labelPostB.cidStr,
|
||||
{ create: ['kind'] },
|
||||
)
|
||||
await testEnv.bsky.ctx.labeler.processAll()
|
||||
await network.bsky.ctx.labeler.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
// @TODO(bsky) blocks posts, reposts, replies by actor takedown via labels
|
||||
@ -80,7 +73,7 @@ describe('timeline views', () => {
|
||||
const aliceTL = await agent.api.app.bsky.feed.getTimeline(
|
||||
{ algorithm: FeedAlgorithm.ReverseChronological },
|
||||
{
|
||||
headers: await appViewHeaders(alice, testEnv),
|
||||
headers: await network.serviceHeaders(alice),
|
||||
},
|
||||
)
|
||||
|
||||
@ -90,7 +83,7 @@ describe('timeline views', () => {
|
||||
const bobTL = await agent.api.app.bsky.feed.getTimeline(
|
||||
{ algorithm: FeedAlgorithm.ReverseChronological },
|
||||
{
|
||||
headers: await appViewHeaders(bob, testEnv),
|
||||
headers: await network.serviceHeaders(bob),
|
||||
},
|
||||
)
|
||||
|
||||
@ -100,7 +93,7 @@ describe('timeline views', () => {
|
||||
const carolTL = await agent.api.app.bsky.feed.getTimeline(
|
||||
{ algorithm: FeedAlgorithm.ReverseChronological },
|
||||
{
|
||||
headers: await appViewHeaders(carol, testEnv),
|
||||
headers: await network.serviceHeaders(carol),
|
||||
},
|
||||
)
|
||||
|
||||
@ -110,7 +103,7 @@ describe('timeline views', () => {
|
||||
const danTL = await agent.api.app.bsky.feed.getTimeline(
|
||||
{ algorithm: FeedAlgorithm.ReverseChronological },
|
||||
{
|
||||
headers: await appViewHeaders(dan, testEnv),
|
||||
headers: await network.serviceHeaders(dan),
|
||||
},
|
||||
)
|
||||
|
||||
@ -122,13 +115,13 @@ describe('timeline views', () => {
|
||||
const defaultTL = await agent.api.app.bsky.feed.getTimeline(
|
||||
{},
|
||||
{
|
||||
headers: await appViewHeaders(alice, testEnv),
|
||||
headers: await network.serviceHeaders(alice),
|
||||
},
|
||||
)
|
||||
const reverseChronologicalTL = await agent.api.app.bsky.feed.getTimeline(
|
||||
{ algorithm: FeedAlgorithm.ReverseChronological },
|
||||
{
|
||||
headers: await appViewHeaders(alice, testEnv),
|
||||
headers: await network.serviceHeaders(alice),
|
||||
},
|
||||
)
|
||||
expect(defaultTL.data.feed).toEqual(reverseChronologicalTL.data.feed)
|
||||
@ -143,7 +136,7 @@ describe('timeline views', () => {
|
||||
cursor,
|
||||
limit: 4,
|
||||
},
|
||||
{ headers: await appViewHeaders(carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(carol) },
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
@ -157,7 +150,7 @@ describe('timeline views', () => {
|
||||
{
|
||||
algorithm: FeedAlgorithm.ReverseChronological,
|
||||
},
|
||||
{ headers: await appViewHeaders(carol, testEnv) },
|
||||
{ headers: await network.serviceHeaders(carol) },
|
||||
)
|
||||
|
||||
expect(full.data.feed.length).toEqual(7)
|
||||
@ -179,7 +172,7 @@ describe('timeline views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -187,7 +180,7 @@ describe('timeline views', () => {
|
||||
|
||||
const aliceTL = await agent.api.app.bsky.feed.getTimeline(
|
||||
{ algorithm: FeedAlgorithm.ReverseChronological },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(aliceTL.data.feed)).toMatchSnapshot()
|
||||
@ -203,7 +196,7 @@ describe('timeline views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -228,7 +221,7 @@ describe('timeline views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
),
|
||||
),
|
||||
@ -236,7 +229,7 @@ describe('timeline views', () => {
|
||||
|
||||
const aliceTL = await agent.api.app.bsky.feed.getTimeline(
|
||||
{ algorithm: FeedAlgorithm.ReverseChronological },
|
||||
{ headers: await appViewHeaders(alice, testEnv) },
|
||||
{ headers: await network.serviceHeaders(alice) },
|
||||
)
|
||||
|
||||
expect(forSnapshot(aliceTL.data.feed)).toMatchSnapshot()
|
||||
@ -252,7 +245,7 @@ describe('timeline views', () => {
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: { authorization: adminAuth() },
|
||||
headers: network.pds.adminAuthHeaders(),
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -3,7 +3,7 @@ const { copy } = require('esbuild-plugin-copy')
|
||||
require('esbuild')
|
||||
.build({
|
||||
logLevel: 'info',
|
||||
entryPoints: ['src/index.ts', 'src/cli.ts'],
|
||||
entryPoints: ['src/index.ts', 'src/bin.ts'],
|
||||
bundle: true,
|
||||
sourcemap: true,
|
||||
outdir: 'dist',
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@atproto/dev-env",
|
||||
"version": "0.1.0",
|
||||
"main": "src/test-env.ts",
|
||||
"bin": "dist/cli.js",
|
||||
"main": "src/index.ts",
|
||||
"bin": "dist/bin.js",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"build": "node ./build.js",
|
||||
"postbuild": "tsc --build tsconfig.build.json",
|
||||
"start": "node dist/cli.js",
|
||||
"start": "node dist/bin.js",
|
||||
"prettier": "prettier --check src/",
|
||||
"prettier:fix": "prettier --write src/",
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
@ -27,13 +27,15 @@
|
||||
"@atproto/did-resolver": "*",
|
||||
"@atproto/pds": "*",
|
||||
"@atproto/uri": "*",
|
||||
"@atproto/xrpc-server": "*",
|
||||
"@did-plc/lib": "^0.0.1",
|
||||
"@did-plc/server": "^0.0.1",
|
||||
"better-sqlite3": "^7.6.2",
|
||||
"chalk": "^5.0.1",
|
||||
"dotenv": "^16.0.1",
|
||||
"get-port": "^6.1.2",
|
||||
"sharp": "^0.31.2"
|
||||
"sharp": "^0.31.2",
|
||||
"uint8arrays": "3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ts-node": "^10.8.1"
|
||||
|
29
packages/dev-env/src/bin.ts
Normal file
29
packages/dev-env/src/bin.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { generateMockSetup } from './mock'
|
||||
import { TestNetworkNoAppView } from './network-no-appview'
|
||||
|
||||
const run = async () => {
|
||||
console.log(`
|
||||
██████╗
|
||||
██╔═══██╗
|
||||
██║██╗██║
|
||||
██║██║██║
|
||||
╚█║████╔╝
|
||||
╚╝╚═══╝ protocol
|
||||
|
||||
[ created by Bluesky ]`)
|
||||
|
||||
const network = await TestNetworkNoAppView.create({
|
||||
pds: { port: 2583 },
|
||||
plc: { port: 2582 },
|
||||
})
|
||||
await generateMockSetup(network)
|
||||
|
||||
console.log(
|
||||
`👤 DID Placeholder server started http://localhost:${network.plc.port}`,
|
||||
)
|
||||
console.log(
|
||||
`🌞 Personal Data server started http://localhost:${network.pds.port}`,
|
||||
)
|
||||
}
|
||||
|
||||
run()
|
98
packages/dev-env/src/bsky.ts
Normal file
98
packages/dev-env/src/bsky.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import getPort from 'get-port'
|
||||
import * as bsky from '@atproto/bsky'
|
||||
import { DAY, HOUR } from '@atproto/common-web'
|
||||
import { AtpAgent } from '@atproto/api'
|
||||
import { Secp256k1Keypair } from '@atproto/crypto'
|
||||
import { Client as PlcClient } from '@did-plc/lib'
|
||||
import { BskyConfig } from './types'
|
||||
|
||||
export class TestBsky {
|
||||
constructor(
|
||||
public url: string,
|
||||
public port: number,
|
||||
public server: bsky.BskyAppView,
|
||||
) {}
|
||||
|
||||
static async create(cfg: BskyConfig): Promise<TestBsky> {
|
||||
const serviceKeypair = await Secp256k1Keypair.create()
|
||||
const plcClient = new PlcClient(cfg.plcUrl)
|
||||
|
||||
const port = cfg.port || (await getPort())
|
||||
const url = `http://localhost:${port}`
|
||||
const serverDid = await plcClient.createDid({
|
||||
signingKey: serviceKeypair.did(),
|
||||
rotationKeys: [serviceKeypair.did()],
|
||||
handle: 'bsky.test',
|
||||
pds: `http://localhost:${port}`,
|
||||
signer: serviceKeypair,
|
||||
})
|
||||
const config = new bsky.ServerConfig({
|
||||
version: '0.0.0',
|
||||
port,
|
||||
didPlcUrl: cfg.plcUrl,
|
||||
publicUrl: 'https://bsky.public.url',
|
||||
serverDid,
|
||||
imgUriSalt: '9dd04221f5755bce5f55f47464c27e1e',
|
||||
imgUriKey:
|
||||
'f23ecd142835025f42c3db2cf25dd813956c178392760256211f9d315f8ab4d8',
|
||||
didCacheStaleTTL: HOUR,
|
||||
didCacheMaxTTL: DAY,
|
||||
...cfg,
|
||||
// Each test suite gets its own lock id for the repo subscription
|
||||
repoSubLockId: uniqueLockId(),
|
||||
adminPassword: 'admin-pass',
|
||||
labelerDid: 'did:example:labeler',
|
||||
labelerKeywords: { label_me: 'test-label', label_me_2: 'test-label-2' },
|
||||
})
|
||||
|
||||
const db = bsky.Database.postgres({
|
||||
url: cfg.dbPostgresUrl,
|
||||
schema: cfg.dbPostgresSchema,
|
||||
})
|
||||
|
||||
// Separate migration db in case migration changes some connection state that we need in the tests, e.g. "alter database ... set ..."
|
||||
const migrationDb = bsky.Database.postgres({
|
||||
url: cfg.dbPostgresUrl,
|
||||
schema: cfg.dbPostgresSchema,
|
||||
})
|
||||
if (cfg.migration) {
|
||||
await migrationDb.migrateToOrThrow(cfg.migration)
|
||||
} else {
|
||||
await migrationDb.migrateToLatestOrThrow()
|
||||
}
|
||||
await migrationDb.close()
|
||||
|
||||
const server = bsky.BskyAppView.create({ db, config })
|
||||
await server.start()
|
||||
return new TestBsky(url, port, server)
|
||||
}
|
||||
|
||||
get ctx(): bsky.AppContext {
|
||||
return this.server.ctx
|
||||
}
|
||||
|
||||
get sub() {
|
||||
if (!this.server.sub) {
|
||||
throw new Error('No subscription on dev-env server')
|
||||
}
|
||||
return this.server.sub
|
||||
}
|
||||
|
||||
getClient() {
|
||||
return new AtpAgent({ service: this.url })
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.server.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
const usedLockIds = new Set()
|
||||
const uniqueLockId = () => {
|
||||
let lockId: number
|
||||
do {
|
||||
lockId = 1000 + Math.ceil(1000 * Math.random())
|
||||
} while (usedLockIds.has(lockId))
|
||||
usedLockIds.add(lockId)
|
||||
return lockId
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
import assert from 'assert'
|
||||
import repl from 'repl'
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import { join } from 'path'
|
||||
import chalk from 'chalk'
|
||||
import { DevEnv, DevEnvServer } from './index.js'
|
||||
import * as env from './env.js'
|
||||
import { ServerType } from './types.js'
|
||||
import { genServerCfg } from './util'
|
||||
import { generateMockSetup } from './mock'
|
||||
|
||||
const pkg = JSON.parse(
|
||||
fs.readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'),
|
||||
)
|
||||
|
||||
let devEnv: DevEnv | undefined
|
||||
const users: Map<string, DevEnvServer> = new Map()
|
||||
|
||||
// commands
|
||||
// =
|
||||
|
||||
const envApi = {
|
||||
get env() {
|
||||
return devEnv
|
||||
},
|
||||
|
||||
get api() {
|
||||
const client = devEnv
|
||||
?.listOfType(ServerType.PersonalDataServer)[0]
|
||||
.getClient()
|
||||
if (!client) {
|
||||
throw new Error('No PDS is active')
|
||||
}
|
||||
return client
|
||||
},
|
||||
|
||||
status() {
|
||||
assert(devEnv)
|
||||
console.log(chalk.bold(' port server'))
|
||||
for (const server of devEnv.servers.values()) {
|
||||
console.log(`${server.description} ${chalk.gray(server.url)}`)
|
||||
}
|
||||
},
|
||||
|
||||
async startPds(port?: number) {
|
||||
assert(devEnv)
|
||||
await devEnv.add(await genServerCfg(ServerType.PersonalDataServer, port))
|
||||
},
|
||||
|
||||
async startBsky(port?: number) {
|
||||
assert(devEnv)
|
||||
await devEnv.add(await genServerCfg(ServerType.BskyAppView, port))
|
||||
},
|
||||
|
||||
async stop(port: number) {
|
||||
assert(devEnv)
|
||||
const inst = devEnv.servers.get(port)
|
||||
if (!inst) {
|
||||
console.error('No server found at port', port)
|
||||
} else {
|
||||
await devEnv.remove(inst)
|
||||
}
|
||||
},
|
||||
|
||||
async mkuser(handle: string, serverPort?: number) {
|
||||
assert(devEnv)
|
||||
assert(handle && typeof handle === 'string', 'Handle is required')
|
||||
|
||||
if (!handle.endsWith('.test')) {
|
||||
handle += '.test'
|
||||
}
|
||||
if (users.has(handle)) {
|
||||
throw new Error(`${handle} already exists`)
|
||||
}
|
||||
const handleNoTld = handle.slice(0, handle.length - '.test'.length)
|
||||
|
||||
const servers = devEnv.listOfType(ServerType.PersonalDataServer)
|
||||
let pds: DevEnvServer
|
||||
if (!serverPort) {
|
||||
if (servers.length > 0) {
|
||||
pds = servers[0]
|
||||
} else {
|
||||
throw new Error('Start a PDS first')
|
||||
}
|
||||
} else {
|
||||
const inst = servers.find((s) => s.port === serverPort)
|
||||
if (!inst) throw new Error(`No PDS running on port ${serverPort}`)
|
||||
pds = inst
|
||||
}
|
||||
|
||||
console.log(`Creating ${handle} on ${pds.description}`)
|
||||
|
||||
// create the PDS account
|
||||
const client = pds.getClient()
|
||||
const pdsRes = await client.api.com.atproto.server.createAccount({
|
||||
email: handleNoTld + '@test.com',
|
||||
handle,
|
||||
password: handleNoTld + '-pass',
|
||||
})
|
||||
users.set(handle, pds)
|
||||
},
|
||||
|
||||
user(handle: string) {
|
||||
const pds = users.get(handle)
|
||||
if (!pds) throw new Error('User not found')
|
||||
return pds.getClient()
|
||||
},
|
||||
}
|
||||
|
||||
// start
|
||||
// =
|
||||
|
||||
console.log(`
|
||||
██████╗
|
||||
██╔═══██╗
|
||||
██║██╗██║
|
||||
██║██║██║
|
||||
╚█║████╔╝
|
||||
╚╝╚═══╝ protocol
|
||||
|
||||
[ v${pkg.version} | created by Bluesky ]
|
||||
|
||||
Initializing...`)
|
||||
async function start() {
|
||||
devEnv = await DevEnv.create(env.load())
|
||||
await generateMockSetup(devEnv)
|
||||
console.log('Test environment generated.')
|
||||
console.log('Type .help if you get lost')
|
||||
|
||||
// create repl
|
||||
const inst = repl.start() //'atp $ ')
|
||||
Object.assign(inst.context, envApi)
|
||||
inst.setupHistory(join(os.homedir(), '.atp-dev-env-history'), () => {})
|
||||
inst.on('exit', async () => {
|
||||
console.log(`Shutting down...`)
|
||||
await devEnv?.shutdown()
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
return inst
|
||||
}
|
||||
start()
|
@ -1,22 +0,0 @@
|
||||
import dotenv from 'dotenv'
|
||||
import { StartParams, ServerType, ServerConfig } from './types.js'
|
||||
|
||||
const getPorts = (type: ServerType, name: string): ServerConfig[] => {
|
||||
const portsStr = process.env[name]
|
||||
if (!portsStr) return []
|
||||
return portsStr
|
||||
.split(',')
|
||||
.map((str) => parseInt(str))
|
||||
.filter(Boolean)
|
||||
.map((port) => ({ type, port }))
|
||||
}
|
||||
|
||||
export function load(): StartParams {
|
||||
dotenv.config()
|
||||
|
||||
return {
|
||||
servers: [
|
||||
...getPorts(ServerType.PersonalDataServer, 'PERSONAL_DATA_SERVERS'),
|
||||
],
|
||||
}
|
||||
}
|
@ -1,273 +1,7 @@
|
||||
import http from 'http'
|
||||
import chalk from 'chalk'
|
||||
import crytpo from 'crypto'
|
||||
import PDSServer, {
|
||||
Database as PDSDatabase,
|
||||
MemoryBlobStore,
|
||||
ServerConfig as PDSServerConfig,
|
||||
AppContext as PDSContext,
|
||||
} from '@atproto/pds'
|
||||
import * as bsky from '@atproto/bsky'
|
||||
import * as plc from '@did-plc/lib'
|
||||
import { PlcServer, Database as PlcDatabase } from '@did-plc/server'
|
||||
import * as crypto from '@atproto/crypto'
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { ServerType, ServerConfig, StartParams, PORTS } from './types.js'
|
||||
import { DAY, HOUR } from '@atproto/common'
|
||||
import { mockNetworkUtilities } from './test-env'
|
||||
|
||||
export * from './test-env'
|
||||
|
||||
interface Startable {
|
||||
start(): Promise<http.Server>
|
||||
}
|
||||
|
||||
interface Destroyable {
|
||||
destroy(): Promise<void>
|
||||
}
|
||||
|
||||
export class DevEnvServer {
|
||||
inst?: Destroyable
|
||||
|
||||
constructor(
|
||||
private env: DevEnv,
|
||||
public type: ServerType,
|
||||
public port: number,
|
||||
) {}
|
||||
|
||||
get name() {
|
||||
return {
|
||||
[ServerType.PersonalDataServer]: '🌞 Personal Data server',
|
||||
[ServerType.DidPlaceholder]: '👤 DID Placeholder server',
|
||||
[ServerType.BskyAppView]: '🌀 Bsky App View server',
|
||||
}[this.type]
|
||||
}
|
||||
|
||||
get description() {
|
||||
return `[${chalk.bold(this.port)}] ${this.name}`
|
||||
}
|
||||
|
||||
get url() {
|
||||
return `http://localhost:${this.port}`
|
||||
}
|
||||
|
||||
get ctx(): PDSContext | undefined {
|
||||
if (this.inst instanceof PDSServer) {
|
||||
return this.inst.ctx
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
if (this.inst) {
|
||||
throw new Error('Already started')
|
||||
}
|
||||
|
||||
const startServer = async (server: Startable): Promise<void> => {
|
||||
try {
|
||||
await server.start()
|
||||
console.log(`${this.description} started ${chalk.gray(this.url)}`)
|
||||
} catch (err) {
|
||||
console.log(`${this.description} failed to start:`, err)
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.type) {
|
||||
case ServerType.PersonalDataServer: {
|
||||
if (!this.env.plcUrl) {
|
||||
throw new Error('Must be running a PLC server to start a PDS')
|
||||
}
|
||||
|
||||
const db = await PDSDatabase.memory()
|
||||
await db.migrateToLatestOrThrow()
|
||||
const keypair = await crypto.EcdsaKeypair.create()
|
||||
|
||||
const blobstore = new MemoryBlobStore()
|
||||
|
||||
const plcClient = new plc.Client(this.env.plcUrl)
|
||||
const serverDid = await plcClient.createDid({
|
||||
signingKey: keypair.did(),
|
||||
rotationKeys: [keypair.did()],
|
||||
handle: 'localhost',
|
||||
pds: `http://localhost:${this.port}`,
|
||||
signer: keypair,
|
||||
})
|
||||
|
||||
const pds = PDSServer.create({
|
||||
db,
|
||||
blobstore,
|
||||
repoSigningKey: keypair,
|
||||
plcRotationKey: keypair,
|
||||
config: new PDSServerConfig({
|
||||
debugMode: true,
|
||||
version: '0.0.0',
|
||||
scheme: 'http',
|
||||
hostname: 'localhost',
|
||||
port: this.port,
|
||||
didPlcUrl: this.env.plcUrl,
|
||||
serverDid,
|
||||
recoveryKey: keypair.did(),
|
||||
jwtSecret: crytpo.randomBytes(8).toString('base64'),
|
||||
availableUserDomains: ['.test'],
|
||||
appUrlPasswordReset: 'app://password-reset',
|
||||
// @TODO setup ethereal.email creds and set emailSmtpUrl here
|
||||
emailNoReplyAddress: 'noreply@blueskyweb.xyz',
|
||||
adminPassword: 'password',
|
||||
inviteRequired: false,
|
||||
userInviteInterval: null,
|
||||
imgUriSalt: '9dd04221f5755bce5f55f47464c27e1e',
|
||||
imgUriKey:
|
||||
'f23ecd142835025f42c3db2cf25dd813956c178392760256211f9d315f8ab4d8',
|
||||
privacyPolicyUrl: 'https://example.com/privacy',
|
||||
termsOfServiceUrl: 'https://example.com/tos',
|
||||
labelerDid: 'did:example:labeler',
|
||||
labelerKeywords: {},
|
||||
maxSubscriptionBuffer: 200,
|
||||
repoBackfillLimitMs: HOUR,
|
||||
appViewRepoProvider: process.env.APP_VIEW_REPO_PROVIDER,
|
||||
}),
|
||||
})
|
||||
await startServer(pds)
|
||||
this.inst = pds
|
||||
break
|
||||
}
|
||||
case ServerType.DidPlaceholder: {
|
||||
const db = PlcDatabase.mock()
|
||||
const plcServer = PlcServer.create({ db, port: this.port })
|
||||
await startServer(plcServer)
|
||||
this.inst = plcServer
|
||||
break
|
||||
}
|
||||
case ServerType.BskyAppView: {
|
||||
if (!this.env.pdsUrl || !this.env.plcUrl) {
|
||||
throw new Error(
|
||||
'Must be running a PDS and PLC servers to start AppView',
|
||||
)
|
||||
}
|
||||
|
||||
const keypair = await crypto.Secp256k1Keypair.create()
|
||||
const plcClient = new plc.Client(this.env.plcUrl)
|
||||
const serverDid = await plcClient.createDid({
|
||||
signingKey: keypair.did(),
|
||||
rotationKeys: [keypair.did()],
|
||||
handle: 'localhost',
|
||||
pds: `http://localhost:${this.port}`,
|
||||
signer: keypair,
|
||||
})
|
||||
|
||||
const config = new bsky.ServerConfig({
|
||||
version: '0.0.0',
|
||||
serverDid,
|
||||
didPlcUrl: this.env.plcUrl,
|
||||
publicUrl: 'https://bsky.public.url',
|
||||
imgUriSalt: '9dd04221f5755bce5f55f47464c27e1e',
|
||||
imgUriKey:
|
||||
'f23ecd142835025f42c3db2cf25dd813956c178392760256211f9d315f8ab4d8',
|
||||
adminPassword: 'password',
|
||||
labelerDid: 'did:example:labeler',
|
||||
dbPostgresUrl: process.env.DB_POSTGRES_URL || '',
|
||||
dbPostgresSchema: process.env.DB_POSTGRES_SCHEMA,
|
||||
repoProvider: this.env.pdsUrl.replace('http://', 'ws://'),
|
||||
port: this.port,
|
||||
labelerKeywords: {},
|
||||
didCacheMaxTTL: DAY,
|
||||
didCacheStaleTTL: HOUR,
|
||||
})
|
||||
|
||||
const db = bsky.Database.postgres({
|
||||
url: config.dbPostgresUrl,
|
||||
schema: config.dbPostgresSchema,
|
||||
})
|
||||
|
||||
await db.migrateToLatestOrThrow()
|
||||
|
||||
const server = bsky.BskyAppView.create({ db, config })
|
||||
await startServer(server)
|
||||
this.inst = server
|
||||
break
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unsupported server type: ${this.type}`)
|
||||
}
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this.inst) {
|
||||
console.log(`Closing ${this.description}`)
|
||||
await this.inst.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
getClient(): AtpAgent {
|
||||
return new AtpAgent({ service: `http://localhost:${this.port}` })
|
||||
}
|
||||
}
|
||||
|
||||
export class DevEnv {
|
||||
plcUrl: string | undefined
|
||||
pdsUrl: string | undefined
|
||||
servers: Map<number, DevEnvServer> = new Map()
|
||||
|
||||
static async create(params: StartParams): Promise<DevEnv> {
|
||||
const devEnv = new DevEnv()
|
||||
for (const cfg of params.servers || []) {
|
||||
await devEnv.add(cfg)
|
||||
}
|
||||
return devEnv
|
||||
}
|
||||
|
||||
async add(cfg: ServerConfig) {
|
||||
if (this.servers.has(cfg.port)) {
|
||||
throw new Error(`Port ${cfg.port} is in use`)
|
||||
} else if (cfg.type === ServerType.DidPlaceholder && this.plcUrl) {
|
||||
throw new Error('There should only be one plc server')
|
||||
}
|
||||
const server = new DevEnvServer(this, cfg.type, cfg.port)
|
||||
await server.start()
|
||||
this.servers.set(cfg.port, server)
|
||||
if (cfg.type === ServerType.DidPlaceholder) {
|
||||
this.plcUrl = `http://localhost:${cfg.port}`
|
||||
}
|
||||
if (cfg.type === ServerType.PersonalDataServer) {
|
||||
this.pdsUrl = `http://localhost:${cfg.port}`
|
||||
}
|
||||
if (cfg.type === ServerType.BskyAppView) {
|
||||
const pds = this.servers.get(PORTS[ServerType.PersonalDataServer])
|
||||
if (pds) {
|
||||
await mockNetworkUtilities({
|
||||
port: pds.port,
|
||||
url: pds.url,
|
||||
close: pds.close,
|
||||
ctx: pds.ctx!,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async remove(server: number | DevEnvServer) {
|
||||
const port = typeof server === 'number' ? server : server.port
|
||||
const inst = this.servers.get(port)
|
||||
if (inst) {
|
||||
await inst.close()
|
||||
this.servers.delete(port)
|
||||
}
|
||||
}
|
||||
|
||||
async shutdown() {
|
||||
for (const server of this.servers.values()) {
|
||||
await server.close()
|
||||
}
|
||||
}
|
||||
|
||||
hasType(type: ServerType) {
|
||||
for (const s of this.servers.values()) {
|
||||
if (s.type === type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
listOfType(type: ServerType): DevEnvServer[] {
|
||||
return Array.from(this.servers.values()).filter((s) => s.type === type)
|
||||
}
|
||||
}
|
||||
export * from './bsky'
|
||||
export * from './network'
|
||||
export * from './network-no-appview'
|
||||
export * from './pds'
|
||||
export * from './plc'
|
||||
export * from './types'
|
||||
export * from './util'
|
||||
|
@ -4,9 +4,7 @@ import {
|
||||
REASONSPAM,
|
||||
REASONOTHER,
|
||||
} from '@atproto/api/src/client/types/com/atproto/moderation/defs'
|
||||
import { DevEnv } from '../index'
|
||||
import { ServerType } from '../types'
|
||||
import { genServerCfg } from '../util'
|
||||
import { TestNetworkNoAppView } from '../index'
|
||||
import { postTexts, replyTexts } from './data'
|
||||
import labeledImgB64 from './labeled-img-b64'
|
||||
|
||||
@ -24,16 +22,8 @@ function* dateGen() {
|
||||
return ''
|
||||
}
|
||||
|
||||
async function createNeededServers(env: DevEnv, numNeeded = 1) {
|
||||
await env.add(await genServerCfg(ServerType.DidPlaceholder))
|
||||
while (env.listOfType(ServerType.PersonalDataServer).length < numNeeded) {
|
||||
await env.add(await genServerCfg(ServerType.PersonalDataServer))
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateMockSetup(env: DevEnv) {
|
||||
export async function generateMockSetup(env: TestNetworkNoAppView) {
|
||||
const date = dateGen()
|
||||
await createNeededServers(env)
|
||||
|
||||
const rand = (n: number) => Math.floor(Math.random() * n)
|
||||
const picka = <T>(arr: Array<T>): T => {
|
||||
@ -44,10 +34,10 @@ export async function generateMockSetup(env: DevEnv) {
|
||||
}
|
||||
|
||||
const clients = {
|
||||
loggedout: env.listOfType(ServerType.PersonalDataServer)[0].getClient(),
|
||||
alice: env.listOfType(ServerType.PersonalDataServer)[0].getClient(),
|
||||
bob: env.listOfType(ServerType.PersonalDataServer)[0].getClient(),
|
||||
carla: env.listOfType(ServerType.PersonalDataServer)[0].getClient(),
|
||||
loggedout: env.pds.getClient(),
|
||||
alice: env.pds.getClient(),
|
||||
bob: env.pds.getClient(),
|
||||
carla: env.pds.getClient(),
|
||||
}
|
||||
interface User {
|
||||
email: string
|
||||
@ -195,7 +185,7 @@ export async function generateMockSetup(env: DevEnv) {
|
||||
},
|
||||
)
|
||||
|
||||
const ctx = env.listOfType(ServerType.PersonalDataServer)[0].ctx
|
||||
const ctx = env.pds.ctx
|
||||
if (ctx) {
|
||||
await ctx.db.db
|
||||
.insertInto('label')
|
||||
|
33
packages/dev-env/src/network-no-appview.ts
Normal file
33
packages/dev-env/src/network-no-appview.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { TestServerParams } from './types'
|
||||
import { TestPlc } from './plc'
|
||||
import { TestPds } from './pds'
|
||||
import { mockNetworkUtilities } from './util'
|
||||
|
||||
export class TestNetworkNoAppView {
|
||||
constructor(public plc: TestPlc, public pds: TestPds) {}
|
||||
|
||||
static async create(
|
||||
params: Partial<TestServerParams> = {},
|
||||
): Promise<TestNetworkNoAppView> {
|
||||
const dbPostgresUrl = params.dbPostgresUrl || process.env.DB_POSTGRES_URL
|
||||
const dbPostgresSchema =
|
||||
params.dbPostgresSchema || process.env.DB_POSTGRES_SCHEMA
|
||||
|
||||
const plc = await TestPlc.create(params.plc ?? {})
|
||||
const pds = await TestPds.create({
|
||||
dbPostgresUrl,
|
||||
dbPostgresSchema,
|
||||
plcUrl: plc.url,
|
||||
...params.pds,
|
||||
})
|
||||
|
||||
mockNetworkUtilities(pds)
|
||||
|
||||
return new TestNetworkNoAppView(plc, pds)
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.pds.close()
|
||||
await this.plc.close()
|
||||
}
|
||||
}
|
84
packages/dev-env/src/network.ts
Normal file
84
packages/dev-env/src/network.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import assert from 'assert'
|
||||
import getPort from 'get-port'
|
||||
import { wait } from '@atproto/common-web'
|
||||
import { createServiceJwt } from '@atproto/xrpc-server'
|
||||
import { TestServerParams } from './types'
|
||||
import { TestPlc } from './plc'
|
||||
import { TestPds } from './pds'
|
||||
import { TestBsky } from './bsky'
|
||||
import { mockNetworkUtilities } from './util'
|
||||
import { TestNetworkNoAppView } from './network-no-appview'
|
||||
|
||||
export class TestNetwork extends TestNetworkNoAppView {
|
||||
constructor(public plc: TestPlc, public pds: TestPds, public bsky: TestBsky) {
|
||||
super(plc, pds)
|
||||
}
|
||||
|
||||
static async create(
|
||||
params: Partial<TestServerParams> = {},
|
||||
): Promise<TestNetwork> {
|
||||
const dbPostgresUrl = params.dbPostgresUrl || process.env.DB_POSTGRES_URL
|
||||
assert(dbPostgresUrl, 'Missing postgres url for tests')
|
||||
const dbPostgresSchema =
|
||||
params.dbPostgresSchema || process.env.DB_POSTGRES_SCHEMA
|
||||
|
||||
const plc = await TestPlc.create(params.plc ?? {})
|
||||
|
||||
const bskyPort = params.bsky?.port ?? (await getPort())
|
||||
const pdsPort = params.pds?.port ?? (await getPort())
|
||||
const bsky = await TestBsky.create({
|
||||
port: bskyPort,
|
||||
plcUrl: plc.url,
|
||||
repoProvider: `ws://localhost:${pdsPort}`,
|
||||
dbPostgresSchema: `appview_${dbPostgresSchema}`,
|
||||
dbPostgresUrl,
|
||||
...params.bsky,
|
||||
})
|
||||
const pds = await TestPds.create({
|
||||
port: pdsPort,
|
||||
dbPostgresUrl,
|
||||
dbPostgresSchema,
|
||||
plcUrl: plc.url,
|
||||
bskyAppViewEndpoint: bsky.url,
|
||||
bskyAppViewDid: bsky.ctx.cfg.serverDid,
|
||||
...params.pds,
|
||||
})
|
||||
mockNetworkUtilities(pds)
|
||||
|
||||
return new TestNetwork(plc, pds, bsky)
|
||||
}
|
||||
|
||||
async processAll(timeout = 5000) {
|
||||
if (!this.bsky) return
|
||||
const sub = this.bsky.sub
|
||||
if (!sub) return
|
||||
const { db } = this.pds.ctx.db
|
||||
const start = Date.now()
|
||||
while (Date.now() - start < timeout) {
|
||||
await wait(50)
|
||||
if (!sub) return
|
||||
const state = await sub.getState()
|
||||
const { lastSeq } = await db
|
||||
.selectFrom('repo_seq')
|
||||
.select(db.fn.max('repo_seq.seq').as('lastSeq'))
|
||||
.executeTakeFirstOrThrow()
|
||||
if (state.cursor === lastSeq) return
|
||||
}
|
||||
throw new Error(`Sequence was not processed within ${timeout}ms`)
|
||||
}
|
||||
|
||||
async serviceHeaders(did: string) {
|
||||
const jwt = await createServiceJwt({
|
||||
iss: did,
|
||||
aud: this.bsky.ctx.cfg.serverDid,
|
||||
keypair: this.pds.ctx.repoSigningKey,
|
||||
})
|
||||
return { authorization: `Bearer ${jwt}` }
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.bsky.close()
|
||||
await this.pds.close()
|
||||
await this.plc.close()
|
||||
}
|
||||
}
|
114
packages/dev-env/src/pds.ts
Normal file
114
packages/dev-env/src/pds.ts
Normal file
@ -0,0 +1,114 @@
|
||||
import getPort from 'get-port'
|
||||
import * as ui8 from 'uint8arrays'
|
||||
import * as pds from '@atproto/pds'
|
||||
import { Secp256k1Keypair } from '@atproto/crypto'
|
||||
import { MessageDispatcher } from '@atproto/pds/src/event-stream/message-queue'
|
||||
import { AtpAgent } from '@atproto/api'
|
||||
import { Client as PlcClient } from '@did-plc/lib'
|
||||
import { PdsConfig } from './types'
|
||||
|
||||
export class TestPds {
|
||||
constructor(
|
||||
public url: string,
|
||||
public port: number,
|
||||
public server: pds.PDS,
|
||||
) {}
|
||||
|
||||
static async create(cfg: PdsConfig): Promise<TestPds> {
|
||||
const repoSigningKey = await Secp256k1Keypair.create()
|
||||
const plcRotationKey = await Secp256k1Keypair.create()
|
||||
const recoveryKey = await Secp256k1Keypair.create()
|
||||
|
||||
const port = cfg.port || (await getPort())
|
||||
const url = `http://localhost:${port}`
|
||||
const plcClient = new PlcClient(cfg.plcUrl)
|
||||
|
||||
const serverDid = await plcClient.createDid({
|
||||
signingKey: repoSigningKey.did(),
|
||||
rotationKeys: [recoveryKey.did(), plcRotationKey.did()],
|
||||
handle: 'pds.test',
|
||||
pds: `http://localhost:${port}`,
|
||||
signer: plcRotationKey,
|
||||
})
|
||||
|
||||
const config = new pds.ServerConfig({
|
||||
debugMode: true,
|
||||
version: '0.0.0',
|
||||
scheme: 'http',
|
||||
port,
|
||||
hostname: 'localhost',
|
||||
serverDid,
|
||||
recoveryKey: recoveryKey.did(),
|
||||
adminPassword: 'admin-pass',
|
||||
inviteRequired: false,
|
||||
userInviteInterval: null,
|
||||
didPlcUrl: cfg.plcUrl,
|
||||
jwtSecret: 'jwt-secret',
|
||||
availableUserDomains: ['.test'],
|
||||
appUrlPasswordReset: 'app://forgot-password',
|
||||
emailNoReplyAddress: 'noreply@blueskyweb.xyz',
|
||||
publicUrl: 'https://pds.public.url',
|
||||
imgUriSalt: '9dd04221f5755bce5f55f47464c27e1e',
|
||||
imgUriKey:
|
||||
'f23ecd142835025f42c3db2cf25dd813956c178392760256211f9d315f8ab4d8',
|
||||
dbPostgresUrl: cfg.dbPostgresUrl,
|
||||
maxSubscriptionBuffer: 200,
|
||||
repoBackfillLimitMs: 1000 * 60 * 60, // 1hr
|
||||
labelerDid: 'did:example:labeler',
|
||||
labelerKeywords: { label_me: 'test-label', label_me_2: 'test-label-2' },
|
||||
...cfg,
|
||||
})
|
||||
|
||||
const blobstore = new pds.MemoryBlobStore()
|
||||
const db = config.dbPostgresUrl
|
||||
? pds.Database.postgres({
|
||||
url: config.dbPostgresUrl,
|
||||
schema: config.dbPostgresSchema,
|
||||
})
|
||||
: pds.Database.memory()
|
||||
await db.migrateToLatestOrThrow()
|
||||
|
||||
if (config.bskyAppViewEndpoint) {
|
||||
// Disable communication to app view within pds
|
||||
MessageDispatcher.prototype.send = async () => {}
|
||||
}
|
||||
|
||||
const server = pds.PDS.create({
|
||||
db,
|
||||
blobstore,
|
||||
repoSigningKey,
|
||||
plcRotationKey,
|
||||
config,
|
||||
})
|
||||
await server.start()
|
||||
return new TestPds(url, port, server)
|
||||
}
|
||||
|
||||
get ctx(): pds.AppContext {
|
||||
return this.server.ctx
|
||||
}
|
||||
|
||||
getClient(): AtpAgent {
|
||||
return new AtpAgent({ service: `http://localhost:${this.port}` })
|
||||
}
|
||||
|
||||
adminAuth(): string {
|
||||
return (
|
||||
'Basic ' +
|
||||
ui8.toString(
|
||||
ui8.fromString(`admin:${this.ctx.cfg.adminPassword}`, 'utf8'),
|
||||
'base64pad',
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
adminAuthHeaders() {
|
||||
return {
|
||||
authorization: this.adminAuth(),
|
||||
}
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.server.destroy()
|
||||
}
|
||||
}
|
33
packages/dev-env/src/plc.ts
Normal file
33
packages/dev-env/src/plc.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import getPort from 'get-port'
|
||||
import { Client as PlcClient } from '@did-plc/lib'
|
||||
import * as plc from '@did-plc/server'
|
||||
import { PlcConfig } from './types'
|
||||
|
||||
export class TestPlc {
|
||||
constructor(
|
||||
public url: string,
|
||||
public port: number,
|
||||
public server: plc.PlcServer,
|
||||
) {}
|
||||
|
||||
static async create(cfg: PlcConfig): Promise<TestPlc> {
|
||||
const db = plc.Database.mock()
|
||||
const port = cfg.port || (await getPort())
|
||||
const url = `http://localhost:${port}`
|
||||
const server = plc.PlcServer.create({ db, port, ...cfg })
|
||||
await server.start()
|
||||
return new TestPlc(url, port, server)
|
||||
}
|
||||
|
||||
get ctx(): plc.AppContext {
|
||||
return this.server.ctx
|
||||
}
|
||||
|
||||
getClient(): PlcClient {
|
||||
return new PlcClient(this.url)
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.server.destroy()
|
||||
}
|
||||
}
|
@ -1,327 +0,0 @@
|
||||
import assert from 'assert'
|
||||
import { AddressInfo } from 'net'
|
||||
import * as crypto from '@atproto/crypto'
|
||||
import * as pds from '@atproto/pds'
|
||||
import * as plc from '@did-plc/server'
|
||||
import { Client as PlcClient } from '@did-plc/lib'
|
||||
import * as bsky from '@atproto/bsky'
|
||||
import { AtpAgent } from '@atproto/api'
|
||||
import { DidResolver } from '@atproto/did-resolver'
|
||||
import { defaultFetchHandler } from '@atproto/xrpc'
|
||||
import { MessageDispatcher } from '@atproto/pds/src/event-stream/message-queue'
|
||||
import { RepoSubscription } from '@atproto/bsky/src/subscription/repo'
|
||||
import getPort from 'get-port'
|
||||
import { DAY, HOUR, wait } from '@atproto/common-web'
|
||||
|
||||
export type CloseFn = () => Promise<void>
|
||||
|
||||
type ServerInfo = {
|
||||
port: number
|
||||
url: string
|
||||
close: CloseFn
|
||||
}
|
||||
|
||||
export type PlcServerInfo = ServerInfo & {
|
||||
ctx: plc.AppContext
|
||||
}
|
||||
|
||||
export type PdsServerInfo = ServerInfo & {
|
||||
ctx: pds.AppContext
|
||||
}
|
||||
|
||||
export type BskyServerInfo = ServerInfo & {
|
||||
ctx: bsky.AppContext
|
||||
sub: RepoSubscription
|
||||
}
|
||||
|
||||
export type TestEnvInfo = {
|
||||
bsky: BskyServerInfo
|
||||
pds: PdsServerInfo
|
||||
plc: PlcServerInfo
|
||||
close: CloseFn
|
||||
}
|
||||
|
||||
export type PlcConfig = {
|
||||
port?: number
|
||||
version?: string
|
||||
}
|
||||
|
||||
export type PdsConfig = Partial<pds.ServerConfig> & {
|
||||
plcUrl: string
|
||||
migration?: string
|
||||
}
|
||||
export type BskyConfig = Partial<bsky.ServerConfig> & {
|
||||
plcUrl: string
|
||||
repoProvider: string
|
||||
dbPostgresUrl: string
|
||||
migration?: string
|
||||
}
|
||||
|
||||
export type TestServerParams = {
|
||||
dbPostgresUrl: string
|
||||
dbPostgresSchema: string
|
||||
pds: Partial<pds.ServerConfig>
|
||||
bsky: Partial<bsky.ServerConfig>
|
||||
}
|
||||
|
||||
export const runTestEnv = async (
|
||||
params: Partial<TestServerParams> = {},
|
||||
): Promise<TestEnvInfo> => {
|
||||
const dbPostgresUrl = params.dbPostgresUrl || process.env.DB_POSTGRES_URL
|
||||
assert(dbPostgresUrl, 'Missing postgres url for tests')
|
||||
const dbPostgresSchema =
|
||||
params.dbPostgresSchema || process.env.DB_POSTGRES_SCHEMA
|
||||
|
||||
const plc = await runPlc({})
|
||||
const pdsPort = await getPort()
|
||||
const bsky = await runBsky({
|
||||
plcUrl: plc.url,
|
||||
repoProvider: `ws://localhost:${pdsPort}`,
|
||||
dbPostgresSchema: `appview_${dbPostgresSchema}`,
|
||||
dbPostgresUrl,
|
||||
})
|
||||
const pds = await runPds({
|
||||
port: pdsPort,
|
||||
dbPostgresUrl,
|
||||
dbPostgresSchema,
|
||||
plcUrl: plc.url,
|
||||
bskyAppViewEndpoint: `http://localhost:${bsky.port}`,
|
||||
bskyAppViewDid: bsky.ctx.cfg.serverDid,
|
||||
})
|
||||
mockNetworkUtilities(pds)
|
||||
|
||||
return {
|
||||
bsky,
|
||||
pds,
|
||||
plc,
|
||||
close: async () => {
|
||||
await bsky.close()
|
||||
await pds.close()
|
||||
await plc.close()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const runPlc = async (cfg: PlcConfig): Promise<PlcServerInfo> => {
|
||||
const db = plc.Database.mock()
|
||||
const server = plc.PlcServer.create({ db, ...cfg })
|
||||
const listener = await server.start()
|
||||
const port = (listener.address() as AddressInfo).port
|
||||
const url = `http://localhost:${port}`
|
||||
return {
|
||||
port,
|
||||
url,
|
||||
ctx: server.ctx,
|
||||
close: async () => {
|
||||
await server.destroy()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const runPds = async (cfg: PdsConfig): Promise<PdsServerInfo> => {
|
||||
const repoSigningKey = await crypto.Secp256k1Keypair.create()
|
||||
const plcRotationKey = await crypto.Secp256k1Keypair.create()
|
||||
const recoveryKey = await crypto.Secp256k1Keypair.create()
|
||||
|
||||
const port = cfg.port || (await getPort())
|
||||
|
||||
const plcClient = new PlcClient(cfg.plcUrl)
|
||||
const serverDid = await plcClient.createDid({
|
||||
signingKey: repoSigningKey.did(),
|
||||
rotationKeys: [recoveryKey.did(), plcRotationKey.did()],
|
||||
handle: 'pds.test',
|
||||
pds: `http://localhost:${port}`,
|
||||
signer: plcRotationKey,
|
||||
})
|
||||
|
||||
const config = new pds.ServerConfig({
|
||||
debugMode: true,
|
||||
version: '0.0.0',
|
||||
scheme: 'http',
|
||||
hostname: 'localhost',
|
||||
port,
|
||||
serverDid,
|
||||
recoveryKey: recoveryKey.did(),
|
||||
adminPassword: 'admin-pass',
|
||||
inviteRequired: false,
|
||||
userInviteInterval: null,
|
||||
didPlcUrl: cfg.plcUrl,
|
||||
jwtSecret: 'jwt-secret',
|
||||
availableUserDomains: ['.test'],
|
||||
appUrlPasswordReset: 'app://forgot-password',
|
||||
emailNoReplyAddress: 'noreply@blueskyweb.xyz',
|
||||
publicUrl: 'https://pds.public.url',
|
||||
imgUriSalt: '9dd04221f5755bce5f55f47464c27e1e',
|
||||
imgUriKey:
|
||||
'f23ecd142835025f42c3db2cf25dd813956c178392760256211f9d315f8ab4d8',
|
||||
dbPostgresUrl: cfg.dbPostgresUrl,
|
||||
maxSubscriptionBuffer: 200,
|
||||
repoBackfillLimitMs: 1000 * 60 * 60, // 1hr
|
||||
labelerDid: 'did:example:labeler',
|
||||
labelerKeywords: { label_me: 'test-label', label_me_2: 'test-label-2' },
|
||||
...cfg,
|
||||
})
|
||||
|
||||
const blobstore = new pds.MemoryBlobStore()
|
||||
const db = config.dbPostgresUrl
|
||||
? pds.Database.postgres({
|
||||
url: config.dbPostgresUrl,
|
||||
schema: config.dbPostgresSchema,
|
||||
})
|
||||
: pds.Database.memory()
|
||||
await db.migrateToLatestOrThrow()
|
||||
|
||||
// Disable communication to app view within pds
|
||||
MessageDispatcher.prototype.send = async () => {}
|
||||
|
||||
const server = pds.PDS.create({
|
||||
db,
|
||||
blobstore,
|
||||
repoSigningKey,
|
||||
plcRotationKey,
|
||||
config,
|
||||
})
|
||||
|
||||
await server.start()
|
||||
const url = `http://localhost:${port}`
|
||||
return {
|
||||
port,
|
||||
url,
|
||||
ctx: server.ctx,
|
||||
close: async () => {
|
||||
await server.destroy()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const runBsky = async (cfg: BskyConfig): Promise<BskyServerInfo> => {
|
||||
const serviceKeypair = await crypto.Secp256k1Keypair.create()
|
||||
const plcClient = new PlcClient(cfg.plcUrl)
|
||||
|
||||
const port = cfg.port || (await getPort())
|
||||
const serverDid = await plcClient.createDid({
|
||||
signingKey: serviceKeypair.did(),
|
||||
rotationKeys: [serviceKeypair.did()],
|
||||
handle: 'bsky.test',
|
||||
pds: `http://localhost:${port}`,
|
||||
signer: serviceKeypair,
|
||||
})
|
||||
|
||||
const config = new bsky.ServerConfig({
|
||||
version: '0.0.0',
|
||||
port,
|
||||
didPlcUrl: cfg.plcUrl,
|
||||
publicUrl: 'https://bsky.public.url',
|
||||
serverDid,
|
||||
imgUriSalt: '9dd04221f5755bce5f55f47464c27e1e',
|
||||
imgUriKey:
|
||||
'f23ecd142835025f42c3db2cf25dd813956c178392760256211f9d315f8ab4d8',
|
||||
didCacheStaleTTL: HOUR,
|
||||
didCacheMaxTTL: DAY,
|
||||
...cfg,
|
||||
// Each test suite gets its own lock id for the repo subscription
|
||||
repoSubLockId: uniqueLockId(),
|
||||
adminPassword: 'admin-pass',
|
||||
labelerDid: 'did:example:labeler',
|
||||
labelerKeywords: { label_me: 'test-label', label_me_2: 'test-label-2' },
|
||||
})
|
||||
|
||||
const db = bsky.Database.postgres({
|
||||
url: cfg.dbPostgresUrl,
|
||||
schema: cfg.dbPostgresSchema,
|
||||
})
|
||||
|
||||
// Separate migration db in case migration changes some connection state that we need in the tests, e.g. "alter database ... set ..."
|
||||
const migrationDb = bsky.Database.postgres({
|
||||
url: cfg.dbPostgresUrl,
|
||||
schema: cfg.dbPostgresSchema,
|
||||
})
|
||||
if (cfg.migration) {
|
||||
await migrationDb.migrateToOrThrow(cfg.migration)
|
||||
} else {
|
||||
await migrationDb.migrateToLatestOrThrow()
|
||||
}
|
||||
await migrationDb.close()
|
||||
|
||||
const server = bsky.BskyAppView.create({ db, config })
|
||||
await server.start()
|
||||
const url = `http://localhost:${port}`
|
||||
const sub = server.sub
|
||||
if (!sub) {
|
||||
throw new Error('No appview sub setup')
|
||||
}
|
||||
return {
|
||||
port,
|
||||
url,
|
||||
ctx: server.ctx,
|
||||
sub,
|
||||
close: async () => {
|
||||
await server.destroy()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const usedLockIds = new Set()
|
||||
const uniqueLockId = () => {
|
||||
let lockId: number
|
||||
do {
|
||||
lockId = 1000 + Math.ceil(1000 * Math.random())
|
||||
} while (usedLockIds.has(lockId))
|
||||
usedLockIds.add(lockId)
|
||||
return lockId
|
||||
}
|
||||
|
||||
export const mockNetworkUtilities = (pds: PdsServerInfo) => {
|
||||
// Map pds public url to its local url when resolving from plc
|
||||
const origResolveDid = DidResolver.prototype.resolveDidNoCache
|
||||
DidResolver.prototype.resolveDidNoCache = async function (did) {
|
||||
const result = await (origResolveDid.call(this, did) as ReturnType<
|
||||
typeof origResolveDid
|
||||
>)
|
||||
const service = result?.service?.find((svc) => svc.id === '#atproto_pds')
|
||||
if (typeof service?.serviceEndpoint === 'string') {
|
||||
service.serviceEndpoint = service.serviceEndpoint.replace(
|
||||
pds.ctx.cfg.publicUrl,
|
||||
`http://localhost:${pds.port}`,
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Map pds public url and handles to pds local url
|
||||
AtpAgent.configure({
|
||||
fetch: (httpUri, ...args) => {
|
||||
const url = new URL(httpUri)
|
||||
const pdsUrl = pds.ctx.cfg.publicUrl
|
||||
const pdsHandleDomains = pds.ctx.cfg.availableUserDomains
|
||||
if (
|
||||
url.origin === pdsUrl ||
|
||||
pdsHandleDomains.some((handleDomain) => url.host.endsWith(handleDomain))
|
||||
) {
|
||||
url.protocol = 'http:'
|
||||
url.host = `localhost:${pds.port}`
|
||||
return defaultFetchHandler(url.href, ...args)
|
||||
}
|
||||
return defaultFetchHandler(httpUri, ...args)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const processAll = async (server: TestEnvInfo, timeout = 5000) => {
|
||||
const { bsky, pds } = server
|
||||
const sub = bsky.sub
|
||||
if (!sub) return
|
||||
const { db } = pds.ctx.db
|
||||
const start = Date.now()
|
||||
while (Date.now() - start < timeout) {
|
||||
await wait(50)
|
||||
if (!sub) return
|
||||
const state = await sub.getState()
|
||||
const { lastSeq } = await db
|
||||
.selectFrom('repo_seq')
|
||||
.select(db.fn.max('repo_seq.seq').as('lastSeq'))
|
||||
.executeTakeFirstOrThrow()
|
||||
if (state.cursor === lastSeq) return
|
||||
}
|
||||
throw new Error(`Sequence was not processed within ${timeout}ms`)
|
||||
}
|
@ -1,24 +1,27 @@
|
||||
export enum ServerType {
|
||||
PersonalDataServer = 'pds',
|
||||
DidPlaceholder = 'plc',
|
||||
BskyAppView = 'bsky',
|
||||
import * as pds from '@atproto/pds'
|
||||
import * as bsky from '@atproto/bsky'
|
||||
|
||||
export type PlcConfig = {
|
||||
port?: number
|
||||
version?: string
|
||||
}
|
||||
|
||||
export interface ServerConfig {
|
||||
type: ServerType
|
||||
port: number
|
||||
export type PdsConfig = Partial<pds.ServerConfig> & {
|
||||
plcUrl: string
|
||||
migration?: string
|
||||
}
|
||||
|
||||
export interface StartParams {
|
||||
servers?: ServerConfig[]
|
||||
export type BskyConfig = Partial<bsky.ServerConfig> & {
|
||||
plcUrl: string
|
||||
repoProvider: string
|
||||
dbPostgresUrl: string
|
||||
migration?: string
|
||||
}
|
||||
|
||||
export const PORTS = {
|
||||
[ServerType.BskyAppView]: 2584,
|
||||
[ServerType.PersonalDataServer]: 2583,
|
||||
[ServerType.DidPlaceholder]: 2582,
|
||||
}
|
||||
|
||||
export const SERVER_TYPE_LABELS = {
|
||||
[ServerType.PersonalDataServer]: 'personal data server',
|
||||
export type TestServerParams = {
|
||||
dbPostgresUrl: string
|
||||
dbPostgresSchema: string
|
||||
pds: Partial<pds.ServerConfig>
|
||||
plc: Partial<pds.ServerConfig>
|
||||
bsky: Partial<bsky.ServerConfig>
|
||||
}
|
||||
|
@ -1,13 +1,40 @@
|
||||
import getPort, { portNumbers } from 'get-port'
|
||||
import { PORTS, ServerType, ServerConfig } from './types.js'
|
||||
import { AtpAgent } from '@atproto/api'
|
||||
import { DidResolver } from '@atproto/did-resolver'
|
||||
import { defaultFetchHandler } from '@atproto/xrpc'
|
||||
import { TestPds } from './pds'
|
||||
|
||||
export async function genServerCfg(
|
||||
type: ServerType,
|
||||
port?: number,
|
||||
): Promise<ServerConfig> {
|
||||
const basePort = PORTS[type]
|
||||
return {
|
||||
type,
|
||||
port: port || (await getPort({ port: portNumbers(basePort, 65535) })),
|
||||
export const mockNetworkUtilities = (pds: TestPds) => {
|
||||
// Map pds public url to its local url when resolving from plc
|
||||
const origResolveDid = DidResolver.prototype.resolveDidNoCache
|
||||
DidResolver.prototype.resolveDidNoCache = async function (did) {
|
||||
const result = await (origResolveDid.call(this, did) as ReturnType<
|
||||
typeof origResolveDid
|
||||
>)
|
||||
const service = result?.service?.find((svc) => svc.id === '#atproto_pds')
|
||||
if (typeof service?.serviceEndpoint === 'string') {
|
||||
service.serviceEndpoint = service.serviceEndpoint.replace(
|
||||
pds.ctx.cfg.publicUrl,
|
||||
`http://localhost:${pds.port}`,
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Map pds public url and handles to pds local url
|
||||
AtpAgent.configure({
|
||||
fetch: (httpUri, ...args) => {
|
||||
const url = new URL(httpUri)
|
||||
const pdsUrl = pds.ctx.cfg.publicUrl
|
||||
const pdsHandleDomains = pds.ctx.cfg.availableUserDomains
|
||||
if (
|
||||
url.origin === pdsUrl ||
|
||||
pdsHandleDomains.some((handleDomain) => url.host.endsWith(handleDomain))
|
||||
) {
|
||||
url.protocol = 'http:'
|
||||
url.host = `localhost:${pds.port}`
|
||||
return defaultFetchHandler(url.href, ...args)
|
||||
}
|
||||
return defaultFetchHandler(httpUri, ...args)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -1,29 +1,28 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, paginateAll } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import usersBulkSeed from '../seeds/users-bulk'
|
||||
import { wait } from '@atproto/common'
|
||||
|
||||
describe('pds user search proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
let headers: { [s: string]: string }
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_user_search',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = new AtpAgent({ service: network.pds.url })
|
||||
sc = new SeedClient(agent)
|
||||
await wait(50) // allow pending sub to be established
|
||||
await testEnv.bsky.sub.destroy()
|
||||
await network.bsky.sub.destroy()
|
||||
await usersBulkSeed(sc)
|
||||
|
||||
// Skip did/handle resolution for expediency
|
||||
const { db } = testEnv.bsky.ctx
|
||||
const { db } = network.bsky.ctx
|
||||
const now = new Date().toISOString()
|
||||
await db.db
|
||||
.insertInto('actor')
|
||||
@ -38,13 +37,13 @@ describe('pds user search proxy views', () => {
|
||||
.execute()
|
||||
|
||||
// Process remaining profiles
|
||||
testEnv.bsky.sub.resume()
|
||||
await processAll(testEnv, 50000)
|
||||
network.bsky.sub.resume()
|
||||
await network.processAll(50000)
|
||||
headers = sc.getHeaders(Object.values(sc.dids)[0])
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('typeahead gives relevant results', async () => {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, paginateAll } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('pds author feed proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -16,23 +16,22 @@ describe('pds author feed proxy views', () => {
|
||||
let dan: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_author_feed',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await basicSeed(sc)
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
carol = sc.dids.carol
|
||||
dan = sc.dids.dan
|
||||
await testEnv.pds.ctx.labeler.processAll()
|
||||
await processAll(testEnv)
|
||||
await network.pds.ctx.labeler.processAll()
|
||||
await network.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches full author feeds for self (sorted, minimal viewer state).', async () => {
|
||||
|
@ -1,31 +1,30 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, paginateAll } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import followsSeed from '../seeds/follows'
|
||||
|
||||
describe('pds follow proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
let alice: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_follows',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await followsSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches followers', async () => {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import likesSeed from '../seeds/likes'
|
||||
import { constantDate, forSnapshot, paginateAll } from '../_util'
|
||||
|
||||
describe('pds like proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -14,20 +14,19 @@ describe('pds like proxy views', () => {
|
||||
let bob: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_likes',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await likesSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
const getCursors = (items: { createdAt?: string }[]) =>
|
||||
|
@ -1,33 +1,31 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, paginateAll } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
import { Notification } from '../../src/lexicon/types/app/bsky/notification/listNotifications'
|
||||
|
||||
describe('pds notification proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
let alice: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_notifications',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = new AtpAgent({ service: network.pds.url })
|
||||
sc = new SeedClient(agent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
const sort = (notifs: Notification[]) => {
|
||||
@ -66,7 +64,7 @@ describe('pds notification proxy views', () => {
|
||||
'indeed',
|
||||
)
|
||||
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const notifCountAlice =
|
||||
await agent.api.app.bsky.notification.getUnreadCount(
|
||||
|
@ -1,12 +1,11 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('popular proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -23,11 +22,10 @@ describe('popular proxy views', () => {
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_popular',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await basicSeed(sc)
|
||||
await sc.createAccount('eve', {
|
||||
@ -42,7 +40,7 @@ describe('popular proxy views', () => {
|
||||
handle: 'frank.test',
|
||||
password: 'frank-pass',
|
||||
})
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
carol = sc.dids.carol
|
||||
@ -52,7 +50,7 @@ describe('popular proxy views', () => {
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('returns well liked posts', async () => {
|
||||
@ -80,7 +78,7 @@ describe('popular proxy views', () => {
|
||||
await sc.like(eve, three.ref)
|
||||
await sc.like(frank, three.ref)
|
||||
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const res = await agent.api.app.bsky.unspecced.getPopular(
|
||||
{},
|
||||
|
@ -1,26 +1,26 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { TestEnvInfo, processAll, runTestEnv } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('pds posts views', () => {
|
||||
let testEnv: TestEnvInfo
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_posts',
|
||||
})
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await testEnv.close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches posts', async () => {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('pds profile proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -15,21 +15,20 @@ describe('pds profile proxy views', () => {
|
||||
let dan: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_profile',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
dan = sc.dids.dan
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches own profile', async () => {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot, paginateAll } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import repostsSeed from '../seeds/reposts'
|
||||
|
||||
describe('pds repost proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -14,20 +14,19 @@ describe('pds repost proxy views', () => {
|
||||
let bob: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_reposts',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await repostsSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches reposted-by for a post', async () => {
|
||||
|
@ -1,26 +1,25 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('pds user search proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_suggestions',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await basicSeed(sc)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('actor suggestion gives users', async () => {
|
||||
|
@ -1,13 +1,12 @@
|
||||
import AtpAgent, { AppBskyFeedGetPostThread } from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll, TestEnvInfo } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { forSnapshot } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
import basicSeed from '../seeds/basic'
|
||||
|
||||
describe('pds thread proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let testEnv: TestEnvInfo
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -15,11 +14,10 @@ describe('pds thread proxy views', () => {
|
||||
let bob: string
|
||||
|
||||
beforeAll(async () => {
|
||||
testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_thread',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await basicSeed(sc)
|
||||
alice = sc.dids.alice
|
||||
@ -29,11 +27,11 @@ describe('pds thread proxy views', () => {
|
||||
beforeAll(async () => {
|
||||
// Add a repost of a reply so that we can confirm viewer state in the thread
|
||||
await sc.repost(bob, sc.replies[alice][0].ref)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it('fetches deep post thread', async () => {
|
||||
@ -120,7 +118,7 @@ describe('pds thread proxy views', () => {
|
||||
)
|
||||
indexes.aliceReplyReply = sc.replies[alice].length - 1
|
||||
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const thread1 = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][indexes.aliceRoot].ref.uriStr },
|
||||
@ -129,7 +127,7 @@ describe('pds thread proxy views', () => {
|
||||
expect(forSnapshot(thread1.data.thread)).toMatchSnapshot()
|
||||
|
||||
await sc.deletePost(bob, sc.replies[bob][indexes.bobReply].ref.uri)
|
||||
await processAll(testEnv)
|
||||
await network.processAll()
|
||||
|
||||
const thread2 = await agent.api.app.bsky.feed.getPostThread(
|
||||
{ uri: sc.posts[alice][indexes.aliceRoot].ref.uriStr },
|
||||
|
@ -1,5 +1,5 @@
|
||||
import AtpAgent from '@atproto/api'
|
||||
import { runTestEnv, CloseFn, processAll } from '@atproto/dev-env'
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { FeedViewPost } from '../../src/lexicon/types/app/bsky/feed/defs'
|
||||
import { forSnapshot, getOriginator, paginateAll } from '../_util'
|
||||
import { SeedClient } from '../seeds/client'
|
||||
@ -7,8 +7,8 @@ import basicSeed from '../seeds/basic'
|
||||
import { FeedAlgorithm } from '../../src/app-view/api/app/bsky/util/feed'
|
||||
|
||||
describe('timeline proxy views', () => {
|
||||
let network: TestNetwork
|
||||
let agent: AtpAgent
|
||||
let close: CloseFn
|
||||
let sc: SeedClient
|
||||
|
||||
// account dids, for convenience
|
||||
@ -18,23 +18,22 @@ describe('timeline proxy views', () => {
|
||||
let dan: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const testEnv = await runTestEnv({
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'proxy_timeline',
|
||||
})
|
||||
close = testEnv.close
|
||||
agent = new AtpAgent({ service: testEnv.pds.url })
|
||||
agent = network.pds.getClient()
|
||||
sc = new SeedClient(agent)
|
||||
await basicSeed(sc)
|
||||
alice = sc.dids.alice
|
||||
bob = sc.dids.bob
|
||||
carol = sc.dids.carol
|
||||
dan = sc.dids.dan
|
||||
await processAll(testEnv)
|
||||
await testEnv.pds.ctx.labeler.processAll()
|
||||
await network.processAll()
|
||||
await network.pds.ctx.labeler.processAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await close()
|
||||
await network.close()
|
||||
})
|
||||
|
||||
it("fetches authenticated user's home feed w/ reverse-chronological algorithm", async () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user