Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add pactffi_log_to_file for consumer/verifier #428

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions native/addon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "pactffiVersion"), Napi::Function::New(env, PactffiVersion));
exports.Set(Napi::String::New(env, "pactffiInit"), Napi::Function::New(env, PactffiInit));
exports.Set(Napi::String::New(env, "pactffiInitWithLogLevel"), Napi::Function::New(env, PactffiInitWithLogLevel));
exports.Set(Napi::String::New(env, "pactffiLogToFile"), Napi::Function::New(env, PactffiLogToFile));

// Consumer
exports.Set(Napi::String::New(env, "pactffiMockServerMatched"), Napi::Function::New(env, PactffiMockServerMatched));
Expand Down
58 changes: 58 additions & 0 deletions native/ffi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,64 @@ Napi::Value PactffiInitWithLogLevel(const Napi::CallbackInfo& info) {
return env.Undefined();
}

LevelFilter integerToLevelFilter(Napi::Env &env, uint32_t number) {
LevelFilter logLevel = LevelFilter::LevelFilter_Off;

switch(number) {
case 0:
logLevel = LevelFilter::LevelFilter_Off;
break;
case 1:
logLevel = LevelFilter::LevelFilter_Error;
break;
case 2:
logLevel = LevelFilter::LevelFilter_Warn;
break;
case 3:
logLevel = LevelFilter::LevelFilter_Info;
break;
case 4:
logLevel = LevelFilter::LevelFilter_Debug;
break;
case 5:
logLevel = LevelFilter::LevelFilter_Trace;
break;
default:
std::string err = "pact-js-core C integration: Unable to parse log level number: ";
err += number;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is err defined somewhere?


throw Napi::Error::New(env, err);
}

return logLevel;
}


