From 52a5b5bc0aca6d77fddca6ac77e1365dce3538b8 Mon Sep 17 00:00:00 2001 From: Sandwich <299465+dskvr@users.noreply.github.com> Date: Sat, 9 Nov 2024 12:04:51 +0100 Subject: [PATCH 1/6] decouple sampler and add skips to expect --- src/base/Expect.ts | 127 ++++++++++-- src/base/Ingestor.ts | 14 ++ src/base/Sampler.ts | 25 ++- src/base/Suite.ts | 95 ++++++--- src/base/SuiteState.ts | 19 ++ src/base/SuiteTest.ts | 185 ++++++++++-------- src/nips/Nip01/ingestors/AuthorIngestor.ts | 5 +- src/nips/Nip01/ingestors/KindIngestor.ts | 5 +- src/nips/Nip01/ingestors/RangeIngestor.ts | 5 +- src/nips/Nip01/ingestors/SingleTagIngestor.ts | 4 +- src/nips/Nip01/tests/FilterAuthor.ts | 7 +- src/nips/Nip01/tests/FilterKinds.ts | 6 +- src/nips/Nip01/tests/FilterRange.ts | 10 +- src/nips/Nip01/tests/FilterTags.ts | 6 +- src/nips/Nip50/ingestors/ContentIngestor.ts | 7 +- src/utils/string.ts | 8 + 16 files changed, 376 insertions(+), 152 deletions(-) create mode 100644 src/base/SuiteState.ts diff --git a/src/base/Expect.ts b/src/base/Expect.ts index 292c85e..ad28e6d 100644 --- a/src/base/Expect.ts +++ b/src/base/Expect.ts @@ -6,17 +6,31 @@ export interface IAssertWrapOptions { verbose?: boolean; } +export type IExpectResults = IExpectResult[]; + +export type IExpectError = Record + +export type IExpectErrors = IExpectError[] + export interface IExpectResult { + code: string; message: string; pass: boolean; - error?: Record; + skipped: boolean; + error?: IExpectError; +} + +export const defaultExpectResult = { + code: "UNSET", + message: "unset", + pass: false, + skipped: false } export class AssertWrap { - private _result: IExpectResult[] = []; - private _passed: string[] = []; - private _failed: string[] = []; + private _result: IExpectResults = []; private _verbose: boolean = false; + private _skip: boolean = false; private logger = new Logger('@nostrwatch/auditor:AssertWrap', { showTimer: false, showNamespace: false @@ -30,28 +44,44 @@ export class AssertWrap { } } - get result(): IExpectResult[] { + set skip(skip: boolean) { + this._skip = skip; + } + + get skip() { + return this._skip; + } + + private set result(result: IExpectResult) { + this._result.push(result); + } + + get result(): IExpectResults { return this._result; } - private set result(result: IExpectResult) { - this._result.push(result); + get passed(): IExpectResults { + return this.result.filter( result => result.pass ) } - get passed() { - return this._passed; + get skipped(): IExpectResults { + return this.result.filter( result => result.skipped ) } - get failed() { - return this._failed; + get failed(): IExpectResults { + return this.result.filter( result => !result.pass && !result.skipped ) } - get didPass() { - return this._failed.length === 0; + get errors(): IExpectErrors { + return this.failed.map( result => result.error ) + } + + get passing() { + return this.failed.length === 0; } get passRate() { - return Math.round((this._passed.length / (this._passed.length + this._failed.length)) * 100); + return Math.round((this.passed.length / (this.result.length)) * 100); } private extractErrorDetails(error: any) { @@ -62,18 +92,27 @@ export class AssertWrap { private createProxy(assertionFn: (...args: any[]) => void) { return new Proxy((...args: any[]) => assertionFn(...args), { apply: (target, thisArg, argumentsList) => { + let result: IExpectResult = defaultExpectResult; const message = argumentsList[argumentsList.length - 1]; + let pass = false + + if(this.skip) { + result = { ...result, message, skipped: true }; + this.result = result; + return; + } + try { Reflect.apply(target, thisArg, argumentsList); - const result: IExpectResult = { message, pass: true }; - this.result = result; - if(this._verbose) this.logger.custom(`pass`, `${message}`, 3); + pass = true; + result = { ...result, message, pass }; + } catch (error) { error = this.extractErrorDetails(error); - const result: IExpectResult = { message, pass: false, error }; - this.result = result - if(this._verbose) this.logger.custom(`fail`, `${message}`, 3); + result = { ...result, message, pass, error }; } + if(this._verbose) this.logger.custom(pass? `pass`: `fail`, `${message}`, 3); + this.result = result; }, }); } @@ -93,8 +132,54 @@ export class AssertWrap { } export class Expect { - conditions: AssertWrap = new AssertWrap({ verbose: true }) + + readonly keys: Array = ['conditions', 'message', 'json', 'behavior', 'errors'] + + conditions: AssertWrap = new AssertWrap({ verbose: true}) message: AssertWrap = new AssertWrap({ verbose: true }) json: AssertWrap = new AssertWrap({ verbose: true }) behavior: AssertWrap = new AssertWrap({ verbose: true }) +z + get passed(): IExpectResults { + return this.returnKeyAggregate('passed') as IExpectResults + } + + get failed(): IExpectResults { + return this.returnKeyAggregate('failed') as IExpectResults + } + + get skipped(): IExpectResults { + return this.returnKeyAggregate('skipped') as IExpectResults + } + + get results(): IExpectResults { + return this.returnKeyAggregate('result') as IExpectResults + } + + get passrate(): number { + return Math.round( this.passed.length / this.results.length ); + } + + get passing(): boolean { + return this.failed.length === 0; + } + + get errors(): IExpectErrors { + return this.returnKeyAggregate('errors') as IExpectErrors; + } + + skip(keys: (keyof Expect)[] ): void { + for(const key of keys){ + this[key].skip = true; + } + } + + private returnKeyAggregate(key: keyof AssertWrap): IExpectResults | IExpectErrors { + let res = [] + for(const key of this.keys){ + res = [...res, ...(this[key as keyof Expect] as AssertWrap)[key] ] + } + return res; + } + } \ No newline at end of file diff --git a/src/base/Ingestor.ts b/src/base/Ingestor.ts index 6371c46..0fc6476 100644 --- a/src/base/Ingestor.ts +++ b/src/base/Ingestor.ts @@ -4,14 +4,28 @@ import { EventEmitter } from 'tseep'; export abstract class Ingestor { protected signal?: EventEmitter; protected sampleSize: number = 10; + private _completed: boolean = false; + constructor(sampleSize?: number) { if(sampleSize){ this.sampleSize = sampleSize; } } + abstract feed(note: Note): void; abstract poop(): any; + registerSignal(signal: any): void { this.signal = signal; } + + protected complete(): void { + this._completed = true; + } + + async completed(): Promise { + while(!this._completed) { + await new Promise(resolve => setTimeout(resolve, 250)); + } + } } \ No newline at end of file diff --git a/src/base/Sampler.ts b/src/base/Sampler.ts index 861cfbb..42771df 100644 --- a/src/base/Sampler.ts +++ b/src/base/Sampler.ts @@ -20,6 +20,7 @@ export class Sampler { private _abort: boolean = false; private signal = new EventEmitter(); private logger: Logger = new Logger('@nostrwatch/auditor:Sampler'); + private _ingestors: Ingestor[] = []; constructor(ws: WebSocket, maximumSamples?: number, timeout?: number) { this.ws = ws; @@ -27,10 +28,28 @@ export class Sampler { if(timeout) this._timeoutMs = timeout } + get ingestors(): Ingestor[] { + return this._ingestors; + } + + get samplable() { + return this.ingestors.length > 0; + } + + private set ingestor(ingestor: Ingestor) { + this._ingestors.push(ingestor); + } + + async runIngestors(note: Note) { + for(const ingestor of this._ingestors) { + ingestor.feed(note); + } + await Promise.allSettled(this._ingestors.map(ingestor => ingestor.completed())); + this.abort() + } + registerIngestor(ingestor: Ingestor) { - ingestor.registerSignal(this.signal); - this.signal.on('ingestor:abort', this.abort.bind(this)); - this.signal.on('ingest', ingestor.feed.bind(ingestor)); + this.ingestor = ingestor; } setupHandlers() { diff --git a/src/base/Suite.ts b/src/base/Suite.ts index bfdec13..6c81624 100644 --- a/src/base/Suite.ts +++ b/src/base/Suite.ts @@ -14,6 +14,9 @@ import { Expect } from './Expect.js'; import { INip01RelayMessage } from '#src/nips/Nip01/interfaces/INip01RelayMessage.js'; import Logger from './Logger.js'; +import { SuiteState } from './SuiteState.js'; +import { Ingestor } from './Ingestor.js'; +import { Sampler } from './Sampler.js'; export type INipTesterCodes = Record @@ -52,17 +55,21 @@ export interface ISuite { pretest: boolean; testKey: string; data: any; + state: SuiteState; setup(): Promise; ready(): Promise; reset(): void; test(): Promise; - logCode(type: 'behavior' | 'json' | 'message', code: string, result: boolean): void; - getCode(type: 'behavior' | 'json' | 'message', code: string): boolean | null | undefined; + + registerIngestors(ingestors: Ingestor[]): void; + registerIngestor(ingestor: Ingestor): void; + // logCode(type: 'behavior' | 'json' | 'message', code: string, result: boolean): void; + // getCode(type: 'behavior' | 'json' | 'message', code: string): boolean | null | undefined; setupHandlers(): void; validateJson(key: string, json: GenericJson): void; - collectCodes(): Partial; + // collectCodes(): Partial; readonly socket: WebSocket; } @@ -70,10 +77,13 @@ export interface ISuite { export abstract class Suite implements ISuite { private readonly testsDirectory: string = './tests'; private expect: Expect; + private _state: SuiteState = new SuiteState(); private logger: Logger = new Logger('@nostrwatch/auditor:Suite', { showTimer: false, showNamespace: false }); + private _sampler: Sampler; + private _ingestors: Ingestor[] = []; public readonly slug: string = "NipXX"; @@ -90,9 +100,9 @@ export abstract class Suite implements ISuite { readonly behaviorComments: Record = {}; protected tests: string[] = []; - protected messageCodes: INipTesterCodes = {}; - protected jsonCodes: INipTesterCodes = {}; - protected behaviorCodes: INipTesterCodes = {}; + // protected messageCodes: INipTesterCodes = {}; + // protected jsonCodes: INipTesterCodes = {}; + // protected behaviorCodes: INipTesterCodes = {}; protected testers: Record = {}; protected _ready: boolean = false; protected totalEvents: number = 0; @@ -122,6 +132,18 @@ export abstract class Suite implements ISuite { this._messages = messages; } + get state(): SuiteState { + return this._state; + } + + get sampler(): Sampler { + return this._sampler; + } + + private set sampler(sampler: Sampler) { + this._sampler = sampler; + } + async setup(){ this.expect = new Expect(); // this.messages.forEach( key => { @@ -152,19 +174,36 @@ export abstract class Suite implements ISuite { reset(){ this.resetKey(); - this.resetCodes(); + // this.resetCodes(); } private resetKey(){ this.testKey = "unset"; } - private resetCodes(){ - this.messageCodes = {}; - this.jsonCodes = {}; - this.behaviorCodes = {}; + registerIngestors(ingestors: Ingestor[]) { + if(ingestors) { + ingestors.forEach(ingestor => this.registerIngestor(ingestor)); + } + } + + registerIngestor(ingestor: Ingestor) { + if(!this?.sampler) + this.initSampler(); + this.sampler.registerIngestor(ingestor); } + private initSampler(){ + if(this.socket === undefined) throw new Error('socket of Suite must be set'); + this.sampler = new Sampler(this.socket); + } + + // private resetCodes(){ + // this.messageCodes = {}; + // this.jsonCodes = {}; + // this.behaviorCodes = {}; + // } + public async test(): Promise { this.logger.info(`BEGIN: ${this.slug} Suite`, 1); await this.ready(); @@ -190,23 +229,23 @@ export abstract class Suite implements ISuite { return failed.length === 0; } - public logCode(type: ISuiteCodeTypes, plainLanguageCode: string, result: boolean): void { - const code = `${plainLanguageCode.replace(/ /g, "_").toUpperCase()}`; - this[`${type}Codes`][code] = result; - } - - public getCode(type: ISuiteCodeTypes, plainLanguageCode: string): boolean | null | undefined { - const code = `${plainLanguageCode.replace(/ /g, "_").toUpperCase()}`; - return this[`${type}Codes`]?.[code] ?? null; - } - - public collectCodes(): Partial { - return { - messageCodes: this.messageCodes, - jsonCodes: this.jsonCodes, - behaviorCodes: this.behaviorCodes - } - } + // public logCode(type: ISuiteCodeTypes, plainLanguageCode: string, result: boolean): void { + // const code = `${plainLanguageCode.replace(/ /g, "_").toUpperCase()}`; + // this[`${type}Codes`][code] = result; + // } + + // public getCode(type: ISuiteCodeTypes, plainLanguageCode: string): boolean | null | undefined { + // const code = `${plainLanguageCode.replace(/ /g, "_").toUpperCase()}`; + // return this[`${type}Codes`]?.[code] ?? null; + // } + + // public collectCodes(): Partial { + // return { + // messageCodes: this.messageCodes, + // jsonCodes: this.jsonCodes, + // behaviorCodes: this.behaviorCodes + // } + // } setupHandlers(): void { this.socket.off() diff --git a/src/base/SuiteState.ts b/src/base/SuiteState.ts new file mode 100644 index 0000000..d4720b0 --- /dev/null +++ b/src/base/SuiteState.ts @@ -0,0 +1,19 @@ +import { EventEmitter } from "tseep"; + +export class SuiteState { + private state: Map = new Map(); + private emitter: EventEmitter; + + constructor(emitter?: EventEmitter){ + if(!emitter) return; + this.emitter = emitter; + } + + set(key: string, value: any): void { + this.state.set(key, value); + } + + get(key: string): any { + return this.state.get(key); + } +} \ No newline at end of file diff --git a/src/base/SuiteTest.ts b/src/base/SuiteTest.ts index f8497c5..a891fed 100644 --- a/src/base/SuiteTest.ts +++ b/src/base/SuiteTest.ts @@ -12,11 +12,12 @@ import Logger from '#base/Logger.js'; import { Nip01ClientMessageGenerator } from "#src/nips/Nip01/index.js"; import { RelayEventMessage } from "#src/nips/Nip01/interfaces/RelayEventMessage.js"; -import { Expect } from "./Expect.js"; +import { AssertWrap, Expect, IExpectErrors, IExpectResult, IExpectResults } from "./Expect.js"; import { INip01Filter } from "#src/nips/Nip01/interfaces/Filter.js"; import { Note } from "#src/nips/Nip01/interfaces/Note.js"; import chalk from "chalk"; +import { SuiteState } from "./SuiteState.js"; export type CompleteOnType = "off" | "maxEvents" | "EOSE"; export type CompleteOnTypeArray = [CompleteOnType, ...CompleteOnType[]]; @@ -34,32 +35,28 @@ export interface ISuiteTest { data: any; run(): any; _onMessageEvent(message: RelayEventMessage): boolean; + test(methods: Expect): void; + precheck(conditions: AssertWrap): void; } export interface ISuiteTestResult { testKey: string; - pass: boolean; + passing: boolean; passrate: number; - reason: string; - passed: string[]; - failed: string[]; + passed: IExpectResults; + failed: IExpectResults; notices: string[]; - messageCodes: Record; - jsonCodes: Record; - behaviorCodes: Record; + errors: IExpectErrors; } export const defaultSuiteTestResult: ISuiteTestResult = { testKey: "unset", - pass: false, - reason: "", + passing: false, passrate: 0, passed: [], failed: [], notices: [], - messageCodes: {}, - jsonCodes: {}, - behaviorCodes: {} + errors: [] } export abstract class SuiteTest implements ISuiteTest { @@ -89,9 +86,8 @@ export abstract class SuiteTest implements ISuiteTest { totalEvents: number = 0; completeOn: CompleteOnTypeArray = ['maxEvents', 'EOSE']; - constructor(suite: ISuite, ingestor?: Ingestor) { + constructor(suite: ISuite) { this.suite = suite; - if(ingestor) this.registerIngestor(ingestor); this.logger.registerLogger('pass', 'info', chalk.green.bold); this.logger.registerLogger('fail', 'info', chalk.redBright.bold); } @@ -104,20 +100,47 @@ export abstract class SuiteTest implements ISuiteTest { return this.suite.socket; } + get state(): SuiteState { + return this.suite.state; + } + protected get expect(): Expect { return this._expect; } - registerIngestor(ingestor: Ingestor) { - this.ingestor = ingestor; - this.sampler = new Sampler(this.suite.socket); - this.sampler.registerIngestor(this.ingestor); + suiteIngest(ingestor: Ingestor[] | Ingestor) { + if(Array.isArray(ingestor)) { + this.suite.registerIngestors(ingestor); + } + else { + this.suite.registerIngestor(ingestor); + } + } + + suiteTestIngest(ingestor: Ingestor[] | Ingestor) { + if(Array.isArray(ingestor)) { + this.registerIngestors(ingestor); + } + else { + this.registerIngestor(ingestor); + } + } + + private registerIngestors(ingestors: Ingestor[]) { + if(ingestors) { + ingestors.forEach(ingestor => this.registerIngestor(ingestor)); + } } - initSampler(ingestor: Ingestor){ + private registerIngestor(ingestor: Ingestor) { + if(!this?.sampler) + this.initSampler(); + this.sampler.registerIngestor(ingestor); + } + + initSampler(){ if(this.suite.socket === undefined) throw new Error('socket of Suite must be set'); this.sampler = new Sampler(this.suite.socket); - this.sampler.registerIngestor(ingestor); } EVENT(event: Note) { @@ -138,6 +161,8 @@ export abstract class SuiteTest implements ISuiteTest { }; } + async screen(conditions: AssertWrap): Promise {} + async prepare() { this.REQ(this.filters) await this.testable(); @@ -145,7 +170,8 @@ export abstract class SuiteTest implements ISuiteTest { async run() { this.logger.info(`BEGIN: ${this.slug}`, 2); - if(this.sampler !== undefined) { + + if(this?.sampler?.samplable) { await this.sampler.sample(); } @@ -161,19 +187,20 @@ export abstract class SuiteTest implements ISuiteTest { if(this.slug === 'unset') throw new Error('slug of SuiteTest must be set'); this.timeoutBegin(); + await this.screen(this.expect.conditions) + this.state.set('okConditions', this.expect.conditions.passed); await this.prepare(); this.finish(); return this.resulter.result } - public logCode(type: ISuiteCodeTypes, plainLanguageCode: string, result: boolean): void { - //console.log(type, plainLanguageCode, result); - this.suite.logCode(type, plainLanguageCode, result); - } + // public logCode(type: ISuiteCodeTypes, plainLanguageCode: string, result: boolean): void { + // this.suite.logCode(type, plainLanguageCode, result); + // } - public getCode(type: ISuiteCodeTypes, plainLanguageCode: string): boolean | null | undefined { - return this.suite.getCode(type, plainLanguageCode); - } + // public getCode(type: ISuiteCodeTypes, plainLanguageCode: string): boolean | null | undefined { + // return this.suite.getCode(type, plainLanguageCode); + // } protected newSubId() { this.subId = generateSubId() @@ -199,72 +226,72 @@ export abstract class SuiteTest implements ISuiteTest { private finish(): void { this.logger.debug(`testKey: ${this.suite.testKey}`, 2); - const codes = this.suite.collectCodes(); - const passed = this.passed(codes); - const failed = this.failed(codes); - const pass = failed.length === 0; + // const codes = this.suite.collectCodes(); + const { passed, failed, passing, errors } = this.expect; const passrate = passed.length / (passed.length + failed.length); - const reason = this.reason(codes); const notices = this.notices; const result = { testKey: this.suite.testKey, - pass, + passing, passrate, - reason, passed, failed, notices, - ...codes + errors } as ISuiteTestResult; - this.logger.custom(pass? 'pass': 'fail', `${this.slug}`, 2); + this.logger.custom(passed? 'pass': 'fail', `${this.slug}`, 2); this.resulter.set(result as ISuiteTestResult); } - evaluate(codes: Partial): boolean { - const { messageCodes, jsonCodes, behaviorCodes } = codes as ISuiteTestResult; + passed(): void { + + } + + // evaluate(codes: Partial): boolean { + // const { messageCodes, jsonCodes, behaviorCodes } = codes as ISuiteTestResult; - const allEmpty = !Object.keys(this.expect.behavior).length && - !Object.keys(this.expect.json).length && - !Object.keys(this.expect.message).length + // const allEmpty = !Object.keys(this.expect.behavior).length && + // !Object.keys(this.expect.json).length && + // !Object.keys(this.expect.message).length - if (allEmpty) return false; + // if (allEmpty) return false; - const messagePass = Object.values(messageCodes).every(code => code === true); - const jsonPass = Object.values(jsonCodes).every(code => code === true); - const behaviorPass = Object.values(behaviorCodes).every(code => code === true); + // const messagePass = Object.values(messageCodes).every(code => code === true); + // const jsonPass = Object.values(jsonCodes).every(code => code === true); + // const behaviorPass = Object.values(behaviorCodes).every(code => code === true); - return messagePass && jsonPass && behaviorPass; - } - - reason(codes: Partial): string { - const { messageCodes, jsonCodes, behaviorCodes } = codes as ISuiteTestResult; - const failedMessages = Object.entries(messageCodes).filter( ([_, code]) => code === false); - const failedJsons = Object.entries(jsonCodes).filter( ([_, code]) => code === false); - const failedBehaviors = Object.entries(behaviorCodes).filter( ([_, code]) => code === false); - const failed = [...failedMessages, ...failedJsons, ...failedBehaviors]; - if(failed.length === 0) return 'all good 🤙'; - return failed.map( ([key, _]) => key).join(', ').toLowerCase().replace(/_/g, ' '); - } - - private passed(codes: Partial): string[] { - const { messageCodes, jsonCodes, behaviorCodes } = codes as ISuiteTestResult; - const passedMessages = Object.entries(messageCodes).filter( ([_, code]) => code === true); - const passedJsons = Object.entries(jsonCodes).filter( ([_, code]) => code === true); - const passedBehaviors = Object.entries(behaviorCodes).filter( ([_, code]) => code === true); - const passed = [...passedMessages, ...passedJsons, ...passedBehaviors]; - return passed.map( ([key, _]) => key); - } - - private failed(codes: Partial): string[] { - const { messageCodes, jsonCodes, behaviorCodes } = codes as ISuiteTestResult; - const failedMessages = Object.entries(messageCodes).filter( ([_, code]) => code === false); - const failedJsons = Object.entries(jsonCodes).filter( ([_, code]) => code === false); - const failedBehaviors = Object.entries(behaviorCodes).filter( ([_, code]) => code === false); - const failed = [...failedMessages, ...failedJsons, ...failedBehaviors]; - return failed.map( ([key, _]) => key); - } + // return messagePass && jsonPass && behaviorPass; + // } + + // reason(codes: Partial): string { + // const { messageCodes, jsonCodes, behaviorCodes } = codes as ISuiteTestResult; + // const failedMessages = Object.entries(messageCodes).filter( ([_, code]) => code === false); + // const failedJsons = Object.entries(jsonCodes).filter( ([_, code]) => code === false); + // const failedBehaviors = Object.entries(behaviorCodes).filter( ([_, code]) => code === false); + // const failed = [...failedMessages, ...failedJsons, ...failedBehaviors]; + // if(failed.length === 0) return 'all good 🤙'; + // return failed.map( ([key, _]) => key).join(', ').toLowerCase().replace(/_/g, ' '); + // } + + // private passed(codes: Partial): string[] { + // const { messageCodes, jsonCodes, behaviorCodes } = codes as ISuiteTestResult; + // const passedMessages = Object.entries(messageCodes).filter( ([_, code]) => code === true); + // const passedJsons = Object.entries(jsonCodes).filter( ([_, code]) => code === true); + // const passedBehaviors = Object.entries(behaviorCodes).filter( ([_, code]) => code === true); + // const passed = [...passedMessages, ...passedJsons, ...passedBehaviors]; + // return passed.map( ([key, _]) => key); + // } + + // private failed(codes: Partial): string[] { + // const { messageCodes, jsonCodes, behaviorCodes } = codes as ISuiteTestResult; + // const failedMessages = Object.entries(messageCodes).filter( ([_, code]) => code === false); + // const failedJsons = Object.entries(jsonCodes).filter( ([_, code]) => code === false); + // const failedBehaviors = Object.entries(behaviorCodes).filter( ([_, code]) => code === false); + // const failed = [...failedMessages, ...failedJsons, ...failedBehaviors]; + // return failed.map( ([key, _]) => key); + // } abort() { this.socket.terminate(); @@ -275,6 +302,10 @@ export abstract class SuiteTest implements ISuiteTest { this.notices.push(notice); } + precheck(conditions: AssertWrap){ + this.logger.warn(`${this.slug} precheck method was not implemented.`, 1); + } + test(methods: Expect) { this.logger.warn(`${this.slug} complete method was not implemented.`, 1); } diff --git a/src/nips/Nip01/ingestors/AuthorIngestor.ts b/src/nips/Nip01/ingestors/AuthorIngestor.ts index 540be1c..d7548ba 100644 --- a/src/nips/Nip01/ingestors/AuthorIngestor.ts +++ b/src/nips/Nip01/ingestors/AuthorIngestor.ts @@ -7,9 +7,8 @@ export class AuthorIngestor extends Ingestor { feed(note: Note): void { if(!this?.signal) throw new Error('Ingestor not registered with signal'); this.authors.add(note.pubkey); - if(this.authors.size >= this.sampleSize) { - this.signal.emit('ingestor:abort'); - } + if(this.authors.size >= this.sampleSize) + this.complete(); } poop(): string[] { diff --git a/src/nips/Nip01/ingestors/KindIngestor.ts b/src/nips/Nip01/ingestors/KindIngestor.ts index ccdf746..123806e 100644 --- a/src/nips/Nip01/ingestors/KindIngestor.ts +++ b/src/nips/Nip01/ingestors/KindIngestor.ts @@ -7,9 +7,8 @@ export class KindIngestor extends Ingestor { feed(note: Note): void { if(!this?.signal) throw new Error('Ingestor not registered with signal'); this.kinds.add(note.kind); - if(this.kinds.size >= this.sampleSize) { - this.signal.emit('ingestor:abort'); - } + if(this.kinds.size < this.sampleSize) return + this.complete(); } poop(): number[] { diff --git a/src/nips/Nip01/ingestors/RangeIngestor.ts b/src/nips/Nip01/ingestors/RangeIngestor.ts index 8111f3d..00bb77d 100644 --- a/src/nips/Nip01/ingestors/RangeIngestor.ts +++ b/src/nips/Nip01/ingestors/RangeIngestor.ts @@ -7,9 +7,8 @@ export class RangeIngestor extends Ingestor { feed(note: Note): void { if(!this?.signal) throw new Error('Ingestor not registered with signal'); this.timestamps.add(note.created_at); - if(this.timestamps.size >= this.sampleSize) { - this.signal.emit('ingestor:abort'); - } + if(this.timestamps.size >= this.sampleSize) + this.complete(); } poop(): number[] { diff --git a/src/nips/Nip01/ingestors/SingleTagIngestor.ts b/src/nips/Nip01/ingestors/SingleTagIngestor.ts index 8c6d3d3..c7cfe4c 100644 --- a/src/nips/Nip01/ingestors/SingleTagIngestor.ts +++ b/src/nips/Nip01/ingestors/SingleTagIngestor.ts @@ -19,9 +19,9 @@ export class SingleTagIngestor extends Ingestor { } if (singleLetterTags.length > 0) { this.tag = singleLetterTags[0]; - this.signal.emit('ingestor:abort'); + this.complete(); } -} + } poop(): string[] { return this.tag; diff --git a/src/nips/Nip01/tests/FilterAuthor.ts b/src/nips/Nip01/tests/FilterAuthor.ts index 6024587..a21c269 100644 --- a/src/nips/Nip01/tests/FilterAuthor.ts +++ b/src/nips/Nip01/tests/FilterAuthor.ts @@ -4,6 +4,7 @@ import { ISuite } from '#base/Suite.js'; import { INip01Filter, Note, RelayEventMessage } from '../interfaces/index.js'; import { is64CharHex } from '#src/utils/nostr.js'; import { AuthorIngestor } from '../ingestors/AuthorIngestor.js'; +import { AssertWrap } from '#src/base/Expect.js'; export class FilterAuthor extends SuiteTest implements ISuiteTest { readonly slug: string = 'FilterAuthor'; @@ -29,10 +30,12 @@ export class FilterAuthor extends SuiteTest implements ISuiteTest { this.authorsReturned.push(note.pubkey); } - test({behavior, conditions}){ + precheck(conditions: AssertWrap){ conditions.toBeOk(typeof this.author === 'string', 'sampled data is sufficient for test'); - conditions.toBeOk(is64CharHex(this.author), 'author pubkey looks valid'); + conditions.toBeOk(is64CharHex(this.author), 'author hex pubkey looks valid'); + } + test({behavior}){ const returnedNum = this.authorsReturned.length const returnedAtLeastOne = returnedNum > 0; const returnedOnlyFromAuthor = this.authorsReturned.every(author => author === this.author); diff --git a/src/nips/Nip01/tests/FilterKinds.ts b/src/nips/Nip01/tests/FilterKinds.ts index 927de68..e04abe1 100644 --- a/src/nips/Nip01/tests/FilterKinds.ts +++ b/src/nips/Nip01/tests/FilterKinds.ts @@ -6,6 +6,7 @@ import { ISuite } from '#base/Suite.js'; import { Nip01ClientMessageGenerator } from '../index.js'; import { INip01Filter, Note, RelayEventMessage } from '../interfaces/index.js'; import { KindIngestor } from "../ingestors/KindIngestor.js"; +import { AssertWrap } from "#src/base/Expect.js"; export class FilterKinds extends SuiteTest implements ISuiteTest { readonly slug: string = 'FilterKinds'; @@ -27,8 +28,11 @@ export class FilterKinds extends SuiteTest implements ISuiteTest { this.kindsReturned.push(note.kind); } - test({behavior, conditions}){ + precheck(conditions: AssertWrap){ conditions.toBeOk(this.kindsReturned.length > 0, 'sample data size is sufficient for test'); + } + + test({behavior}){ const moreThanZero = this.kindsReturned.length > 0 const returnedOnlyEventKinds = this.kindsReturned.every((item: number) => this.ingestor.poop().includes(item)); behavior.toBeOk(moreThanZero, 'returned at least one event'); diff --git a/src/nips/Nip01/tests/FilterRange.ts b/src/nips/Nip01/tests/FilterRange.ts index 24c44e5..5d69cd5 100644 --- a/src/nips/Nip01/tests/FilterRange.ts +++ b/src/nips/Nip01/tests/FilterRange.ts @@ -4,6 +4,7 @@ import { ISuite } from '#base/Suite.js'; ; import { INip01Filter, RelayEventMessage } from '../interfaces/index.js'; import { RangeIngestor } from "../ingestors/RangeIngestor.js"; +import { AssertWrap } from '#src/base/Expect.js'; export class FilterRange extends SuiteTest implements ISuiteTest { readonly slug: string = 'FilterRange'; @@ -28,15 +29,16 @@ export class FilterRange extends SuiteTest implements ISuiteTest { this.timestampsReturned.push(note.created_at); } - test({behavior, conditions}){ + precheck(conditions: AssertWrap){ const sampleSufficient = this?.range?.since && this?.range?.until && this.range.since != this.range.until conditions.toBeOk(this?.range?.since && this?.range?.until && this.range.since != this.range.until, 'sample data to be sufficient') + } + + test({behavior}){ behavior.toEqual(this.timestampsReturned.length, this.limit, `returned number of events requested`); behavior.toBeOk(this.timestampsReturned.length > 0, 'returned at least one event'); - if(sampleSufficient) { - behavior.toBeOk(this.withinRange(), 'return only events within range') - } + behavior.toBeOk(this.withinRange(), 'return only events within range') } private withinRange(): boolean { diff --git a/src/nips/Nip01/tests/FilterTags.ts b/src/nips/Nip01/tests/FilterTags.ts index 98d4909..23a6cfe 100644 --- a/src/nips/Nip01/tests/FilterTags.ts +++ b/src/nips/Nip01/tests/FilterTags.ts @@ -4,6 +4,7 @@ import { ISuite } from '#base/Suite.js'; import { INip01Filter, Note, RelayEventMessage } from '../interfaces/index.js'; import { SingleTagIngestor } from "../ingestors/SingleTagIngestor.js"; import { truncate } from "#src/utils/string.js"; +import { AssertWrap } from '#src/base/Expect.js'; export class FilterTags extends SuiteTest implements ISuiteTest { readonly slug: string = 'FilterTags'; @@ -30,8 +31,11 @@ export class FilterTags extends SuiteTest implements ISuiteTest { tags.filter(tag => tag[0].length === 1).forEach(tag => this.singleLetterTagsReturned.push(tag)) } - test({behavior, conditions}){ + precheck(conditions: AssertWrap): void { conditions.toBeOk(this.singleLetterTagsReturned.length > 0, 'sample data size is sufficient for test'); + } + + test({behavior}){ const numTagsReturned = this.singleLetterTagsReturned.length const returnedOnlyTagsRequested = this.singleLetterTagsReturned.some((item: string[]) => { const key = this.ingestor.poop()[0] diff --git a/src/nips/Nip50/ingestors/ContentIngestor.ts b/src/nips/Nip50/ingestors/ContentIngestor.ts index 872e103..f4aca9d 100644 --- a/src/nips/Nip50/ingestors/ContentIngestor.ts +++ b/src/nips/Nip50/ingestors/ContentIngestor.ts @@ -16,15 +16,14 @@ export class ContentIngestor extends Ingestor { if(!isNaturalLanguage(note.content)) return; let term = null; let tries = 0; - while(term === null && tries < 10){ + while(term === null && tries < 21){ const word = this.getRandomWord(note.content, 4, 12); if(word) term = word; tries++; } if(term !== null) this.searches.add(term); - if(this.searches.size >= this.sampleSize) { - this.signal.emit('ingestor:abort'); - } + if(this.searches.size >= this.sampleSize) + this.complete(); } poop(): string[] { diff --git a/src/utils/string.ts b/src/utils/string.ts index bb0414f..ca608e2 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -7,4 +7,12 @@ export function truncate(str: string, maxLength: number = 64): string { return str; } return str.slice(0, maxLength - 3) + '...'; +} + +export function toCode(message: string): string { + return message.toUpperCase().replace(/ /g, "_") +} + +export function fromCode(message: string): string { + return message.toLowerCase().replace(/_/g, ' ') } \ No newline at end of file From 809d3c0176c582ca9dd7bb177030992d778dc163 Mon Sep 17 00:00:00 2001 From: Sandwich <299465+dskvr@users.noreply.github.com> Date: Sat, 9 Nov 2024 12:24:45 +0100 Subject: [PATCH 2/6] update ingestor init --- src/base/Ingestor.ts | 9 +++++++++ src/base/Suite.ts | 30 +++++++++++++++++++++++----- src/base/SuiteState.ts | 10 ++++++---- src/base/SuiteTest.ts | 10 +++++++--- src/nips/Nip01/tests/FilterAuthor.ts | 2 +- src/nips/Nip01/tests/FilterRange.ts | 2 +- src/nips/Nip01/tests/FilterTags.ts | 2 +- 7 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/base/Ingestor.ts b/src/base/Ingestor.ts index 0fc6476..9d87102 100644 --- a/src/base/Ingestor.ts +++ b/src/base/Ingestor.ts @@ -5,12 +5,21 @@ export abstract class Ingestor { protected signal?: EventEmitter; protected sampleSize: number = 10; private _completed: boolean = false; + private _parent?: string; constructor(sampleSize?: number) { if(sampleSize){ this.sampleSize = sampleSize; } } + + get parent(): string { + return this._parent; + } + + set belongsTo(parent: string) { + this._parent = parent; + } abstract feed(note: Note): void; abstract poop(): any; diff --git a/src/base/Suite.ts b/src/base/Suite.ts index 6c81624..679cb1f 100644 --- a/src/base/Suite.ts +++ b/src/base/Suite.ts @@ -18,6 +18,8 @@ import { SuiteState } from './SuiteState.js'; import { Ingestor } from './Ingestor.js'; import { Sampler } from './Sampler.js'; +export type ISuiteSampleData = Record; + export type INipTesterCodes = Record export type GenericJson = Record @@ -62,8 +64,8 @@ export interface ISuite { reset(): void; test(): Promise; - registerIngestors(ingestors: Ingestor[]): void; - registerIngestor(ingestor: Ingestor): void; + registerIngestors(testSlug: string, ingestors: Ingestor[]): void; + registerIngestor(testSlug: string, ingestor: Ingestor): void; // logCode(type: 'behavior' | 'json' | 'message', code: string, result: boolean): void; // getCode(type: 'behavior' | 'json' | 'message', code: string): boolean | null | undefined; setupHandlers(): void; @@ -181,15 +183,18 @@ export abstract class Suite implements ISuite { this.testKey = "unset"; } - registerIngestors(ingestors: Ingestor[]) { + registerIngestors(testSlug: string, ingestors: Ingestor[]) { if(ingestors) { - ingestors.forEach(ingestor => this.registerIngestor(ingestor)); + ingestors.forEach(ingestor => { + this.registerIngestor(testSlug, ingestor) + }); } } - registerIngestor(ingestor: Ingestor) { + registerIngestor(testSlug: string, ingestor: Ingestor) { if(!this?.sampler) this.initSampler(); + ingestor.belongsTo = testSlug; this.sampler.registerIngestor(ingestor); } @@ -198,6 +203,15 @@ export abstract class Suite implements ISuite { this.sampler = new Sampler(this.socket); } + private toilet(){ + const poops: ISuiteSampleData = {}; + for(const ingestor of this._ingestors) { + const testKey = ingestor.parent; + poops[testKey] = ingestor.poop(); + } + this.state.set('samples', poops); + } + // private resetCodes(){ // this.messageCodes = {}; // this.jsonCodes = {}; @@ -206,7 +220,13 @@ export abstract class Suite implements ISuite { public async test(): Promise { this.logger.info(`BEGIN: ${this.slug} Suite`, 1); + await this.ready(); + if(this?.sampler?.samplable) { + await this.sampler.sample(); + this.toilet(); + } + for(const test of Object.entries(this.testers)) { const [testName, suiteTest] = test; const results = await suiteTest.run(); diff --git a/src/base/SuiteState.ts b/src/base/SuiteState.ts index d4720b0..8917163 100644 --- a/src/base/SuiteState.ts +++ b/src/base/SuiteState.ts @@ -1,7 +1,9 @@ import { EventEmitter } from "tseep"; +export type ISuiteState = Map + export class SuiteState { - private state: Map = new Map(); + private state: ISuiteState = new Map(); private emitter: EventEmitter; constructor(emitter?: EventEmitter){ @@ -9,11 +11,11 @@ export class SuiteState { this.emitter = emitter; } - set(key: string, value: any): void { + set(key: string, value: T): void { this.state.set(key, value); } - get(key: string): any { - return this.state.get(key); + get(key: string ): T | undefined { + return this.state.get(key) ?? undefined; } } \ No newline at end of file diff --git a/src/base/SuiteTest.ts b/src/base/SuiteTest.ts index a891fed..f65c673 100644 --- a/src/base/SuiteTest.ts +++ b/src/base/SuiteTest.ts @@ -3,7 +3,7 @@ import { SuiteTestResulter } from "#base/Resulter.js"; import { Sampler } from "#base/Sampler.js"; import { Ingestor } from "#base/Ingestor.js"; -import type { ISuite } from "#base/Suite.js"; +import type { ISuite, ISuiteSampleData } from "#base/Suite.js"; import { generateSubId } from "#src/utils/nostr.js"; import { ISuiteCodeTypes } from "./Suite.js"; import { WebSocketWrapper as WebSocket } from "./WebSocketWrapper.js"; @@ -104,16 +104,20 @@ export abstract class SuiteTest implements ISuiteTest { return this.suite.state; } + get samples(): ISuiteSampleData { + return this.state.get('samples'); + } + protected get expect(): Expect { return this._expect; } suiteIngest(ingestor: Ingestor[] | Ingestor) { if(Array.isArray(ingestor)) { - this.suite.registerIngestors(ingestor); + this.suite.registerIngestors(this.slug, ingestor); } else { - this.suite.registerIngestor(ingestor); + this.suite.registerIngestor(this.slug, ingestor); } } diff --git a/src/nips/Nip01/tests/FilterAuthor.ts b/src/nips/Nip01/tests/FilterAuthor.ts index a21c269..7172161 100644 --- a/src/nips/Nip01/tests/FilterAuthor.ts +++ b/src/nips/Nip01/tests/FilterAuthor.ts @@ -16,7 +16,7 @@ export class FilterAuthor extends SuiteTest implements ISuiteTest { constructor(suite: ISuite) { super(suite); - this.registerIngestor(new AuthorIngestor(1)); + this.suiteIngest(new AuthorIngestor(1)); } get filters(): INip01Filter[] { diff --git a/src/nips/Nip01/tests/FilterRange.ts b/src/nips/Nip01/tests/FilterRange.ts index 5d69cd5..823ccf1 100644 --- a/src/nips/Nip01/tests/FilterRange.ts +++ b/src/nips/Nip01/tests/FilterRange.ts @@ -16,7 +16,7 @@ export class FilterRange extends SuiteTest implements ISuiteTest { constructor(suite: ISuite) { super(suite); - this.registerIngestor(new RangeIngestor(30)); + this.suiteIngest(new RangeIngestor(30)); } get filters(): INip01Filter[] { diff --git a/src/nips/Nip01/tests/FilterTags.ts b/src/nips/Nip01/tests/FilterTags.ts index 23a6cfe..a6756df 100644 --- a/src/nips/Nip01/tests/FilterTags.ts +++ b/src/nips/Nip01/tests/FilterTags.ts @@ -16,7 +16,7 @@ export class FilterTags extends SuiteTest implements ISuiteTest { constructor(suite: ISuite) { super(suite); - this.registerIngestor(new SingleTagIngestor(1)); + this.suiteIngest(new SingleTagIngestor(1)); } get filters(): INip01Filter[] { From d23bf80eb07a74f2322a15545a79a3316f46ac20 Mon Sep 17 00:00:00 2001 From: Sandwich <299465+dskvr@users.noreply.github.com> Date: Sat, 9 Nov 2024 12:24:53 +0100 Subject: [PATCH 3/6] update ingestor init --- src/nips/Nip01/tests/FilterKinds.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nips/Nip01/tests/FilterKinds.ts b/src/nips/Nip01/tests/FilterKinds.ts index e04abe1..cd4fda9 100644 --- a/src/nips/Nip01/tests/FilterKinds.ts +++ b/src/nips/Nip01/tests/FilterKinds.ts @@ -16,7 +16,7 @@ export class FilterKinds extends SuiteTest implements ISuiteTest { constructor(suite: ISuite) { super(suite); - this.registerIngestor(new KindIngestor(1)); + this.suiteIngest(new KindIngestor(1)); } get filters(): INip01Filter[] { From e1fb80385f38736e4d019f19cf11b39d73154a67 Mon Sep 17 00:00:00 2001 From: Sandwich <299465+dskvr@users.noreply.github.com> Date: Sat, 9 Nov 2024 15:02:17 +0100 Subject: [PATCH 4/6] sampler in Suite works --- src/base/Expect.ts | 19 +++++-- src/base/Sampler.ts | 13 +++-- src/base/Suite.ts | 26 ++++------ src/base/SuiteState.ts | 28 +++++++++++ src/base/SuiteTest.ts | 46 +++++++++-------- src/base/WebSocketWrapper.ts | 1 - src/nips/Nip01/index.ts | 38 -------------- src/nips/Nip01/ingestors/AuthorIngestor.ts | 2 +- src/nips/Nip01/ingestors/KindIngestor.ts | 1 - src/nips/Nip01/ingestors/RangeIngestor.ts | 1 - src/nips/Nip01/ingestors/SingleTagIngestor.ts | 2 - src/nips/Nip01/interfaces/index.ts | 5 +- src/nips/Nip01/schemata/note.schema.json | 5 +- src/nips/Nip01/tests/FilterAuthor.ts | 16 +++--- src/nips/Nip01/tests/FilterKinds.ts | 10 ++-- src/nips/Nip01/tests/FilterMulti.ts | 1 - src/nips/Nip01/tests/FilterRange.ts | 16 ++++-- src/nips/Nip01/tests/FilterTags.ts | 23 +++++---- src/nips/Nip01/utils/generators.ts | 50 +++++++++++++++++++ src/nips/Nip11/ingestors/ContentIngestor.ts | 1 - src/nips/Nip11/tests/ValidateSchema.ts | 4 +- src/nips/Nip50/ingestors/ContentIngestor.ts | 7 --- src/nips/Nip50/tests/Search.ts | 2 +- 23 files changed, 188 insertions(+), 129 deletions(-) create mode 100644 src/nips/Nip01/utils/generators.ts diff --git a/src/base/Expect.ts b/src/base/Expect.ts index ad28e6d..bc8c629 100644 --- a/src/base/Expect.ts +++ b/src/base/Expect.ts @@ -133,7 +133,7 @@ export class AssertWrap { export class Expect { - readonly keys: Array = ['conditions', 'message', 'json', 'behavior', 'errors'] + readonly keys: Array = ['conditions', 'message', 'json', 'behavior'] conditions: AssertWrap = new AssertWrap({ verbose: true}) message: AssertWrap = new AssertWrap({ verbose: true }) @@ -168,16 +168,27 @@ z return this.returnKeyAggregate('errors') as IExpectErrors; } - skip(keys: (keyof Expect)[] ): void { + evaluateConditions(skip: boolean = false): boolean { + if(this.conditions.passing) return true; + if(skip) this.skip(['behavior']) + } + + private skip(keys: (keyof Expect)[] ): void { for(const key of keys){ this[key].skip = true; } } private returnKeyAggregate(key: keyof AssertWrap): IExpectResults | IExpectErrors { + // console.log(`returnKeyAggregate: ${key}`) let res = [] - for(const key of this.keys){ - res = [...res, ...(this[key as keyof Expect] as AssertWrap)[key] ] + for(const expectKey of this.keys){ + const arr = (this[expectKey as keyof Expect] as AssertWrap)[key] + if(!(arr instanceof Array)) { + console.log(`returnKeyAggregate: this[${expectKey}][${key}] is not an array`) + continue; + } + res = [...res, ...arr] } return res; } diff --git a/src/base/Sampler.ts b/src/base/Sampler.ts index 42771df..208bdec 100644 --- a/src/base/Sampler.ts +++ b/src/base/Sampler.ts @@ -1,15 +1,13 @@ -import type { WebSocketWrapper as WebSocket } from './WebSocketWrapper.js'; - import { EventEmitter } from "tseep"; -import { Ingestor } from "./Ingestor.js"; +import { Ingestor } from "#base/Ingestor.js"; +import Logger from "#base/Logger.js"; +import type { WebSocketWrapper as WebSocket } from '#base/WebSocketWrapper.js'; -import { Nip01ClientMessageGenerator } from "#src/nips/Nip01/index.js"; +import { Nip01ClientMessageGenerator } from "#src/nips/Nip01/utils/generators.js"; import type { Note, RelayEventMessage } from "#src/nips/Nip01/interfaces/index.js"; import { generateSubId } from "#utils/nostr.js"; -import Logger from "#base/Logger.js"; - export class Sampler { private ws: WebSocket; private subId: string = "test"; @@ -60,7 +58,8 @@ export class Sampler { case 'EVENT': { const note = (message as RelayEventMessage)[2] as Note; this._totalSamples++; - this.signal.emit('ingest', note); + // this.signal.emit('ingest', note); + this.runIngestors(note); break; } case 'EOSE': { diff --git a/src/base/Suite.ts b/src/base/Suite.ts index 679cb1f..5dbe323 100644 --- a/src/base/Suite.ts +++ b/src/base/Suite.ts @@ -11,7 +11,7 @@ import type { ISuiteTest, ISuiteTestResult } from "./SuiteTest.js"; import { capitalize, truncate } from '#utils/string.js'; import { Expect } from './Expect.js'; -import { INip01RelayMessage } from '#src/nips/Nip01/interfaces/INip01RelayMessage.js'; +import type { INip01RelayMessage } from '#src/nips/Nip01/interfaces/INip01RelayMessage.js'; import Logger from './Logger.js'; import { SuiteState } from './SuiteState.js'; @@ -51,7 +51,6 @@ export interface ISuite { readonly jsonValidators: Record>; // readonly jsons: string[]; // readonly behaviors: string[]; - readonly behaviorComments: Record; readonly requires: string[]; pretest: boolean; @@ -100,7 +99,6 @@ export abstract class Suite implements ISuite { // jsons: string[] = []; // behaviors: string[] = []; - readonly behaviorComments: Record = {}; protected tests: string[] = []; // protected messageCodes: INipTesterCodes = {}; // protected jsonCodes: INipTesterCodes = {}; @@ -146,20 +144,12 @@ export abstract class Suite implements ISuite { this._sampler = sampler; } + get ingestors(): Ingestor[] { + return this.sampler.ingestors + } + async setup(){ this.expect = new Expect(); - // this.messages.forEach( key => { - // this.messageCodes[key] = null; - // }) - - // this.jsons.forEach( key => { - // this.jsonCodes[key] = null; - // }) - - // this.behaviors.forEach( key => { - // this.behaviorCodes[key] = null; - // this.behaviorComments[key] = []; - // }) const tests: DynamicallyImportedNipTests = await import(this.testsDirectory); for (const [key, cl] of Object.entries(tests)) { @@ -192,6 +182,7 @@ export abstract class Suite implements ISuite { } registerIngestor(testSlug: string, ingestor: Ingestor) { + console.log(`registering ingestor for ${testSlug}`); if(!this?.sampler) this.initSampler(); ingestor.belongsTo = testSlug; @@ -204,8 +195,10 @@ export abstract class Suite implements ISuite { } private toilet(){ + console.log(`flushing toilet ${this.ingestors.length}`); const poops: ISuiteSampleData = {}; - for(const ingestor of this._ingestors) { + for(const ingestor of this.ingestors) { + console.log('flushing poop', ingestor.parent, ingestor.poop()); const testKey = ingestor.parent; poops[testKey] = ingestor.poop(); } @@ -230,6 +223,7 @@ export abstract class Suite implements ISuite { for(const test of Object.entries(this.testers)) { const [testName, suiteTest] = test; const results = await suiteTest.run(); + console.log(results) this.resulter.set('tests', testName, results); if(suiteTest?.data !== null) { this.resulter.set('data', { [testName]: suiteTest.data }); diff --git a/src/base/SuiteState.ts b/src/base/SuiteState.ts index 8917163..5abff03 100644 --- a/src/base/SuiteState.ts +++ b/src/base/SuiteState.ts @@ -18,4 +18,32 @@ export class SuiteState { get(key: string ): T | undefined { return this.state.get(key) ?? undefined; } + + push(key: string, value: any): void { + const current = this.get(key); + if(!Array.isArray(current)) { + throw new Error('Value at key is not an array'); + } + if(!current) { + this.set(key, [value]); + } + else { + current.push(value); + this.set(key, current); + } + } + + add(key: string, value: any): void { + const current = this.get(key); + if(!(current instanceof Set)) { + throw new Error('Value at key is not an array'); + } + if(!current) { + this.set(key, new Set([value])); + } + else { + current.add(value); + this.set(key, current); + } + } } \ No newline at end of file diff --git a/src/base/SuiteTest.ts b/src/base/SuiteTest.ts index f65c673..e150cf3 100644 --- a/src/base/SuiteTest.ts +++ b/src/base/SuiteTest.ts @@ -1,22 +1,19 @@ +import chalk from "chalk"; import { SuiteTestResulter } from "#base/Resulter.js"; import { Sampler } from "#base/Sampler.js"; import { Ingestor } from "#base/Ingestor.js"; - +import Logger from '#base/Logger.js'; import type { ISuite, ISuiteSampleData } from "#base/Suite.js"; import { generateSubId } from "#src/utils/nostr.js"; -import { ISuiteCodeTypes } from "./Suite.js"; + import { WebSocketWrapper as WebSocket } from "./WebSocketWrapper.js"; -import Logger from '#base/Logger.js'; -import { Nip01ClientMessageGenerator } from "#src/nips/Nip01/index.js"; -import { RelayEventMessage } from "#src/nips/Nip01/interfaces/RelayEventMessage.js"; +import { AssertWrap, Expect, type IExpectErrors, type IExpectResults } from "./Expect.js"; -import { AssertWrap, Expect, IExpectErrors, IExpectResult, IExpectResults } from "./Expect.js"; +import { Nip01ClientMessageGenerator } from "#src/nips/Nip01/utils/generators.js"; +import type { INip01Filter, Note, RelayEventMessage } from "#src/nips/Nip01/interfaces/index.js"; -import { INip01Filter } from "#src/nips/Nip01/interfaces/Filter.js"; -import { Note } from "#src/nips/Nip01/interfaces/Note.js"; -import chalk from "chalk"; import { SuiteState } from "./SuiteState.js"; export type CompleteOnType = "off" | "maxEvents" | "EOSE"; @@ -104,14 +101,18 @@ export abstract class SuiteTest implements ISuiteTest { return this.suite.state; } - get samples(): ISuiteSampleData { - return this.state.get('samples'); - } - protected get expect(): Expect { return this._expect; } + getSamples(): T | undefined { + return this.state.get('samples')?.[this.slug]; + } + + digest() { + this.logger.debug(`${this.slug} digest method was not implemented.`, 1); + } + suiteIngest(ingestor: Ingestor[] | Ingestor) { if(Array.isArray(ingestor)) { this.suite.registerIngestors(this.slug, ingestor); @@ -165,16 +166,16 @@ export abstract class SuiteTest implements ISuiteTest { }; } - async screen(conditions: AssertWrap): Promise {} - async prepare() { this.REQ(this.filters) await this.testable(); } async run() { + if(this.slug === 'unset') throw new Error('slug of SuiteTest must be set'); + this.logger.info(`BEGIN: ${this.slug}`, 2); - + if(this?.sampler?.samplable) { await this.sampler.sample(); } @@ -188,11 +189,10 @@ export abstract class SuiteTest implements ISuiteTest { this.newSubId(); } - if(this.slug === 'unset') throw new Error('slug of SuiteTest must be set'); - this.timeoutBegin(); - await this.screen(this.expect.conditions) - this.state.set('okConditions', this.expect.conditions.passed); + this.digest(); + this.precheck(this.expect.conditions); + this.expect.evaluateConditions(true); await this.prepare(); this.finish(); return this.resulter.result @@ -233,7 +233,7 @@ export abstract class SuiteTest implements ISuiteTest { // const codes = this.suite.collectCodes(); const { passed, failed, passing, errors } = this.expect; const passrate = passed.length / (passed.length + failed.length); - const notices = this.notices; + const notices = this.notices.map(notice => notice[1]); const result = { testKey: this.suite.testKey, passing, @@ -245,6 +245,8 @@ export abstract class SuiteTest implements ISuiteTest { } as ISuiteTestResult; this.logger.custom(passed? 'pass': 'fail', `${this.slug}`, 2); + + console.log(`before resulter`) this.resulter.set(result as ISuiteTestResult); } @@ -307,7 +309,7 @@ export abstract class SuiteTest implements ISuiteTest { } precheck(conditions: AssertWrap){ - this.logger.warn(`${this.slug} precheck method was not implemented.`, 1); + this.logger.debug(`${this.slug} precheck method was not implemented.`, 1); } test(methods: Expect) { diff --git a/src/base/WebSocketWrapper.ts b/src/base/WebSocketWrapper.ts index 0f8e9d7..b38ca93 100644 --- a/src/base/WebSocketWrapper.ts +++ b/src/base/WebSocketWrapper.ts @@ -1,4 +1,3 @@ -import { Nip01ClientMessageGenerator } from "#src/nips/Nip01"; import { WebSocket } from "ws"; import Logger from '#base/Logger.js'; import { INip01RelayMessage } from "#src/nips/Nip01/interfaces"; diff --git a/src/nips/Nip01/index.ts b/src/nips/Nip01/index.ts index 1a2085c..19be0c6 100644 --- a/src/nips/Nip01/index.ts +++ b/src/nips/Nip01/index.ts @@ -18,44 +18,6 @@ import type { ClientEventMessage, ClientCloseMessage } from './interfaces/index.js'; -import { MachineReadableStatus } from './interfaces/MachineReadableStatus.js'; -import { HumanReadableStatus } from './interfaces/HumanReadableStatus.js'; - -export class Nip01ClientMessageGenerator { - static EVENT(note: Note): Buffer { - return Buffer.from(JSON.stringify(['EVENT', note] as ClientEventMessage)); - } - - static REQ(subscriptionId: string, filters: T[]): Buffer { - return Buffer.from(JSON.stringify(['REQ', subscriptionId, ...filters] as ClientReqMessageBase)); - } - - static CLOSE(subId: string): Buffer { - return Buffer.from(JSON.stringify(['CLOSE', subId] as ClientCloseMessage)); - } -} - -export class Nip01RelayMessageGenerator { - static EVENT(subId: string, note: Note): Buffer { - return Buffer.from(JSON.stringify(['EVENT', subId, note] as RelayEventMessage)); - } - - static OK(subId: string, status: boolean, message: MachineReadableStatus): Buffer { - return Buffer.from(JSON.stringify(['OK', subId, status, message] as RelayOkMessage)); - } - - static EOSE(subId: string): Buffer { - return Buffer.from(JSON.stringify(['EOSE', subId] as RelayEoseMessage)); - } - - static NOTICE(subId: string, message: HumanReadableStatus): Buffer { - return Buffer.from(JSON.stringify(['NOTICE', message] as RelayNoticeMessage)); - } - - static CLOSED(subId: string, message: MachineReadableStatus): Buffer { - return Buffer.from(JSON.stringify(['CLOSED', subId, message] as RelayClosedMessage)); - } -} //nip01 export class Nip01 extends Suite implements ISuite { diff --git a/src/nips/Nip01/ingestors/AuthorIngestor.ts b/src/nips/Nip01/ingestors/AuthorIngestor.ts index d7548ba..7b69fd8 100644 --- a/src/nips/Nip01/ingestors/AuthorIngestor.ts +++ b/src/nips/Nip01/ingestors/AuthorIngestor.ts @@ -5,7 +5,7 @@ export class AuthorIngestor extends Ingestor { private authors: Set = new Set(); feed(note: Note): void { - if(!this?.signal) throw new Error('Ingestor not registered with signal'); + console.log(`AuthorIngestor.feed() ${note.id}`); this.authors.add(note.pubkey); if(this.authors.size >= this.sampleSize) this.complete(); diff --git a/src/nips/Nip01/ingestors/KindIngestor.ts b/src/nips/Nip01/ingestors/KindIngestor.ts index 123806e..79d6cb0 100644 --- a/src/nips/Nip01/ingestors/KindIngestor.ts +++ b/src/nips/Nip01/ingestors/KindIngestor.ts @@ -5,7 +5,6 @@ export class KindIngestor extends Ingestor { private kinds: Set = new Set(); feed(note: Note): void { - if(!this?.signal) throw new Error('Ingestor not registered with signal'); this.kinds.add(note.kind); if(this.kinds.size < this.sampleSize) return this.complete(); diff --git a/src/nips/Nip01/ingestors/RangeIngestor.ts b/src/nips/Nip01/ingestors/RangeIngestor.ts index 00bb77d..dc88f37 100644 --- a/src/nips/Nip01/ingestors/RangeIngestor.ts +++ b/src/nips/Nip01/ingestors/RangeIngestor.ts @@ -5,7 +5,6 @@ export class RangeIngestor extends Ingestor { private timestamps: Set = new Set(); feed(note: Note): void { - if(!this?.signal) throw new Error('Ingestor not registered with signal'); this.timestamps.add(note.created_at); if(this.timestamps.size >= this.sampleSize) this.complete(); diff --git a/src/nips/Nip01/ingestors/SingleTagIngestor.ts b/src/nips/Nip01/ingestors/SingleTagIngestor.ts index c7cfe4c..7ea3d36 100644 --- a/src/nips/Nip01/ingestors/SingleTagIngestor.ts +++ b/src/nips/Nip01/ingestors/SingleTagIngestor.ts @@ -8,8 +8,6 @@ export class SingleTagIngestor extends Ingestor { feed(note: Note): void { if (this.tags.size >= this.sampleSize) return; - if (!this?.signal) - throw new Error('Ingestor not registered with signal'); let singleLetterTags = []; try { singleLetterTags = note.tags.filter((tag: string[]) => tag[0].length === 1); diff --git a/src/nips/Nip01/interfaces/index.ts b/src/nips/Nip01/interfaces/index.ts index 5dcb63b..b7fe6e1 100644 --- a/src/nips/Nip01/interfaces/index.ts +++ b/src/nips/Nip01/interfaces/index.ts @@ -11,4 +11,7 @@ export * from "./ClientCloseMessage"; export * from "./ClientEventMessage"; export * from "./ClientReqMessage"; -export * from "./INip01RelayMessage"; \ No newline at end of file +export * from "./INip01RelayMessage"; + +export * from "./MachineReadableStatus"; +export * from "./HumanReadableStatus"; \ No newline at end of file diff --git a/src/nips/Nip01/schemata/note.schema.json b/src/nips/Nip01/schemata/note.schema.json index 6aa274f..6c50184 100644 --- a/src/nips/Nip01/schemata/note.schema.json +++ b/src/nips/Nip01/schemata/note.schema.json @@ -14,8 +14,9 @@ }, "created_at": { "type": "integer", - "minimum": 0, - "description": "Unix timestamp in seconds" + "minimum": 1000000000, + "maximum": 9999999999, + "description": "Unix timestamp in seconds (10-digit timestamp, not in milliseconds)" }, "kind": { "type": "integer", diff --git a/src/nips/Nip01/tests/FilterAuthor.ts b/src/nips/Nip01/tests/FilterAuthor.ts index 7172161..40c207d 100644 --- a/src/nips/Nip01/tests/FilterAuthor.ts +++ b/src/nips/Nip01/tests/FilterAuthor.ts @@ -11,7 +11,7 @@ export class FilterAuthor extends SuiteTest implements ISuiteTest { maxEvents: number = 3; authorsReturned: string[] = []; - author: string = ''; + author?: string; limit: number = 1; constructor(suite: ISuite) { @@ -20,14 +20,12 @@ export class FilterAuthor extends SuiteTest implements ISuiteTest { } get filters(): INip01Filter[] { - this.author = this.ingestor.poop()[0] return [{ authors: [ this.author ], limit: this.limit }]; } - onMessageEvent(message: RelayEventMessage){ - const note = message?.[2]; - if(!note) return; - this.authorsReturned.push(note.pubkey); + digest(){ + const samples = this.getSamples() + this.author = samples[0]; } precheck(conditions: AssertWrap){ @@ -35,6 +33,12 @@ export class FilterAuthor extends SuiteTest implements ISuiteTest { conditions.toBeOk(is64CharHex(this.author), 'author hex pubkey looks valid'); } + onMessageEvent(message: RelayEventMessage){ + const note = message?.[2]; + if(!note) return; + this.authorsReturned.push(note.pubkey); + } + test({behavior}){ const returnedNum = this.authorsReturned.length const returnedAtLeastOne = returnedNum > 0; diff --git a/src/nips/Nip01/tests/FilterKinds.ts b/src/nips/Nip01/tests/FilterKinds.ts index cd4fda9..019d644 100644 --- a/src/nips/Nip01/tests/FilterKinds.ts +++ b/src/nips/Nip01/tests/FilterKinds.ts @@ -3,13 +3,13 @@ import { Sampler } from "#base/Sampler.js"; import { CompleteOnTypeArray, ISuiteTest, SuiteTest } from '#base/SuiteTest.js'; import { ISuite } from '#base/Suite.js'; -import { Nip01ClientMessageGenerator } from '../index.js'; import { INip01Filter, Note, RelayEventMessage } from '../interfaces/index.js'; import { KindIngestor } from "../ingestors/KindIngestor.js"; import { AssertWrap } from "#src/base/Expect.js"; export class FilterKinds extends SuiteTest implements ISuiteTest { readonly slug: string = 'FilterKinds'; + kindsSampled: number[] = []; kindsReturned: number[] = []; maxEvents: number = 15; limit: number = 5 @@ -20,7 +20,11 @@ export class FilterKinds extends SuiteTest implements ISuiteTest { } get filters(): INip01Filter[] { - return [{ kinds: this.ingestor.poop(), limit: this.limit }]; + return [{ kinds: this.kindsSampled, limit: this.limit }]; + } + + digest(){ + this.kindsSampled = this.getSamples() } onMessageEvent(message: RelayEventMessage){ @@ -34,7 +38,7 @@ export class FilterKinds extends SuiteTest implements ISuiteTest { test({behavior}){ const moreThanZero = this.kindsReturned.length > 0 - const returnedOnlyEventKinds = this.kindsReturned.every((item: number) => this.ingestor.poop().includes(item)); + const returnedOnlyEventKinds = this.kindsReturned.every((item: number) => this.kindsSampled.includes(item)); behavior.toBeOk(moreThanZero, 'returned at least one event'); behavior.toBeOk(moreThanZero && returnedOnlyEventKinds, 'return only requested event kinds'); } diff --git a/src/nips/Nip01/tests/FilterMulti.ts b/src/nips/Nip01/tests/FilterMulti.ts index b38b636..155b562 100644 --- a/src/nips/Nip01/tests/FilterMulti.ts +++ b/src/nips/Nip01/tests/FilterMulti.ts @@ -2,7 +2,6 @@ import { CompleteOnTypeArray, ISuiteTest, SuiteTest } from '#base/SuiteTest.js'; import { ISuite } from '#base/Suite.js'; -import { Nip01ClientMessageGenerator } from '../index.js'; import { INip01Filter, Note, RelayEventMessage } from '../interfaces/index.js'; export class FilterMulti extends SuiteTest implements ISuiteTest { diff --git a/src/nips/Nip01/tests/FilterRange.ts b/src/nips/Nip01/tests/FilterRange.ts index 823ccf1..4f019ff 100644 --- a/src/nips/Nip01/tests/FilterRange.ts +++ b/src/nips/Nip01/tests/FilterRange.ts @@ -19,8 +19,11 @@ export class FilterRange extends SuiteTest implements ISuiteTest { this.suiteIngest(new RangeIngestor(30)); } + digest(){ + this.range = this.selectRangeFromSample(this.getSamples()); + } + get filters(): INip01Filter[] { - this.range = this.selectRangeFromSample(this.ingestor.poop()); return [{ ...this.range, limit: this.limit }]; } @@ -30,8 +33,15 @@ export class FilterRange extends SuiteTest implements ISuiteTest { } precheck(conditions: AssertWrap){ - const sampleSufficient = this?.range?.since && this?.range?.until && this.range.since != this.range.until - conditions.toBeOk(this?.range?.since && this?.range?.until && this.range.since != this.range.until, 'sample data to be sufficient') + const bothRangeValuesAreNumbers = typeof this?.range?.since === 'number' && typeof this?.range?.until === 'number'; + const rangeValuesAreDifferent = this?.range?.since != this?.range?.until; + const untilIsGreaterThanSince = this?.range?.until > this?.range?.since; + const sampleSufficient = bothRangeValuesAreNumbers && rangeValuesAreDifferent && untilIsGreaterThanSince; + conditions.toBeOk(untilIsGreaterThanSince, 'until is greater than since'); + conditions.toBeOk(bothRangeValuesAreNumbers, 'since and until are numbers'); + conditions.toNotEqual(this?.range?.since, this?.range?.until, 'since and until are different values'); + conditions.toBeOk(sampleSufficient, 'sample data to be sufficient') + } diff --git a/src/nips/Nip01/tests/FilterTags.ts b/src/nips/Nip01/tests/FilterTags.ts index a6756df..a68d2ff 100644 --- a/src/nips/Nip01/tests/FilterTags.ts +++ b/src/nips/Nip01/tests/FilterTags.ts @@ -10,6 +10,7 @@ export class FilterTags extends SuiteTest implements ISuiteTest { readonly slug: string = 'FilterTags'; protected timeoutMs: number = 15000; + tagsSampled: string[] = []; singleLetterTagsReturned: string[][] = []; maxEvents: number = 5; limit: number = 1; @@ -19,9 +20,17 @@ export class FilterTags extends SuiteTest implements ISuiteTest { this.suiteIngest(new SingleTagIngestor(1)); } + digest(){ + this.tagsSampled = this.getSamples(); + } + + precheck(conditions: AssertWrap): void { + conditions.toBeOk(this.singleLetterTagsReturned.length > 0, 'sample data size is sufficient for test'); + } + get filters(): INip01Filter[] { - const tag: string[] = this.ingestor.poop() as string[]; - const filter = { [`#${tag[0]}`]: [tag[1]] } as Partial + const tag = this.tagsSampled + const filter = { [`#${tag[0]}`]: [tag[1]] } as Partial return [{ ...filter, limit: this.limit }]; } @@ -31,19 +40,15 @@ export class FilterTags extends SuiteTest implements ISuiteTest { tags.filter(tag => tag[0].length === 1).forEach(tag => this.singleLetterTagsReturned.push(tag)) } - precheck(conditions: AssertWrap): void { - conditions.toBeOk(this.singleLetterTagsReturned.length > 0, 'sample data size is sufficient for test'); - } - test({behavior}){ const numTagsReturned = this.singleLetterTagsReturned.length const returnedOnlyTagsRequested = this.singleLetterTagsReturned.some((item: string[]) => { - const key = this.ingestor.poop()[0] - const value = this.ingestor.poop()[1] + const key = this.tagsSampled[0] + const value = this.tagsSampled[1] return item[0] === key && item[1] === value }); behavior.toBeOk(returnedOnlyTagsRequested, `returned only requested tags: ${truncate(JSON.stringify(this.singleLetterTagsReturned))}`); - behavior.toEqual(numTagsReturned, 1, 'returned only one event'); + behavior.toEqual(numTagsReturned, this.limit, 'returned only requested number of events'); } } diff --git a/src/nips/Nip01/utils/generators.ts b/src/nips/Nip01/utils/generators.ts new file mode 100644 index 0000000..881c59d --- /dev/null +++ b/src/nips/Nip01/utils/generators.ts @@ -0,0 +1,50 @@ +import type { + Note, + INip01Filter, + ClientEventMessage, + ClientReqMessageBase, + ClientCloseMessage, + RelayEventMessage, + RelayEoseMessage, + RelayOkMessage, + RelayNoticeMessage, + RelayClosedMessage, + HumanReadableStatus, + MachineReadableStatus +} from '../interfaces/index.js'; + +export class Nip01ClientMessageGenerator { + static EVENT(note: Note): Buffer { + return Buffer.from(JSON.stringify(['EVENT', note] as ClientEventMessage)); + } + + static REQ(subscriptionId: string, filters: T[]): Buffer { + return Buffer.from(JSON.stringify(['REQ', subscriptionId, ...filters] as ClientReqMessageBase)); + } + + static CLOSE(subId: string): Buffer { + return Buffer.from(JSON.stringify(['CLOSE', subId] as ClientCloseMessage)); + } + } + + export class Nip01RelayMessageGenerator { + static EVENT(subId: string, note: Note): Buffer { + return Buffer.from(JSON.stringify(['EVENT', subId, note] as RelayEventMessage)); + } + + static OK(subId: string, status: boolean, message: MachineReadableStatus): Buffer { + return Buffer.from(JSON.stringify(['OK', subId, status, message] as RelayOkMessage)); + } + + static EOSE(subId: string): Buffer { + return Buffer.from(JSON.stringify(['EOSE', subId] as RelayEoseMessage)); + } + + static NOTICE(subId: string, message: HumanReadableStatus): Buffer { + return Buffer.from(JSON.stringify(['NOTICE', message] as RelayNoticeMessage)); + } + + static CLOSED(subId: string, message: MachineReadableStatus): Buffer { + return Buffer.from(JSON.stringify(['CLOSED', subId, message] as RelayClosedMessage)); + } + } \ No newline at end of file diff --git a/src/nips/Nip11/ingestors/ContentIngestor.ts b/src/nips/Nip11/ingestors/ContentIngestor.ts index fda657f..23038ac 100644 --- a/src/nips/Nip11/ingestors/ContentIngestor.ts +++ b/src/nips/Nip11/ingestors/ContentIngestor.ts @@ -12,7 +12,6 @@ export class ContentIngestor extends Ingestor { } feed(note: Note): void { - if(!this?.signal) throw new Error('Ingestor not registered with signal'); if(!isNaturalLanguage(note.content) || this.searches.has(note.content)) return; this.searches.add(note.content); if(this.searches.size >= this.sampleSize) { diff --git a/src/nips/Nip11/tests/ValidateSchema.ts b/src/nips/Nip11/tests/ValidateSchema.ts index c9a107a..3a2a18a 100644 --- a/src/nips/Nip11/tests/ValidateSchema.ts +++ b/src/nips/Nip11/tests/ValidateSchema.ts @@ -38,8 +38,8 @@ export class ValidateSchema extends SuiteTest implements ISuiteTest { }) .catch((e) => { //console.log('catch', e.message) - this.resulter.set('reason', e.message) - this.resulter.set('pass', false) + // this.resulter.set('reason', e.message) + this.resulter.set('passing', false) }); this.data = data } diff --git a/src/nips/Nip50/ingestors/ContentIngestor.ts b/src/nips/Nip50/ingestors/ContentIngestor.ts index f4aca9d..de539b1 100644 --- a/src/nips/Nip50/ingestors/ContentIngestor.ts +++ b/src/nips/Nip50/ingestors/ContentIngestor.ts @@ -3,16 +3,9 @@ import { Note } from '#nips/Nip01/interfaces/Note.js'; import { isNaturalLanguage } from '#utils/discriminators.js' export class ContentIngestor extends Ingestor { - readonly sampleSize: number = 5; private searches = new Set(); - constructor(sampleSize?: number) { - super(); - if(sampleSize) this.sampleSize = sampleSize; - } - feed(note: Note): void { - if(!this?.signal) throw new Error('Ingestor not registered with signal'); if(!isNaturalLanguage(note.content)) return; let term = null; let tries = 0; diff --git a/src/nips/Nip50/tests/Search.ts b/src/nips/Nip50/tests/Search.ts index 06a5fe9..8e3a7a4 100644 --- a/src/nips/Nip50/tests/Search.ts +++ b/src/nips/Nip50/tests/Search.ts @@ -17,7 +17,7 @@ export class Search extends SuiteTest implements ISuiteTest { constructor(suite: ISuite) { super(suite); - this.registerIngestor(new ContentIngestor()); + this.suiteIngest(new ContentIngestor(5)); } get filters(): Nip50Filter[] { From 7c74e4f216d79808746c37dd45eafeda447c18ec Mon Sep 17 00:00:00 2001 From: Sandwich <299465+dskvr@users.noreply.github.com> Date: Sat, 9 Nov 2024 15:14:58 +0100 Subject: [PATCH 5/6] less verbosity --- example/nip01.js | 12 ++++++------ example/nip50.js | 12 ++++++------ src/base/Expect.ts | 8 +++++--- src/base/Suite.ts | 8 ++++---- src/base/SuiteTest.ts | 2 +- src/nips/Nip01/ingestors/AuthorIngestor.ts | 1 - 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/example/nip01.js b/example/nip01.js index c6e3b91..8f7b0ed 100644 --- a/example/nip01.js +++ b/example/nip01.js @@ -30,7 +30,7 @@ try { for( const result of results) { - console.log(result.relay, result.suites.Nip01.pass); + //console.log(result.relay, result.suites.Nip01.pass); } let totalChecked = 0; @@ -38,7 +38,7 @@ let totalPassed = 0; let totalFailed = 0; for (const result of results) { - console.log(result.relay, result.suites.Nip01.pass); + //console.log(result.relay, result.suites.Nip01.pass); totalChecked++; if (result.suites.Nip01.pass) { @@ -50,7 +50,7 @@ for (const result of results) { const percentagePassed = ((totalPassed / totalChecked) * 100).toFixed(2); -console.log('Total checked:', totalChecked); -console.log('Total passed:', totalPassed); -console.log('Total failed:', totalFailed); -console.log('Percentage passed:', percentagePassed + '%'); \ No newline at end of file +//console.log('Total checked:', totalChecked); +//console.log('Total passed:', totalPassed); +//console.log('Total failed:', totalFailed); +//console.log('Percentage passed:', percentagePassed + '%'); \ No newline at end of file diff --git a/example/nip50.js b/example/nip50.js index c034398..e868609 100644 --- a/example/nip50.js +++ b/example/nip50.js @@ -31,7 +31,7 @@ try { for( const result of results) { - console.log(result.relay, result.suites.Nip50.pass); + //console.log(result.relay, result.suites.Nip50.pass); } let totalChecked = 0; @@ -39,7 +39,7 @@ let totalPassed = 0; let totalFailed = 0; for (const result of results) { - console.log(result.relay, result.suites.Nip50.pass); + //console.log(result.relay, result.suites.Nip50.pass); totalChecked++; if (result.suites.Nip50.pass) { @@ -51,7 +51,7 @@ for (const result of results) { const percentagePassed = ((totalPassed / totalChecked) * 100).toFixed(2); -console.log('Total checked:', totalChecked); -console.log('Total passed:', totalPassed); -console.log('Total failed:', totalFailed); -console.log('Percentage passed:', percentagePassed + '%'); \ No newline at end of file +//console.log('Total checked:', totalChecked); +//console.log('Total passed:', totalPassed); +//console.log('Total failed:', totalFailed); +//console.log('Percentage passed:', percentagePassed + '%'); \ No newline at end of file diff --git a/src/base/Expect.ts b/src/base/Expect.ts index bc8c629..446b420 100644 --- a/src/base/Expect.ts +++ b/src/base/Expect.ts @@ -41,6 +41,7 @@ export class AssertWrap { if(this._verbose) { this.logger.registerLogger('pass', 'info', chalk.green.bold) this.logger.registerLogger('fail', 'info', chalk.redBright.bold) + this.logger.registerLogger('skip', 'info', chalk.gray.bold) } } @@ -99,6 +100,7 @@ export class AssertWrap { if(this.skip) { result = { ...result, message, skipped: true }; this.result = result; + if(this._verbose) this.logger.custom('skip', `${message}`, 3); return; } @@ -136,8 +138,8 @@ export class Expect { readonly keys: Array = ['conditions', 'message', 'json', 'behavior'] conditions: AssertWrap = new AssertWrap({ verbose: true}) - message: AssertWrap = new AssertWrap({ verbose: true }) - json: AssertWrap = new AssertWrap({ verbose: true }) + message: AssertWrap = new AssertWrap() + json: AssertWrap = new AssertWrap() behavior: AssertWrap = new AssertWrap({ verbose: true }) z get passed(): IExpectResults { @@ -185,7 +187,7 @@ z for(const expectKey of this.keys){ const arr = (this[expectKey as keyof Expect] as AssertWrap)[key] if(!(arr instanceof Array)) { - console.log(`returnKeyAggregate: this[${expectKey}][${key}] is not an array`) + //console.log(`returnKeyAggregate: this[${expectKey}][${key}] is not an array`) continue; } res = [...res, ...arr] diff --git a/src/base/Suite.ts b/src/base/Suite.ts index 5dbe323..19233f8 100644 --- a/src/base/Suite.ts +++ b/src/base/Suite.ts @@ -182,7 +182,7 @@ export abstract class Suite implements ISuite { } registerIngestor(testSlug: string, ingestor: Ingestor) { - console.log(`registering ingestor for ${testSlug}`); + //console.log(`registering ingestor for ${testSlug}`); if(!this?.sampler) this.initSampler(); ingestor.belongsTo = testSlug; @@ -195,10 +195,10 @@ export abstract class Suite implements ISuite { } private toilet(){ - console.log(`flushing toilet ${this.ingestors.length}`); + //console.log(`flushing toilet ${this.ingestors.length}`); const poops: ISuiteSampleData = {}; for(const ingestor of this.ingestors) { - console.log('flushing poop', ingestor.parent, ingestor.poop()); + //console.log('flushing poop', ingestor.parent, ingestor.poop()); const testKey = ingestor.parent; poops[testKey] = ingestor.poop(); } @@ -223,7 +223,7 @@ export abstract class Suite implements ISuite { for(const test of Object.entries(this.testers)) { const [testName, suiteTest] = test; const results = await suiteTest.run(); - console.log(results) + //console.log(results) this.resulter.set('tests', testName, results); if(suiteTest?.data !== null) { this.resulter.set('data', { [testName]: suiteTest.data }); diff --git a/src/base/SuiteTest.ts b/src/base/SuiteTest.ts index e150cf3..1ea75ed 100644 --- a/src/base/SuiteTest.ts +++ b/src/base/SuiteTest.ts @@ -246,7 +246,7 @@ export abstract class SuiteTest implements ISuiteTest { this.logger.custom(passed? 'pass': 'fail', `${this.slug}`, 2); - console.log(`before resulter`) + //console.log(`before resulter`) this.resulter.set(result as ISuiteTestResult); } diff --git a/src/nips/Nip01/ingestors/AuthorIngestor.ts b/src/nips/Nip01/ingestors/AuthorIngestor.ts index 7b69fd8..feb6c82 100644 --- a/src/nips/Nip01/ingestors/AuthorIngestor.ts +++ b/src/nips/Nip01/ingestors/AuthorIngestor.ts @@ -5,7 +5,6 @@ export class AuthorIngestor extends Ingestor { private authors: Set = new Set(); feed(note: Note): void { - console.log(`AuthorIngestor.feed() ${note.id}`); this.authors.add(note.pubkey); if(this.authors.size >= this.sampleSize) this.complete(); From fa1c19921b136264964c9ef032b6db37d375b83a Mon Sep 17 00:00:00 2001 From: Sandwich <299465+dskvr@users.noreply.github.com> Date: Sat, 9 Nov 2024 21:35:35 +0100 Subject: [PATCH 6/6] log notices and better results --- example/nip50.js | 7 ++-- src/base/Expect.ts | 47 ++++++++++++++++++-------- src/base/Sampler.ts | 3 +- src/base/Suite.ts | 47 ++++++-------------------- src/base/SuiteTest.ts | 23 +++++++++---- src/nips/Nip01/tests/FilterKinds.ts | 8 ++--- src/nips/Nip01/tests/FilterRange.ts | 2 +- src/nips/Nip01/tests/FilterTags.ts | 5 ++- src/nips/Nip11/tests/ValidateSchema.ts | 2 +- src/nips/Nip50/tests/Search.ts | 17 ++++++---- 10 files changed, 82 insertions(+), 79 deletions(-) diff --git a/example/nip50.js b/example/nip50.js index e868609..6b0bfe0 100644 --- a/example/nip50.js +++ b/example/nip50.js @@ -1,6 +1,5 @@ import { Auditor } from '../dist/server/index.js'; -import util from 'util'; -import https from 'https'; +import { shuffleArray } from '../dist/server/utils/array.js'; const url = 'https://api.nostr.watch/v1/nip/50'; @@ -12,12 +11,12 @@ try { throw new Error(`HTTP error! Status: ${response.status}`); } - const relays = await response.json(); + const relays = shuffleArray(await response.json()); if (Array.isArray(relays)) { for (const relay of relays) { const auditor = new Auditor(); - auditor.removeSuite('Nip01'); + // auditor.removeSuite('Nip01'); auditor.addSuite('Nip50') const result = await auditor.test(relay); results.push(result); diff --git a/src/base/Expect.ts b/src/base/Expect.ts index 446b420..7199ca5 100644 --- a/src/base/Expect.ts +++ b/src/base/Expect.ts @@ -1,8 +1,10 @@ import assert from 'power-assert'; import Logger from './Logger.js'; import chalk from 'chalk'; +import { toCode } from '#src/utils/string.js'; export interface IAssertWrapOptions { + type: string; verbose?: boolean; } @@ -13,6 +15,7 @@ export type IExpectError = Record export type IExpectErrors = IExpectError[] export interface IExpectResult { + type: string; code: string; message: string; pass: boolean; @@ -21,6 +24,7 @@ export interface IExpectResult { } export const defaultExpectResult = { + type: "unset", code: "UNSET", message: "unset", pass: false, @@ -28,6 +32,7 @@ export const defaultExpectResult = { } export class AssertWrap { + private _type: string; private _result: IExpectResults = []; private _verbose: boolean = false; private _skip: boolean = false; @@ -36,8 +41,9 @@ export class AssertWrap { showNamespace: false }); - constructor(options: IAssertWrapOptions = {}) { - if(options?.verbose !== undefined) this._verbose = options.verbose; + constructor({type, verbose}: IAssertWrapOptions) { + this._type = type + if(verbose !== undefined) this._verbose = verbose; if(this._verbose) { this.logger.registerLogger('pass', 'info', chalk.green.bold) this.logger.registerLogger('fail', 'info', chalk.redBright.bold) @@ -45,6 +51,10 @@ export class AssertWrap { } } + get type() { + return this._type; + } + set skip(skip: boolean) { this._skip = skip; } @@ -85,6 +95,10 @@ export class AssertWrap { return Math.round((this.passed.length / (this.result.length)) * 100); } + get defaultResult(){ + return {...defaultExpectResult, type: this.type}; + } + private extractErrorDetails(error: any) { const { generatedMessage, code, actual, expected, operator } = error; return { generatedMessage, code, actual, expected, operator }; @@ -93,12 +107,14 @@ export class AssertWrap { private createProxy(assertionFn: (...args: any[]) => void) { return new Proxy((...args: any[]) => assertionFn(...args), { apply: (target, thisArg, argumentsList) => { - let result: IExpectResult = defaultExpectResult; + let result: IExpectResult = this.defaultResult; const message = argumentsList[argumentsList.length - 1]; + const code = toCode(message); let pass = false + let error; if(this.skip) { - result = { ...result, message, skipped: true }; + result = { ...result, code, message, skipped: true }; this.result = result; if(this._verbose) this.logger.custom('skip', `${message}`, 3); return; @@ -107,12 +123,11 @@ export class AssertWrap { try { Reflect.apply(target, thisArg, argumentsList); pass = true; - result = { ...result, message, pass }; } catch (error) { error = this.extractErrorDetails(error); - result = { ...result, message, pass, error }; } + result = { ...result, code, message, pass, error }; if(this._verbose) this.logger.custom(pass? `pass`: `fail`, `${message}`, 3); this.result = result; }, @@ -135,19 +150,19 @@ export class AssertWrap { export class Expect { - readonly keys: Array = ['conditions', 'message', 'json', 'behavior'] + readonly keys: Array = ['message', 'json', 'behavior'] - conditions: AssertWrap = new AssertWrap({ verbose: true}) - message: AssertWrap = new AssertWrap() - json: AssertWrap = new AssertWrap() - behavior: AssertWrap = new AssertWrap({ verbose: true }) + conditions: AssertWrap = new AssertWrap({ type: 'conditions', verbose: true}) + message: AssertWrap = new AssertWrap({ type: 'message' }) + json: AssertWrap = new AssertWrap({ type: 'json' }) + behavior: AssertWrap = new AssertWrap({ type: 'conditions', verbose: true }) z get passed(): IExpectResults { - return this.returnKeyAggregate('passed') as IExpectResults + return this.returnKeyAggregate('passed').filter(this.ignoreConditions) as IExpectResults } get failed(): IExpectResults { - return this.returnKeyAggregate('failed') as IExpectResults + return this.returnKeyAggregate('failed').filter(this.ignoreConditions) as IExpectResults } get skipped(): IExpectResults { @@ -155,7 +170,7 @@ z } get results(): IExpectResults { - return this.returnKeyAggregate('result') as IExpectResults + return this.returnKeyAggregate('result').filter(this.ignoreConditions) as IExpectResults } get passrate(): number { @@ -195,4 +210,8 @@ z return res; } + private ignoreConditions(result: IExpectResult): boolean { + return result.type !== 'conditions'; + } + } \ No newline at end of file diff --git a/src/base/Sampler.ts b/src/base/Sampler.ts index 208bdec..6d83326 100644 --- a/src/base/Sampler.ts +++ b/src/base/Sampler.ts @@ -58,7 +58,6 @@ export class Sampler { case 'EVENT': { const note = (message as RelayEventMessage)[2] as Note; this._totalSamples++; - // this.signal.emit('ingest', note); this.runIngestors(note); break; } @@ -102,7 +101,7 @@ export class Sampler { } private sendRequest() { - const message = Nip01ClientMessageGenerator.REQ(this.subId, [{ limit: this._maximumSamples }]); + const message = Nip01ClientMessageGenerator.REQ(this.subId, [{ limit: this._maximumSamples, since: 0 }]); this.ws.send(message); } diff --git a/src/base/Suite.ts b/src/base/Suite.ts index 19233f8..7a9b039 100644 --- a/src/base/Suite.ts +++ b/src/base/Suite.ts @@ -17,6 +17,7 @@ import Logger from './Logger.js'; import { SuiteState } from './SuiteState.js'; import { Ingestor } from './Ingestor.js'; import { Sampler } from './Sampler.js'; +import chalk from 'chalk'; export type ISuiteSampleData = Record; @@ -96,13 +97,8 @@ export abstract class Suite implements ISuite { readonly messageValidators: Record> = {}; readonly jsonValidators: Record> = {}; - // jsons: string[] = []; - // behaviors: string[] = []; protected tests: string[] = []; - // protected messageCodes: INipTesterCodes = {}; - // protected jsonCodes: INipTesterCodes = {}; - // protected behaviorCodes: INipTesterCodes = {}; protected testers: Record = {}; protected _ready: boolean = false; protected totalEvents: number = 0; @@ -115,6 +111,7 @@ export abstract class Suite implements ISuite { constructor(ws: WebSocket, metaUrl: string) { this.ws = ws; + this.logger.registerLogger('notice', 'info', chalk.gray.italic); this.testsDirectory = this._calculateFilePath(metaUrl); this.signal.once("SUITE:READY", () => { this._ready = true }); this.setup() @@ -182,7 +179,6 @@ export abstract class Suite implements ISuite { } registerIngestor(testSlug: string, ingestor: Ingestor) { - //console.log(`registering ingestor for ${testSlug}`); if(!this?.sampler) this.initSampler(); ingestor.belongsTo = testSlug; @@ -195,10 +191,8 @@ export abstract class Suite implements ISuite { } private toilet(){ - //console.log(`flushing toilet ${this.ingestors.length}`); const poops: ISuiteSampleData = {}; for(const ingestor of this.ingestors) { - //console.log('flushing poop', ingestor.parent, ingestor.poop()); const testKey = ingestor.parent; poops[testKey] = ingestor.poop(); } @@ -223,7 +217,6 @@ export abstract class Suite implements ISuite { for(const test of Object.entries(this.testers)) { const [testName, suiteTest] = test; const results = await suiteTest.run(); - //console.log(results) this.resulter.set('tests', testName, results); if(suiteTest?.data !== null) { this.resulter.set('data', { [testName]: suiteTest.data }); @@ -239,28 +232,10 @@ export abstract class Suite implements ISuite { evaluate() { const tests = this.resulter.get('tests'); - const failed = Object.values(tests).filter( test => test.pass === false); + const failed = Object.values(tests).filter( test => test.pass === false ); return failed.length === 0; } - // public logCode(type: ISuiteCodeTypes, plainLanguageCode: string, result: boolean): void { - // const code = `${plainLanguageCode.replace(/ /g, "_").toUpperCase()}`; - // this[`${type}Codes`][code] = result; - // } - - // public getCode(type: ISuiteCodeTypes, plainLanguageCode: string): boolean | null | undefined { - // const code = `${plainLanguageCode.replace(/ /g, "_").toUpperCase()}`; - // return this[`${type}Codes`]?.[code] ?? null; - // } - - // public collectCodes(): Partial { - // return { - // messageCodes: this.messageCodes, - // jsonCodes: this.jsonCodes, - // behaviorCodes: this.behaviorCodes - // } - // } - setupHandlers(): void { this.socket.off() this.socket.on('message', this.handleMessage.bind(this)); @@ -268,21 +243,17 @@ export abstract class Suite implements ISuite { protected validateMessage(message: INip01RelayMessage): void { const key = message?.[0] ?? "unset" - if(!this?.messageValidators?.[key]){ - this.logger.warn(`No validator found for message ${key}`, 2); - return; - } + // if(!this?.messageValidators?.[key]){ + // this.logger.warn(`No validator found for message ${key}`, 3); + // return; + // } const isValid = this?.messageValidators?.[key]?.validate(message) this.expect.message.toBeOk(isValid, `message ${key} is valid: ${truncate(JSON.stringify(message))}`); - // if(this?.messageValidators?.[key]?.validate) { - // this.logCode('message', key, this.messageValidators[key].validate(message)); - // } } validateJson(key: string, json: GenericJson) { key = key.toUpperCase(); this.expect.json.toBeOk(this?.jsonValidators?.[key]?.validate, `json ${key} is valid`); - // this.logCode('json', key, this.jsonValidators[key].validate(json)); } protected handleMessage(messageBuffer: T): void { @@ -294,6 +265,10 @@ export abstract class Suite implements ISuite { const messageArr = this.messages.get(key) ?? []; this.messages.set(key, [...messageArr, message]); + if(key === 'NOTICE') { + this.logger.custom('notice', message[1], 3); + } + let suiteHandler = (this[`onMessage${capitalize(key)}` as keyof typeof this] as unknown as MessageHandler) if (suiteHandler) { suiteHandler = suiteHandler.bind(this); diff --git a/src/base/SuiteTest.ts b/src/base/SuiteTest.ts index 1ea75ed..4252377 100644 --- a/src/base/SuiteTest.ts +++ b/src/base/SuiteTest.ts @@ -38,21 +38,23 @@ export interface ISuiteTest { export interface ISuiteTestResult { testKey: string; - passing: boolean; + pass: boolean; passrate: number; passed: IExpectResults; failed: IExpectResults; + skipped: IExpectResults; notices: string[]; errors: IExpectErrors; } export const defaultSuiteTestResult: ISuiteTestResult = { testKey: "unset", - passing: false, + pass: false, passrate: 0, passed: [], failed: [], notices: [], + skipped: [], errors: [] } @@ -87,6 +89,7 @@ export abstract class SuiteTest implements ISuiteTest { this.suite = suite; this.logger.registerLogger('pass', 'info', chalk.green.bold); this.logger.registerLogger('fail', 'info', chalk.redBright.bold); + this.logger.registerLogger('skipped', 'info', chalk.bgGray.yellow.bold); } get filters(): INip01Filter[] { @@ -230,22 +233,28 @@ export abstract class SuiteTest implements ISuiteTest { private finish(): void { this.logger.debug(`testKey: ${this.suite.testKey}`, 2); - // const codes = this.suite.collectCodes(); - const { passed, failed, passing, errors } = this.expect; + const { passing, passed, failed, skipped, errors } = this.expect; const passrate = passed.length / (passed.length + failed.length); const notices = this.notices.map(notice => notice[1]); + const pass = passing const result = { testKey: this.suite.testKey, - passing, + pass, passrate, passed, + skipped, failed, notices, errors } as ISuiteTestResult; - this.logger.custom(passed? 'pass': 'fail', `${this.slug}`, 2); - + if(skipped.length) { + this.logger.custom('skipped', `${this.slug}`, 2); + } + else { + this.logger.custom(passed? 'pass': 'fail', `${this.slug}`, 2); + } + //console.log(`before resulter`) this.resulter.set(result as ISuiteTestResult); diff --git a/src/nips/Nip01/tests/FilterKinds.ts b/src/nips/Nip01/tests/FilterKinds.ts index 019d644..e4bfc74 100644 --- a/src/nips/Nip01/tests/FilterKinds.ts +++ b/src/nips/Nip01/tests/FilterKinds.ts @@ -27,15 +27,15 @@ export class FilterKinds extends SuiteTest implements ISuiteTest { this.kindsSampled = this.getSamples() } + precheck(conditions: AssertWrap){ + conditions.toBeOk(this.kindsSampled.length > 0, 'sample data size is sufficient for test'); + } + onMessageEvent(message: RelayEventMessage){ const note = message[2]; this.kindsReturned.push(note.kind); } - precheck(conditions: AssertWrap){ - conditions.toBeOk(this.kindsReturned.length > 0, 'sample data size is sufficient for test'); - } - test({behavior}){ const moreThanZero = this.kindsReturned.length > 0 const returnedOnlyEventKinds = this.kindsReturned.every((item: number) => this.kindsSampled.includes(item)); diff --git a/src/nips/Nip01/tests/FilterRange.ts b/src/nips/Nip01/tests/FilterRange.ts index 4f019ff..9b7072f 100644 --- a/src/nips/Nip01/tests/FilterRange.ts +++ b/src/nips/Nip01/tests/FilterRange.ts @@ -48,7 +48,7 @@ export class FilterRange extends SuiteTest implements ISuiteTest { test({behavior}){ behavior.toEqual(this.timestampsReturned.length, this.limit, `returned number of events requested`); behavior.toBeOk(this.timestampsReturned.length > 0, 'returned at least one event'); - behavior.toBeOk(this.withinRange(), 'return only events within range') + behavior.toBeOk(() => this.withinRange(), 'return only events within range') } private withinRange(): boolean { diff --git a/src/nips/Nip01/tests/FilterTags.ts b/src/nips/Nip01/tests/FilterTags.ts index a68d2ff..a46d1f5 100644 --- a/src/nips/Nip01/tests/FilterTags.ts +++ b/src/nips/Nip01/tests/FilterTags.ts @@ -25,7 +25,7 @@ export class FilterTags extends SuiteTest implements ISuiteTest { } precheck(conditions: AssertWrap): void { - conditions.toBeOk(this.singleLetterTagsReturned.length > 0, 'sample data size is sufficient for test'); + conditions.toBeOk(this.tagsSampled.length > 0, 'sample data size is sufficient for test'); } get filters(): INip01Filter[] { @@ -41,14 +41,13 @@ export class FilterTags extends SuiteTest implements ISuiteTest { } test({behavior}){ - const numTagsReturned = this.singleLetterTagsReturned.length const returnedOnlyTagsRequested = this.singleLetterTagsReturned.some((item: string[]) => { const key = this.tagsSampled[0] const value = this.tagsSampled[1] return item[0] === key && item[1] === value }); behavior.toBeOk(returnedOnlyTagsRequested, `returned only requested tags: ${truncate(JSON.stringify(this.singleLetterTagsReturned))}`); - behavior.toEqual(numTagsReturned, this.limit, 'returned only requested number of events'); + behavior.toEqual(this.totalEvents, this.limit, 'returned only requested number of events'); } } diff --git a/src/nips/Nip11/tests/ValidateSchema.ts b/src/nips/Nip11/tests/ValidateSchema.ts index 3a2a18a..9d58254 100644 --- a/src/nips/Nip11/tests/ValidateSchema.ts +++ b/src/nips/Nip11/tests/ValidateSchema.ts @@ -39,7 +39,7 @@ export class ValidateSchema extends SuiteTest implements ISuiteTest { .catch((e) => { //console.log('catch', e.message) // this.resulter.set('reason', e.message) - this.resulter.set('passing', false) + this.resulter.set('pass', false) }); this.data = data } diff --git a/src/nips/Nip50/tests/Search.ts b/src/nips/Nip50/tests/Search.ts index 8e3a7a4..0124909 100644 --- a/src/nips/Nip50/tests/Search.ts +++ b/src/nips/Nip50/tests/Search.ts @@ -4,6 +4,7 @@ import { ISuite } from '#base/Suite.js'; import { INip01Filter, Note, RelayEventMessage } from '#nips/Nip01/interfaces/index.js'; import { ContentIngestor } from '../ingestors/ContentIngestor.js'; +import { AssertWrap } from '#src/base/Expect.js'; export interface Nip50Filter extends INip01Filter { search: string; @@ -22,9 +23,8 @@ export class Search extends SuiteTest implements ISuiteTest { get filters(): Nip50Filter[] { const filters: Nip50Filter[] = []; - this.searchTermsToFilter = this.ingestor.poop() as string[]; - if(this.searchTermsToFilter.length > 5){ - this.searchTermsToFilter.length = 5; + if(this.searchTermsToFilter.length > 1){ + this.searchTermsToFilter.length = 1; } for(const search of this.searchTermsToFilter){ filters.push({ search, limit:1 }); @@ -37,12 +37,15 @@ export class Search extends SuiteTest implements ISuiteTest { this.contentsRecievedWithTerms.push(note.content); } - test({behavior, conditions}) { - conditions.toBeOk(this.searchTermsToFilter.length > 0, 'data sample size is sufficient for test'); + digest(){ + this.searchTermsToFilter = this.getSamples(); + } - console.log(this.searchTermsToFilter) - console.log(this.contentsRecievedWithTerms) + precheck(conditions: AssertWrap): void { + conditions.toBeOk(this.searchTermsToFilter.length > 0, 'data sample size is sufficient for test'); + } + test({behavior, conditions}) { const eventsContainedTerms = this.contentsRecievedWithTerms.every(content => { return this.searchTermsToFilter.some(term => { const regex = new RegExp(term, 'i');