0
0
mirror of https://github.com/PostHog/posthog.git synced 2024-11-30 19:41:46 +01:00
posthog/plugin-server/functional_tests/exports-v1.test.ts

266 lines
9.4 KiB
TypeScript
Raw Normal View History

import { createServer, Server } from 'http'
import Redis from 'ioredis'
import { Kafka, Partitioners, Producer } from 'kafkajs'
import { Pool } from 'pg'
import { defaultConfig } from '../src/config/config'
import { UUIDT } from '../src/utils/utils'
import { capture, createAndReloadPluginConfig, createOrganization, createPlugin, createTeam } from './api'
import { waitForExpect } from './expectations'
let producer: Producer
let postgres: Pool // NOTE: we use a Pool here but it's probably not necessary, but for instance `insertRow` uses a Pool.
let kafka: Kafka
let redis: Redis.Redis
let organizationId: string
let server: Server
const webHookCalledWith: any = {}
beforeAll(async () => {
// Setup connections to kafka, clickhouse, and postgres
postgres = new Pool({
connectionString: defaultConfig.DATABASE_URL!,
// We use a pool only for typings sake, but we don't actually need to,
// so set max connections to 1.
max: 1,
})
kafka = new Kafka({ brokers: [defaultConfig.KAFKA_HOSTS] })
producer = kafka.producer({ createPartitioner: Partitioners.DefaultPartitioner })
await producer.connect()
redis = new Redis(defaultConfig.REDIS_URL)
organizationId = await createOrganization(postgres)
server = createServer((req, res) => {
let body = ''
req.on('data', (chunk) => {
body += chunk
})
req.on('end', () => {
webHookCalledWith[req.url!] = webHookCalledWith[req.url!] ?? []
webHookCalledWith[req.url!].push(JSON.parse(body))
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end()
})
})
await new Promise((resolve) => {
server.on('listening', resolve)
server.listen()
})
})
afterAll(async () => {
server.close()
await Promise.all([producer.disconnect(), postgres.end(), redis.disconnect()])
})
test.concurrent(`exports: exporting events on ingestion`, async () => {
const teamId = await createTeam(postgres, organizationId)
const plugin = await createPlugin(postgres, {
organization_id: organizationId,
name: 'export plugin',
plugin_type: 'source',
is_global: false,
source__index_ts: `
export const exportEvents = async (events, { global, config }) => {
await fetch(
"http://localhost:${server.address()?.port}/${teamId}",
{method: "POST", body: JSON.stringify(events)}
)
}
`,
})
await createAndReloadPluginConfig(postgres, teamId, plugin.id, redis)
const distinctId = new UUIDT().toString()
const uuid = new UUIDT().toString()
// First let's ingest an event
await capture(producer, teamId, distinctId, uuid, 'custom event', {
name: 'hehe',
uuid: new UUIDT().toString(),
})
// Then check that the exportEvents function was called
feat(person-on-events): add option to delay all events (#13505) * feat(person-on-events): add option to delay all events This change implements the option outlined in https://github.com/PostHog/product-internal/pull/405 Here I do not try to do any large structural changes to the code, I'll leave that for later although it does mean the code has a few loose couplings between pipeline steps that probably should be strongly coupled. I've tried to comment these to try to make it clear about the couplings. I've also added a workflow to run the functional tests against both configurations, which we can remove once we're happy with the new implementation. Things of note: 1. We can't enable this for all users yet, not without the live events view and not without verifying that the buffer size is sufficiently large. We can however enable this for the test team and verify that it functions as expected. 2. I have not handled the case mentioned in the above PR regarding guarding against processing the delayed events before all events in the delay window have been processed. wip test(person-on-events): add currently failing test for person on events This test doesn't work with the previous behaviour of the person-on-events implementation, but should pass with the new delay all events behaviour. * add test for KafkaJSError behaviour * add comment re delay * add test for create_alias * chore: increase exports timeout It seems to fail in CI, but only for the delayed events enabled tests. I'm not sure why, but I'm guessing it's because the events are further delayed by the new implementation. * chore: fix test * add test for ordering of person properties * use ubuntu-latest-8-cores runner * add tests for plugin processEvent * chore: ensure plugin processEvent isn't run multiple times * expand on person properties ordering test * wip * wip * add additional test * change fullyProcessEvent to onlyUpdatePersonIdAssociations * update test * add test to ensure person properties do not propagate backwards in time * simplicfy person property tests * weaken guarantee in test * chore: make sure we don't update properties on the first parse We should only be updating person_id and asociated distinct_ids on first parse. * add tests for dropping events * increase export timeout * increase historical exports timeout * increase default waitForExpect interval to 1 second
2023-01-05 17:38:43 +01:00
await waitForExpect(
() => {
const exportEvents = webHookCalledWith[`/${teamId}`]
expect(exportEvents.length).toBeGreaterThan(0)
const exportedEvents = exportEvents[0]
expect(exportedEvents).toEqual([
expect.objectContaining({
distinct_id: distinctId,
team_id: teamId,
event: 'custom event',
properties: expect.objectContaining({
name: 'hehe',
uuid: uuid,
}),
timestamp: expect.any(String),
uuid: uuid,
feat(person-on-events): add option to delay all events (#13505) * feat(person-on-events): add option to delay all events This change implements the option outlined in https://github.com/PostHog/product-internal/pull/405 Here I do not try to do any large structural changes to the code, I'll leave that for later although it does mean the code has a few loose couplings between pipeline steps that probably should be strongly coupled. I've tried to comment these to try to make it clear about the couplings. I've also added a workflow to run the functional tests against both configurations, which we can remove once we're happy with the new implementation. Things of note: 1. We can't enable this for all users yet, not without the live events view and not without verifying that the buffer size is sufficiently large. We can however enable this for the test team and verify that it functions as expected. 2. I have not handled the case mentioned in the above PR regarding guarding against processing the delayed events before all events in the delay window have been processed. wip test(person-on-events): add currently failing test for person on events This test doesn't work with the previous behaviour of the person-on-events implementation, but should pass with the new delay all events behaviour. * add test for KafkaJSError behaviour * add comment re delay * add test for create_alias * chore: increase exports timeout It seems to fail in CI, but only for the delayed events enabled tests. I'm not sure why, but I'm guessing it's because the events are further delayed by the new implementation. * chore: fix test * add test for ordering of person properties * use ubuntu-latest-8-cores runner * add tests for plugin processEvent * chore: ensure plugin processEvent isn't run multiple times * expand on person properties ordering test * wip * wip * add additional test * change fullyProcessEvent to onlyUpdatePersonIdAssociations * update test * add test to ensure person properties do not propagate backwards in time * simplicfy person property tests * weaken guarantee in test * chore: make sure we don't update properties on the first parse We should only be updating person_id and asociated distinct_ids on first parse. * add tests for dropping events * increase export timeout * increase historical exports timeout * increase default waitForExpect interval to 1 second
2023-01-05 17:38:43 +01:00
elements: [],
}),
feat(person-on-events): add option to delay all events (#13505) * feat(person-on-events): add option to delay all events This change implements the option outlined in https://github.com/PostHog/product-internal/pull/405 Here I do not try to do any large structural changes to the code, I'll leave that for later although it does mean the code has a few loose couplings between pipeline steps that probably should be strongly coupled. I've tried to comment these to try to make it clear about the couplings. I've also added a workflow to run the functional tests against both configurations, which we can remove once we're happy with the new implementation. Things of note: 1. We can't enable this for all users yet, not without the live events view and not without verifying that the buffer size is sufficiently large. We can however enable this for the test team and verify that it functions as expected. 2. I have not handled the case mentioned in the above PR regarding guarding against processing the delayed events before all events in the delay window have been processed. wip test(person-on-events): add currently failing test for person on events This test doesn't work with the previous behaviour of the person-on-events implementation, but should pass with the new delay all events behaviour. * add test for KafkaJSError behaviour * add comment re delay * add test for create_alias * chore: increase exports timeout It seems to fail in CI, but only for the delayed events enabled tests. I'm not sure why, but I'm guessing it's because the events are further delayed by the new implementation. * chore: fix test * add test for ordering of person properties * use ubuntu-latest-8-cores runner * add tests for plugin processEvent * chore: ensure plugin processEvent isn't run multiple times * expand on person properties ordering test * wip * wip * add additional test * change fullyProcessEvent to onlyUpdatePersonIdAssociations * update test * add test to ensure person properties do not propagate backwards in time * simplicfy person property tests * weaken guarantee in test * chore: make sure we don't update properties on the first parse We should only be updating person_id and asociated distinct_ids on first parse. * add tests for dropping events * increase export timeout * increase historical exports timeout * increase default waitForExpect interval to 1 second
2023-01-05 17:38:43 +01:00
])
},
60_000,
1_000
)
})
test.concurrent(`exports: exporting $autocapture events on ingestion`, async () => {
const teamId = await createTeam(postgres, organizationId)
const plugin = await createPlugin(postgres, {
organization_id: organizationId,
name: 'export plugin',
plugin_type: 'source',
is_global: false,
source__index_ts: `
export const exportEvents = async (events, { global, config }) => {
await fetch(
"http://localhost:${server.address()?.port}/${teamId}",
{method: "POST", body: JSON.stringify(events)}
)
}
`,
})
await createAndReloadPluginConfig(postgres, teamId, plugin.id, redis)
const distinctId = new UUIDT().toString()
const uuid = new UUIDT().toString()
// First let's ingest an event
await capture(producer, teamId, distinctId, uuid, '$autocapture', {
name: 'hehe',
uuid: new UUIDT().toString(),
$elements: [{ tag_name: 'div', nth_child: 1, nth_of_type: 2, $el_text: '💻' }],
})
// Then check that the exportEvents function was called
feat(person-on-events): add option to delay all events (#13505) * feat(person-on-events): add option to delay all events This change implements the option outlined in https://github.com/PostHog/product-internal/pull/405 Here I do not try to do any large structural changes to the code, I'll leave that for later although it does mean the code has a few loose couplings between pipeline steps that probably should be strongly coupled. I've tried to comment these to try to make it clear about the couplings. I've also added a workflow to run the functional tests against both configurations, which we can remove once we're happy with the new implementation. Things of note: 1. We can't enable this for all users yet, not without the live events view and not without verifying that the buffer size is sufficiently large. We can however enable this for the test team and verify that it functions as expected. 2. I have not handled the case mentioned in the above PR regarding guarding against processing the delayed events before all events in the delay window have been processed. wip test(person-on-events): add currently failing test for person on events This test doesn't work with the previous behaviour of the person-on-events implementation, but should pass with the new delay all events behaviour. * add test for KafkaJSError behaviour * add comment re delay * add test for create_alias * chore: increase exports timeout It seems to fail in CI, but only for the delayed events enabled tests. I'm not sure why, but I'm guessing it's because the events are further delayed by the new implementation. * chore: fix test * add test for ordering of person properties * use ubuntu-latest-8-cores runner * add tests for plugin processEvent * chore: ensure plugin processEvent isn't run multiple times * expand on person properties ordering test * wip * wip * add additional test * change fullyProcessEvent to onlyUpdatePersonIdAssociations * update test * add test to ensure person properties do not propagate backwards in time * simplicfy person property tests * weaken guarantee in test * chore: make sure we don't update properties on the first parse We should only be updating person_id and asociated distinct_ids on first parse. * add tests for dropping events * increase export timeout * increase historical exports timeout * increase default waitForExpect interval to 1 second
2023-01-05 17:38:43 +01:00
await waitForExpect(
() => {
const exportEvents = webHookCalledWith[`/${teamId}`]
expect(exportEvents.length).toBeGreaterThan(0)
const exportedEvents = exportEvents[0]
expect(exportedEvents).toEqual([
expect.objectContaining({
distinct_id: distinctId,
team_id: teamId,
event: '$autocapture',
properties: expect.objectContaining({
name: 'hehe',
uuid: uuid,
}),
timestamp: expect.any(String),
uuid: uuid,
feat(person-on-events): add option to delay all events (#13505) * feat(person-on-events): add option to delay all events This change implements the option outlined in https://github.com/PostHog/product-internal/pull/405 Here I do not try to do any large structural changes to the code, I'll leave that for later although it does mean the code has a few loose couplings between pipeline steps that probably should be strongly coupled. I've tried to comment these to try to make it clear about the couplings. I've also added a workflow to run the functional tests against both configurations, which we can remove once we're happy with the new implementation. Things of note: 1. We can't enable this for all users yet, not without the live events view and not without verifying that the buffer size is sufficiently large. We can however enable this for the test team and verify that it functions as expected. 2. I have not handled the case mentioned in the above PR regarding guarding against processing the delayed events before all events in the delay window have been processed. wip test(person-on-events): add currently failing test for person on events This test doesn't work with the previous behaviour of the person-on-events implementation, but should pass with the new delay all events behaviour. * add test for KafkaJSError behaviour * add comment re delay * add test for create_alias * chore: increase exports timeout It seems to fail in CI, but only for the delayed events enabled tests. I'm not sure why, but I'm guessing it's because the events are further delayed by the new implementation. * chore: fix test * add test for ordering of person properties * use ubuntu-latest-8-cores runner * add tests for plugin processEvent * chore: ensure plugin processEvent isn't run multiple times * expand on person properties ordering test * wip * wip * add additional test * change fullyProcessEvent to onlyUpdatePersonIdAssociations * update test * add test to ensure person properties do not propagate backwards in time * simplicfy person property tests * weaken guarantee in test * chore: make sure we don't update properties on the first parse We should only be updating person_id and asociated distinct_ids on first parse. * add tests for dropping events * increase export timeout * increase historical exports timeout * increase default waitForExpect interval to 1 second
2023-01-05 17:38:43 +01:00
elements: [
{
tag_name: 'div',
nth_child: 1,
nth_of_type: 2,
order: 0,
$el_text: '💻',
text: '💻',
attributes: {},
},
],
}),
feat(person-on-events): add option to delay all events (#13505) * feat(person-on-events): add option to delay all events This change implements the option outlined in https://github.com/PostHog/product-internal/pull/405 Here I do not try to do any large structural changes to the code, I'll leave that for later although it does mean the code has a few loose couplings between pipeline steps that probably should be strongly coupled. I've tried to comment these to try to make it clear about the couplings. I've also added a workflow to run the functional tests against both configurations, which we can remove once we're happy with the new implementation. Things of note: 1. We can't enable this for all users yet, not without the live events view and not without verifying that the buffer size is sufficiently large. We can however enable this for the test team and verify that it functions as expected. 2. I have not handled the case mentioned in the above PR regarding guarding against processing the delayed events before all events in the delay window have been processed. wip test(person-on-events): add currently failing test for person on events This test doesn't work with the previous behaviour of the person-on-events implementation, but should pass with the new delay all events behaviour. * add test for KafkaJSError behaviour * add comment re delay * add test for create_alias * chore: increase exports timeout It seems to fail in CI, but only for the delayed events enabled tests. I'm not sure why, but I'm guessing it's because the events are further delayed by the new implementation. * chore: fix test * add test for ordering of person properties * use ubuntu-latest-8-cores runner * add tests for plugin processEvent * chore: ensure plugin processEvent isn't run multiple times * expand on person properties ordering test * wip * wip * add additional test * change fullyProcessEvent to onlyUpdatePersonIdAssociations * update test * add test to ensure person properties do not propagate backwards in time * simplicfy person property tests * weaken guarantee in test * chore: make sure we don't update properties on the first parse We should only be updating person_id and asociated distinct_ids on first parse. * add tests for dropping events * increase export timeout * increase historical exports timeout * increase default waitForExpect interval to 1 second
2023-01-05 17:38:43 +01:00
])
},
60_000,
1_000
)
})
test.concurrent(`exports: historical exports`, async () => {
const teamId = await createTeam(postgres, organizationId)
const distinctId = new UUIDT().toString()
const uuid = new UUIDT().toString()
const plugin = await createPlugin(postgres, {
organization_id: organizationId,
name: 'export plugin',
plugin_type: 'source',
is_global: false,
source__index_ts: `
export const exportEvents = async (events, { global, config }) => {
await fetch(
"http://localhost:${server.address()?.port}/${teamId}",
{method: "POST", body: JSON.stringify(events)}
)
}
`,
})
const pluginConfig = await createAndReloadPluginConfig(postgres, teamId, plugin.id, redis)
// First let's capture an event and wait for it to be ingested so
// so we can check that the historical event is the same as the one
// passed to processEvent on initial ingestion.
await capture(producer, teamId, distinctId, uuid, '$autocapture', {
name: 'hehe',
uuid: new UUIDT().toString(),
$elements: [{ tag_name: 'div', nth_child: 1, nth_of_type: 2, $el_text: '💻' }],
})
// Then check that the exportEvents function was called
feat(person-on-events): add option to delay all events (#13505) * feat(person-on-events): add option to delay all events This change implements the option outlined in https://github.com/PostHog/product-internal/pull/405 Here I do not try to do any large structural changes to the code, I'll leave that for later although it does mean the code has a few loose couplings between pipeline steps that probably should be strongly coupled. I've tried to comment these to try to make it clear about the couplings. I've also added a workflow to run the functional tests against both configurations, which we can remove once we're happy with the new implementation. Things of note: 1. We can't enable this for all users yet, not without the live events view and not without verifying that the buffer size is sufficiently large. We can however enable this for the test team and verify that it functions as expected. 2. I have not handled the case mentioned in the above PR regarding guarding against processing the delayed events before all events in the delay window have been processed. wip test(person-on-events): add currently failing test for person on events This test doesn't work with the previous behaviour of the person-on-events implementation, but should pass with the new delay all events behaviour. * add test for KafkaJSError behaviour * add comment re delay * add test for create_alias * chore: increase exports timeout It seems to fail in CI, but only for the delayed events enabled tests. I'm not sure why, but I'm guessing it's because the events are further delayed by the new implementation. * chore: fix test * add test for ordering of person properties * use ubuntu-latest-8-cores runner * add tests for plugin processEvent * chore: ensure plugin processEvent isn't run multiple times * expand on person properties ordering test * wip * wip * add additional test * change fullyProcessEvent to onlyUpdatePersonIdAssociations * update test * add test to ensure person properties do not propagate backwards in time * simplicfy person property tests * weaken guarantee in test * chore: make sure we don't update properties on the first parse We should only be updating person_id and asociated distinct_ids on first parse. * add tests for dropping events * increase export timeout * increase historical exports timeout * increase default waitForExpect interval to 1 second
2023-01-05 17:38:43 +01:00
const [exportedEvent] = await waitForExpect(
() => {
const exportEvents = webHookCalledWith[`/${teamId}`]
expect(exportEvents.length).toBeGreaterThan(0)
return exportEvents[0]
},
60_000,
1_000
)
// NOTE: the frontend doesn't actually push to this queue but rather
// adds directly to PostgreSQL using the graphile-worker stored
// procedure `add_job`. I'd rather keep these tests graphile
// unaware.
await producer.send({
topic: 'jobs',
messages: [
{
key: teamId.toString(),
value: JSON.stringify({
type: 'Export historical events',
pluginConfigId: pluginConfig.id,
pluginConfigTeam: teamId,
payload: {
dateFrom: new Date(Date.now() - 60000).toISOString(),
dateTo: new Date(Date.now()).toISOString(),
},
}),
},
],
})
// Then check that the exportEvents function was called with the
// same data that was used with the non-historical export, with the
// additions of details related to the historical export.
await waitForExpect(
() => {
const historicallyExportedEvents = webHookCalledWith[`/${teamId}`].filter((events) =>
events.some((event) => event.properties['$$is_historical_export_event'])
)
expect(historicallyExportedEvents.length).toBeGreaterThan(0)
const historicallyExportedEvent = historicallyExportedEvents[0]
expect(historicallyExportedEvent).toEqual([
expect.objectContaining({
...exportedEvent,
ip: '', // NOTE: for some reason this is "" when exported historically, but null otherwise.
properties: {
...exportedEvent.properties,
$$is_historical_export_event: true,
$$historical_export_timestamp: expect.any(String),
$$historical_export_source_db: 'clickhouse',
},
}),
])
},
feat(person-on-events): add option to delay all events (#13505) * feat(person-on-events): add option to delay all events This change implements the option outlined in https://github.com/PostHog/product-internal/pull/405 Here I do not try to do any large structural changes to the code, I'll leave that for later although it does mean the code has a few loose couplings between pipeline steps that probably should be strongly coupled. I've tried to comment these to try to make it clear about the couplings. I've also added a workflow to run the functional tests against both configurations, which we can remove once we're happy with the new implementation. Things of note: 1. We can't enable this for all users yet, not without the live events view and not without verifying that the buffer size is sufficiently large. We can however enable this for the test team and verify that it functions as expected. 2. I have not handled the case mentioned in the above PR regarding guarding against processing the delayed events before all events in the delay window have been processed. wip test(person-on-events): add currently failing test for person on events This test doesn't work with the previous behaviour of the person-on-events implementation, but should pass with the new delay all events behaviour. * add test for KafkaJSError behaviour * add comment re delay * add test for create_alias * chore: increase exports timeout It seems to fail in CI, but only for the delayed events enabled tests. I'm not sure why, but I'm guessing it's because the events are further delayed by the new implementation. * chore: fix test * add test for ordering of person properties * use ubuntu-latest-8-cores runner * add tests for plugin processEvent * chore: ensure plugin processEvent isn't run multiple times * expand on person properties ordering test * wip * wip * add additional test * change fullyProcessEvent to onlyUpdatePersonIdAssociations * update test * add test to ensure person properties do not propagate backwards in time * simplicfy person property tests * weaken guarantee in test * chore: make sure we don't update properties on the first parse We should only be updating person_id and asociated distinct_ids on first parse. * add tests for dropping events * increase export timeout * increase historical exports timeout * increase default waitForExpect interval to 1 second
2023-01-05 17:38:43 +01:00
60_000,
1_000
)
})