Skip to content

Commit

Permalink
feat: finish contact service
Browse files Browse the repository at this point in the history
  • Loading branch information
kaladivo committed Aug 23, 2024
1 parent d867e0a commit 02be811
Show file tree
Hide file tree
Showing 80 changed files with 2,982 additions and 263 deletions.
Binary file not shown.
7 changes: 2 additions & 5 deletions apps/contact-service/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ DB_DEBUG=true
# DB_USER=postgres
# DB_PASSWORD=root


EXPIRATION_PERIOD_DAYS=7
OFFER_REPORT_FILTER=1
REPORT_LIMIT_INTERVAL_DAYS=1

INACTIVITY_NOTIFICATION_AFTER_DAYS=3
NEW_CONTENT_NOTIFICATION_AFTER_DAYS=4

TEST_DB_PREFIX=offer_service_test_
TEST_DB_PORT=5432
Expand Down
6 changes: 6 additions & 0 deletions apps/contact-service/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ RUN yarn build
FROM node:19 as runner


ARG SERVICE_VERSION
ARG ENVIRONMENT

ENV SERVICE_VERSION=${SERVICE_VERSION}
ENV SERVICE_NAME="Contact service - ${ENVIRONMENT}"

COPY --from=builder /app/apps/contact-service/ /app/apps/contact-service
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/package.json /app/package.json
Expand Down
4 changes: 2 additions & 2 deletions apps/contact-service/src/__tests__/utils/NodeTestingApp.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {OfferApiSpecification} from '@vexl-next/rest-api/src/services/offer/specification'
import {ContactApiSpecification} from '@vexl-next/rest-api/src/services/contact/specification'
import {Context, Layer, type Effect} from 'effect'
import {NodeTesting} from 'effect-http-node'
import {app} from '../../httpServer'

const nodeTestingAppEffect = NodeTesting.make(app, OfferApiSpecification)
const nodeTestingAppEffect = NodeTesting.make(app, ContactApiSpecification)

export class NodeTestingApp extends Context.Tag('NodeTestingApp')<
NodeTestingApp,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {Effect, Layer} from 'effect'
import {
type BatchResponse,
type MulticastMessage,
} from 'firebase-admin/messaging'
import {FirebaseMessagingService} from '../../utils/notifications/FirebaseMessagingService'

export const sendMessageMock = jest.fn(
async ({tokens}: MulticastMessage): Promise<BatchResponse> => ({
responses: tokens.map(() => ({
success: true as const,
})),
successCount: tokens.length,
failureCount: 0,
})
)

export const sendToTopicMock = jest.fn()

