Skip to content
This repository has been archived by the owner on Jan 15, 2025. It is now read-only.

Commit

Permalink
[#IOCIT-357] IT added
Browse files Browse the repository at this point in the history
  • Loading branch information
gquadrati committed Feb 17, 2023
1 parent b723c32 commit dc4ad03
Show file tree
Hide file tree
Showing 21 changed files with 5,520 additions and 6 deletions.
22 changes: 21 additions & 1 deletion .devops/code-review-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,24 @@ stages:
- bash: |
bash <(curl -s https://codecov.io/bash)
displayName: 'Code coverage'
displayName: 'Code coverage'
- stage: Integration_Tests
dependsOn: []
jobs:
- job: integration_tests
steps:
- template: templates/node-job-setup/template.yaml@pagopaCommons
- script: |
cd __integrations__
cp environments/env.base environments/.env
yarn install --frozen-lockfile
yarn start
displayName: 'Start test resources'
- script: |
cd __integrations__
yarn install --frozen-lockfile
sleep 30s
docker exec integrations___testagent_1 yarn test
# ^^^ FIXME: reference container using a less arbitrary name
displayName: 'Execute tests'
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ generated
azure-functions-core-tools

.history

docker-compose.override.yml
97 changes: 97 additions & 0 deletions __integrations__/__mocks__/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { CosmosClient, Database } from "@azure/cosmos";

import * as TE from "fp-ts/lib/TaskEither";
import * as RA from "fp-ts/ReadonlyArray";
import { pipe } from "fp-ts/lib/function";

import * as MessageStatusCollection from "@pagopa/io-functions-commons/dist/src/models/message_status";

import { log } from "../utils/logger";
import {
createContainer as createCollection,
createDatabase,
deleteContainer
} from "./utils/cosmos";
import { CosmosErrors } from "@pagopa/io-functions-commons/dist/src/utils/cosmosdb_model";
import { toCosmosErrorResponse } from "@pagopa/io-functions-commons/dist/src/utils/cosmosdb_model";
import { Container } from "@azure/cosmos";

/**
*
* @param database
* @returns
*/
// TODO
// export const createAllCollections = (
// database: Database
// ): TE.TaskEither<CosmosErrors, readonly Container[]> =>
// pipe(
// [
// //TODO: Replace
// // message-status
// createCollection(
// database,
// MessageStatusCollection.MESSAGE_STATUS_COLLECTION_NAME,
// MessageStatusCollection.MESSAGE_STATUS_MODEL_PK_FIELD
// )
// ],
// RA.sequence(TE.ApplicativePar)
// );

/**
* Create DB
*/
export const deleteAllCollections = (
database: Database
): TE.TaskEither<CosmosErrors, readonly Container[]> => {
log("deleting CosmosDB");

return pipe(
database,
TE.of,
TE.bindTo("db"),
TE.bind("collectionNames", ({ db }) =>
pipe(
TE.tryCatch(
() => db.containers.readAll().fetchAll(),
toCosmosErrorResponse
),
TE.map(r => r.resources),
TE.map(RA.map(r => r.id))
)
),
TE.chain(({ db, collectionNames }) =>
pipe(
collectionNames,
RA.map(r => deleteContainer(db, r)),
RA.sequence(TE.ApplicativePar)
)
),
TE.map(collections => {
log("Deleted", collections.length, "collections");
return collections;
}),
TE.mapLeft(err => {
log("Error", err);
return err;
})
);
};

/**
* Create DB and collections
*/
export const createCosmosDbAndCollections = (
client: CosmosClient,
cosmosDbName: string
): TE.TaskEither<CosmosErrors, Database> =>
pipe(
createDatabase(client, cosmosDbName),
// Delete all collections, in case they already exist
TE.chainFirst(deleteAllCollections),
// TE.chainFirst(createAllCollections),
TE.mapLeft(err => {
log("Error", err);
return err;
})
);
48 changes: 48 additions & 0 deletions __integrations__/__mocks__/utils/azure_storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { BlobService } from "azure-storage";
import { QueueServiceClient } from "@azure/storage-queue";
import { flow, pipe } from "fp-ts/lib/function";
import * as RA from "fp-ts/lib/ReadonlyArray";
import * as TE from "fp-ts/lib/TaskEither";
import * as E from "fp-ts/lib/Either";
import * as T from "fp-ts/lib/Task";

export const createBlobs = (blobServiceClient: BlobService, blobs: string[]) =>
pipe(
blobs,
T.of,
T.chain(
flow(
RA.map(b =>
TE.tryCatch(
async () =>
blobServiceClient.createContainerIfNotExists(
b,
(error, result) => {
if (!error) Promise.resolve(result);
else Promise.reject(error);
}
),
E.toError
)
),
RA.sequence(TE.ApplicativeSeq)
)
)
);

export const createQueues = (
queueServiceClient: QueueServiceClient,
queues: string[]
) =>
pipe(
queues,
T.of,
T.chain(
flow(
RA.map(q =>
TE.tryCatch(async () => queueServiceClient.createQueue(q), E.toError)
),
RA.sequence(T.ApplicativeSeq)
)
)
);
59 changes: 59 additions & 0 deletions __integrations__/__mocks__/utils/cosmos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Insert fake data into CosmosDB database emulator.
*/
import {
Container,
Database,
CosmosClient,
IndexingPolicy
} from "@azure/cosmos";

import { pipe } from "fp-ts/lib/function";
import * as TE from "fp-ts/lib/TaskEither";
import {
CosmosErrors,
toCosmosErrorResponse
} from "@pagopa/io-functions-commons/dist/src/utils/cosmosdb_model";

export const createDatabase = (
client: CosmosClient,
dbName: string
): TE.TaskEither<CosmosErrors, Database> =>
pipe(
TE.tryCatch(
() => client.databases.createIfNotExists({ id: dbName }),
toCosmosErrorResponse
),
TE.map(databaseResponse => databaseResponse.database)
);

export const createContainer = (
db: Database,
containerName: string,
partitionKey: string,
indexingPolicy?: IndexingPolicy
): TE.TaskEither<CosmosErrors, Container> =>
pipe(
TE.tryCatch(
() =>
db.containers.createIfNotExists({
id: containerName,
indexingPolicy,
partitionKey: `/${partitionKey}`
}),
toCosmosErrorResponse
),
TE.map(containerResponse => containerResponse.container)
);

export const deleteContainer = (
db: Database,
containerName: string
): TE.TaskEither<CosmosErrors, Container> =>
pipe(
TE.tryCatch(
() => db.container(containerName).delete(),
toCosmosErrorResponse
),
TE.map(containerResponse => containerResponse.container)
);
106 changes: 106 additions & 0 deletions __integrations__/__tests__/activatePubKey.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable sort-keys */
import { exit } from "process";

import { CosmosClient, Database } from "@azure/cosmos";
import { createBlobService } from "azure-storage";

import * as TE from "fp-ts/TaskEither";
import { pipe } from "fp-ts/lib/function";

import { createCosmosDbAndCollections } from "../__mocks__/fixtures";

import { getNodeFetch } from "../utils/fetch";
import { log } from "../utils/logger";

import {
WAIT_MS,
SHOW_LOGS,
COSMOSDB_URI,
COSMOSDB_KEY,
COSMOSDB_NAME,
QueueStorageConnection
} from "../env";

const MAX_ATTEMPT = 50;

jest.setTimeout(WAIT_MS * MAX_ATTEMPT);

const baseUrl = "http://function:7071";
const fetch = getNodeFetch();

// ----------------
// Setup dbs
// ----------------

const blobService = createBlobService(QueueStorageConnection);

// @ts-ignore
const cosmosClient = new CosmosClient({
endpoint: COSMOSDB_URI,
key: COSMOSDB_KEY
});

// eslint-disable-next-line functional/no-let
let database: Database;

// Wait some time
beforeAll(async () => {
database = await pipe(
createCosmosDbAndCollections(cosmosClient, COSMOSDB_NAME),
TE.getOrElse(e => {
throw Error("Cannot create db");
})
)();

// await pipe(
// createBlobs(blobService, [MESSAGE_CONTAINER_NAME]),
// TE.getOrElse(() => {
// throw Error("Cannot create azure storage");
// })
// )();

await waitFunctionToSetup();
});

beforeEach(() => {
jest.clearAllMocks();
});

// -------------------------
// Tests
// -------------------------

describe("activatePubKey |> Success Results", () => {
it("dummy", () => {
expect(true).toBe(true);
});
});

// -----------------------
// utils
// -----------------------

const delay = (ms: number): Promise<void> =>
new Promise(resolve => setTimeout(resolve, ms));

const waitFunctionToSetup = async (): Promise<void> => {
log("ENV: ", COSMOSDB_URI, WAIT_MS, SHOW_LOGS);
// eslint-disable-next-line functional/no-let
let i = 0;
while (i < MAX_ATTEMPT) {
log("Waiting the function to setup..");
try {
await fetch(baseUrl + "/info");
break;
} catch (e) {
log("Waiting the function to setup..");
await delay(WAIT_MS);
i++;
}
}
if (i >= MAX_ATTEMPT) {
log("Function unable to setup in time");
exit(1);
}
};
Loading

0 comments on commit dc4ad03

Please sign in to comment.