Napi::Value PactffiLogToFile(const Napi::CallbackInfo& info) {
// return: int
Napi::Env env = info.Env();

if (info.Length() < 2) {
throw Napi::Error::New(env, "PactffiLogToFile(envVar) received < 2 arguments");
}

if (!info[0].IsString()) {
throw Napi::Error::New(env, "PactffiLogToFile(envVar) expected a string");
}

if (!info[1].IsNumber()) {
throw Napi::Error::New(env, "PactffiLogToFile(envVar) expected a number");
}

// Extract log level
std::string fileName = info[0].As<Napi::String>().Utf8Value();
uint32_t levelFilterNumber = info[1].As<Napi::Number>().Uint32Value();
LevelFilter levelFilter = integerToLevelFilter(env, levelFilterNumber);

int res = pactffi_log_to_file(fileName.c_str(), levelFilter);

return Napi::Number::New(env, res);
}
/*

Napi::Value Pactffi_log_message(const Napi::CallbackInfo& info) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
"build": "tsc --project tsconfig.build.json",
"prerelease": "npm run snyk-protect",
"release": "commit-and-tag-version",
"test": "cross-env LOGLEVEL=debug PACT_DO_NOT_TRACK=true mocha \"{src,test}/**/*.spec.ts\"",
"test": "cross-env PACT_DO_NOT_TRACK=true mocha \"{src,test}/**/*.spec.ts\"",
"snyk-protect": "snyk-protect",
"format:base": "prettier --parser typescript",
"format:check": "npm run format:base -- --list-different \"{src,test}/**/*.{ts,tsx}\"",
Expand Down
10 changes: 6 additions & 4 deletions src/consumer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@ export const makeConsumerPact = (
consumer: string,
provider: string,
version: FfiSpecificationVersion = 3,
logLevel = getLogLevel()
logLevel = getLogLevel(),
logFile?: string
): ConsumerPact => {
const ffi = getFfiLib(logLevel);
if (logLevel) {
setLogLevel(logLevel);
}
const ffi = getFfiLib(logLevel, logFile);

const pactPtr = ffi.pactffiNewPact(consumer, provider);
if (!ffi.pactffiWithSpecification(pactPtr, version)) {
Expand Down Expand Up @@ -370,12 +371,13 @@ export const makeConsumerMessagePact = (
consumer: string,
provider: string,
version: FfiSpecificationVersion = 4,
logLevel = getLogLevel()
logLevel = getLogLevel(),
logFile?: string
): ConsumerMessagePact => {
const ffi = getFfiLib(logLevel);
if (logLevel) {
setLogLevel(logLevel);
}
const ffi = getFfiLib(logLevel, logFile);

const pactPtr = ffi.pactffiNewPact(consumer, provider);
if (!ffi.pactffiWithSpecification(pactPtr, version) || version < 4) {
Expand Down
32 changes: 17 additions & 15 deletions src/ffi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'node:path';
import bindings = require('node-gyp-build');
import logger, { DEFAULT_LOG_LEVEL } from '../logger';
import { LogLevel } from '../logger/types';
import { Ffi } from './types';
import { Ffi, FfiLogLevelFilter } from './types';

export const PACT_FFI_VERSION = '0.4.22';

Expand Down Expand Up @@ -85,18 +85,15 @@ const renderBinaryErrorMessage = (error: unknown) => {
};

let ffi: typeof ffiLib;
let ffiLogLevel: LogLevel;

const initialiseFfi = (logLevel: LogLevel): typeof ffi => {
const initialiseFfi = (): typeof ffi => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (process.stdout._handle) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
process.stdout._handle.setBlocking(true);
}
logger.debug(`Initalising native core at log level '${logLevel}'`);
ffiLogLevel = logLevel;
try {
bindingPaths.every((bindingPath, i) => {
try {
Expand All @@ -114,7 +111,6 @@ const initialiseFfi = (logLevel: LogLevel): typeof ffi => {
return true;
}
});
ffiLib.pactffiInitWithLogLevel(logLevel);
} catch (error) {
renderBinaryErrorMessage(error);
throw new Error(
Expand All @@ -125,18 +121,24 @@ const initialiseFfi = (logLevel: LogLevel): typeof ffi => {
};

export const getFfiLib = (
logLevel: LogLevel = DEFAULT_LOG_LEVEL
logLevel: LogLevel = DEFAULT_LOG_LEVEL,
logFile: string | undefined = undefined
): typeof ffi => {
if (!ffi) {
logger.trace('Initiliasing ffi for the first time');
ffi = initialiseFfi(logLevel);
} else {
logger.trace('Ffi has already been initialised, no need to repeat it');
if (logLevel !== ffiLogLevel) {
logger.warn(
`The pact native core has already been initialised at log level '${ffiLogLevel}'`
logger.trace('Initialising ffi for the first time');
ffi = initialiseFfi();
logger.debug(
`Initialising native core at log level '${logLevel}'`,
logFile
);
if (logFile) {
logger.debug(
`writing log file at level ${FfiLogLevelFilter[logLevel]} to ${logFile}`
);
logger.warn(`The new requested log level '${logLevel}' will be ignored`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we missing handling the error in this scenario (somebody initialising the FFI more than once with a different log level)?

const res = ffiLib.pactffiLogToFile(logFile, FfiLogLevelFilter[logLevel]);
logger.debug(`result of writing to file '${res}'`);
} else {
ffiLib.pactffiInitWithLogLevel(logLevel);
}
}
return ffi;
Expand Down
2 changes: 1 addition & 1 deletion src/verifier/nativeVerifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const verify = (opts: VerifierOptions): Promise<string> => {
if (opts.logLevel) {
setLogLevel(opts.logLevel);
}
const ffi = getFfiLib(opts.logLevel);
const ffi = getFfiLib(opts.logLevel, opts.logFile);

const handle = ffi.pactffiVerifierNewForApplication(
pkg.name.split('/')[1],
Expand Down
1 change: 1 addition & 0 deletions src/verifier/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface VerifierOptions {
consumerVersionSelectors?: ConsumerVersionSelector[];
timeout?: number;
logLevel?: LogLevel;
logFile?: string;
disableSslVerification?: boolean;
buildUrl?: string;
customProviderHeaders?: CustomHeaders | string[];
Expand Down
1 change: 1 addition & 0 deletions src/verifier/validateOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ export const validationRules: ArgumentValidationRules<InternalPactVerifierOption
verbose: [deprecatedFunction],
monkeypatch: [deprecatedFunction],
logDir: [deprecatedFunction],
logFile: [assertNonEmptyString],
consumerFilters: [assertNonEmptyString],
failIfNoPactsFound: [assertBoolean],
transports: [],
Expand Down
3 changes: 0 additions & 3 deletions test/consumer.integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import zlib = require('zlib');
import FormData = require('form-data');
import fs = require('fs');
import { load } from 'protobufjs';
import { setLogLevel } from '../src/logger';
import {
ConsumerPact,
makeConsumerPact,
Expand All @@ -21,8 +20,6 @@ const { expect } = chai;
const HOST = '127.0.0.1';

describe('FFI integration test for the HTTP Consumer API', () => {
setLogLevel('trace');

let port: number;
let pact: ConsumerPact;
const bytes: Buffer = zlib.gzipSync('this is an encoded string');
Expand Down
3 changes: 0 additions & 3 deletions test/matt.consumer.integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
makeConsumerMessagePact,
makeConsumerPact,
} from '../src';
import { setLogLevel } from '../src/logger';
import { FfiSpecificationVersion } from '../src/ffi/types';

chai.use(chaiAsPromised);
Expand Down Expand Up @@ -45,8 +44,6 @@ const sendMattMessageTCP = (

const skipPluginTests = process.env['SKIP_PLUGIN_TESTS'] === 'true';
(skipPluginTests ? describe.skip : describe)('MATT protocol test', () => {
setLogLevel('trace');

let provider: ConsumerPact;
let tcpProvider: ConsumerMessagePact;
let port: number;
Expand Down