export const mockedFirebaseMessagingServiceLayer = Layer.effect(
FirebaseMessagingService,
Effect.succeed({
sendEachForMulticast: sendMessageMock,
sendToTopic: sendToTopicMock,
})
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {HttpClientRequest} from '@effect/platform'
import {Array, Effect, Order, pipe} from 'effect'
import {NodeTestingApp} from '../../NodeTestingApp'
import {runPromiseInMockedEnvironment} from '../../runPromiseInMockedEnvironment'
import {
createAndImportUsersFromNetwork,
type DummyUser,
generateKeysAndHasheForNumber,
} from './utils'

let networkOne: [DummyUser, ...DummyUser[]]
let networkTwo: [DummyUser, ...DummyUser[]]

beforeAll(async () => {
await runPromiseInMockedEnvironment(
Effect.gen(function* (_) {
networkOne = yield* _(
Effect.all([
generateKeysAndHasheForNumber('+420733333001'),
generateKeysAndHasheForNumber('+420733333002'),
generateKeysAndHasheForNumber('+420733333003'),
generateKeysAndHasheForNumber('+420733333004'),
generateKeysAndHasheForNumber('+420733333005'),
])
)

yield* _(
Effect.forEach(networkOne, (oneUser) =>
createAndImportUsersFromNetwork(oneUser, networkOne)
)
)

networkTwo = yield* _(
Effect.all([
generateKeysAndHasheForNumber('+420733333101'),
generateKeysAndHasheForNumber('+420733333102'),
generateKeysAndHasheForNumber('+420733333106'),
generateKeysAndHasheForNumber('+420733333107'),
generateKeysAndHasheForNumber('+420733333108'),
])
)

yield* _(
Effect.forEach(networkTwo, (twoUser) =>
createAndImportUsersFromNetwork(twoUser, networkTwo)
)
)
})
)
})

describe('Common connections', () => {
it('Fetches common connections for array of friends', async () => {
await runPromiseInMockedEnvironment(
Effect.gen(function* (_) {
const app = yield* _(NodeTestingApp)

const me = networkOne[0]
const userContacts = Array.filter(
networkOne,
(u) => u.keys.publicKeyPemBase64 !== me.keys.publicKeyPemBase64
)

const connections = yield* _(
app.fetchCommonConnections(
{
body: {
publicKeys: Array.map(
userContacts,
(one) => one.keys.publicKeyPemBase64
),
},
},
HttpClientRequest.setHeaders(networkOne[0].authHeaders)
)
)

const resultKeys = pipe(
connections.commonContacts,
Array.map((c) => c.publicKey),
Array.sort(Order.string),
Array.join(', ')
)
// Result keys equals to requestzdcgtrfdcdfgtzrcfedxs
expect(resultKeys).toBe(
pipe(
userContacts,
Array.map((o) => o.keys.publicKeyPemBase64),
Array.sort(Order.string),
Array.join(', ')
)
)

// Each friend should have other people as common friends
for (const {common, publicKey} of connections.commonContacts) {
const otherFriendsHashes = pipe(
userContacts,
Array.filter((o) => o.keys.publicKeyPemBase64 !== publicKey),
Array.map((o) => o.hashedNumber),
Array.sort(Order.string),
Array.join(',')
)

expect(
pipe(common.hashes, Array.sort(Order.string), Array.join(','))
).toEqual(otherFriendsHashes)
}
})
)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import {HttpClientRequest} from '@effect/platform'
import {MAX_PAGE_SIZE} from '@vexl-next/rest-api/src/Pagination.brand'
import {Array, Effect, Order, pipe} from 'effect'
import {NodeTestingApp} from '../../NodeTestingApp'
import {runPromiseInMockedEnvironment} from '../../runPromiseInMockedEnvironment'
import {
createAndImportUsersFromNetwork,
type DummyUser,
generateKeysAndHasheForNumber,
} from './utils'

let networkOne: [DummyUser, ...DummyUser[]]
let networkTwo: [DummyUser, ...DummyUser[]]

beforeAll(async () => {
await runPromiseInMockedEnvironment(
Effect.gen(function* (_) {
networkOne = yield* _(
Effect.all([
generateKeysAndHasheForNumber('+420733333001'),
generateKeysAndHasheForNumber('+420733333002'),
generateKeysAndHasheForNumber('+420733333003'),
generateKeysAndHasheForNumber('+420733333004'),
generateKeysAndHasheForNumber('+420733333005'),
])
)

yield* _(
Effect.forEach(networkOne, (oneUser) =>
createAndImportUsersFromNetwork(oneUser, networkOne)
)
)

networkTwo = yield* _(
Effect.all([
generateKeysAndHasheForNumber('+420733333101'),
generateKeysAndHasheForNumber('+420733333102'),
generateKeysAndHasheForNumber('+420733333106'),
generateKeysAndHasheForNumber('+420733333107'),
generateKeysAndHasheForNumber('+420733333108'),
])
)

yield* _(
Effect.forEach(networkTwo, (twoUser) =>
createAndImportUsersFromNetwork(twoUser, [
// ...networkTwo,
...networkOne,
])
)
)
})
)
})

describe('Fetch my contacts', () => {
it('Properly fetches first level contacts', async () => {
await runPromiseInMockedEnvironment(
Effect.gen(function* (_) {
const me = networkOne[0]

const userContacts = Array.filter(
networkOne,
(u) => u.keys.publicKeyPemBase64 !== me.keys.publicKeyPemBase64
)
const app = yield* _(NodeTestingApp)
const {items} = yield* _(
app.fetchMyContacts(
{
query: {level: 'FIRST' as const, page: 0, limit: MAX_PAGE_SIZE},
},
HttpClientRequest.setHeaders(networkOne[0].authHeaders)
)
)

expect(
pipe(
items,
Array.map((o) => o.publicKey),
Array.sort(Order.string),
Array.join(',')
)
).toBe(
pipe(
userContacts,
Array.map((one) => one.keys.publicKeyPemBase64),
Array.sort(Order.string),
Array.join(',')
)
)
})
)
})
it('Propely fetches second level contacts', async () => {
await runPromiseInMockedEnvironment(
Effect.gen(function* (_) {
const me = networkOne[0]
const userContacts = Array.filter(
networkOne,
(u) => u.keys.publicKeyPemBase64 !== me.keys.publicKeyPemBase64
)

const app = yield* _(NodeTestingApp)
const {items} = yield* _(
app.fetchMyContacts(
{
query: {level: 'SECOND' as const, page: 0, limit: MAX_PAGE_SIZE},
},
HttpClientRequest.setHeaders(me.authHeaders)
)
)

console.log('me', me.keys.publicKeyPemBase64)

expect(
pipe(
items,
Array.map((o) => o.publicKey),
Array.sort(Order.string),
Array.join(',')
)
).toBe(
pipe(
[...networkTwo, ...userContacts],
Array.map((one) => one.keys.publicKeyPemBase64),
Array.sort(Order.string),
Array.join(',')
)
)
})
)
})
it('Properly fetches all level contacts', async () => {
await runPromiseInMockedEnvironment(
Effect.gen(function* (_) {
const me = networkOne[0]
const userContacts = Array.filter(
networkOne,
(u) => u.keys.publicKeyPemBase64 !== me.keys.publicKeyPemBase64
)

const app = yield* _(NodeTestingApp)
const {items} = yield* _(
app.fetchMyContacts(
{
query: {level: 'ALL' as const, page: 0, limit: MAX_PAGE_SIZE},
},
HttpClientRequest.setHeaders(me.authHeaders)
)
)

console.log('me', me.keys.publicKeyPemBase64)

expect(
pipe(
items,
Array.map((o) => o.publicKey),
Array.sort(Order.string),
Array.join(',')
)
).toBe(
pipe(
[...networkTwo, ...userContacts],
Array.map((one) => one.keys.publicKeyPemBase64),
Array.sort(Order.string),
Array.join(',')
)
)
})
)
})
})
Loading

0 comments on commit 02be811

Please sign in to comment.