-
Notifications
You must be signed in to change notification settings - Fork 1
#29 : Add fixture validation for benchmark workspaces (fail-fast) #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
defender-777
wants to merge
4
commits into
edouardmisset:main
Choose a base branch
from
defender-777:feature/fix-validation
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
45969a2
#29 issue resolved; feat: add fixture validation for benchmark worksp…
defender-777 b1b94c3
fix: address review feedback (Codacy and CodeRabbit)
defender-777 643713d
fix: strengthen dynamic import validation and clarify error handling
defender-777 6ebc21b
refactor: improve dynamic import safety and reduce unnecessary suppre…
defender-777 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| import { getAllWorkspaceConfigs } from './deno-config.ts' | ||
| import { validateFixturesOrThrow } from './validate-fixtures.ts' | ||
|
|
||
| /** | ||
| * Main benchmark runner script. | ||
| * Validates fixtures before running any benchmarks. | ||
| */ | ||
| async function main(): Promise<void> { | ||
| try { | ||
| const workspaces = await getAllWorkspaceConfigs() | ||
| globalThis.console.log(` Validating ${workspaces.length} workspace fixtures...\n`) | ||
|
|
||
| // Validate all fixtures before running benchmarks (fail fast) | ||
| await validateFixturesOrThrow() | ||
|
|
||
| globalThis.console.log(' All workspace fixtures are valid!\n') | ||
|
|
||
| // TODO: Add actual benchmark execution here | ||
| // For now, this is a placeholder for future benchmark implementation | ||
| globalThis.console.log(' Benchmark execution would start here...') | ||
| globalThis.console.log(' (Benchmark runner implementation pending)\n') | ||
| } catch (error) { | ||
| // Print the detailed error message and exit with error code | ||
| globalThis.console.error(error instanceof Error ? error.message : String(error)) | ||
| Deno.exit(1) | ||
| } | ||
| } | ||
|
|
||
| // Run the main function | ||
| if (import.meta.main) { | ||
| await main() | ||
| } | ||
|
|
||
| // Made with Bob | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| /** | ||
| * Interface that all workspace fixtures must implement. | ||
| * Provides test data at different scales for benchmarking. | ||
| */ | ||
| export interface FixtureFactory { | ||
| /** | ||
| * Returns a small dataset for quick benchmarks | ||
| */ | ||
| small: () => unknown | ||
|
|
||
| /** | ||
| * Returns a medium-sized dataset for standard benchmarks | ||
| */ | ||
| medium: () => unknown | ||
|
|
||
| /** | ||
| * Returns a large dataset for stress testing | ||
| */ | ||
| large: () => unknown | ||
| } | ||
|
|
||
| // Made with Bob |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| import { exists } from '@std/fs' | ||
| import { join, toFileUrl } from '@std/path' | ||
| import { | ||
| getAllWorkspaceConfigs, | ||
| ROOT_DIRECTORY, | ||
| } from './deno-config.ts' | ||
| import type { FixtureFactory } from './fixture-types.ts' | ||
|
|
||
| /** Error details for a single workspace fixture validation failure */ | ||
| interface FixtureValidationError { | ||
| workspaceName: string | ||
| expectedPath: string | ||
| missing: string[] | ||
| } | ||
|
|
||
| /** Result of fixture validation across all workspaces */ | ||
| interface ValidationResult { | ||
| success: boolean | ||
| errors: FixtureValidationError[] | ||
| } | ||
|
|
||
| /** | ||
| * Validates that a workspace has a fixtures.ts file with required exports | ||
| * @param workspaceName - Name of the workspace to validate | ||
| * @returns Validation error if any, null if valid | ||
| */ | ||
| async function validateWorkspaceFixtures( | ||
| workspaceName: string, | ||
| ): Promise<FixtureValidationError | null> { | ||
| const fixturePath = join(ROOT_DIRECTORY, workspaceName, 'fixtures.ts') | ||
| const missing: string[] = [] | ||
|
|
||
| // Check if fixtures.ts exists | ||
| const fixtureExists = await exists(fixturePath) | ||
| if (!fixtureExists) { | ||
| missing.push('fixtures.ts file') | ||
| return { | ||
| workspaceName, | ||
| expectedPath: fixturePath, | ||
| missing, | ||
| } | ||
| } | ||
|
|
||
| // Try to import and validate exports | ||
| try { | ||
| // Use proper URL construction for cross-platform compatibility | ||
| const fixtureUrl = toFileUrl(fixturePath).href | ||
| const url = new URL(fixtureUrl) | ||
|
|
||
| // Validate that the import path is a safe local file URL | ||
| if (url.protocol !== 'file:') { | ||
| throw new Error(`Invalid fixture import path: ${fixtureUrl}`) | ||
| } | ||
|
|
||
| // codacy-disable-next-line | ||
| const fixtureModule = await import(url.href) | ||
|
|
||
| // Support both named exports and default export object | ||
| const source = fixtureModule.default ?? fixtureModule | ||
|
|
||
| // Validate required function exports | ||
| const requiredFunctions: (keyof FixtureFactory)[] = [ | ||
| 'small', | ||
| 'medium', | ||
| 'large', | ||
| ] | ||
|
|
||
| for (const functionName of requiredFunctions) { | ||
| if (typeof source[functionName] !== 'function') { | ||
| missing.push(`${functionName}() function`) | ||
| } | ||
| } | ||
|
|
||
| if (missing.length > 0) { | ||
| return { | ||
| workspaceName, | ||
| expectedPath: fixturePath, | ||
| missing, | ||
| } | ||
| } | ||
|
|
||
| return null | ||
| } catch (error) { | ||
| const errorMessage = error instanceof Error ? error.message : String(error) | ||
| missing.push(`valid fixtures.ts (import failed: ${errorMessage})`) | ||
| return { | ||
| workspaceName, | ||
| expectedPath: fixturePath, | ||
| missing, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Validates fixtures across all workspaces | ||
| * @returns Validation result with any errors found | ||
| */ | ||
| export async function validateAllFixtures(): Promise<ValidationResult> { | ||
| const workspaceConfigs = await getAllWorkspaceConfigs() | ||
| const errors: FixtureValidationError[] = [] | ||
|
|
||
| // Validate each workspace in parallel | ||
| const validationResults = await Promise.all( | ||
| workspaceConfigs.map(({ workspaceName }) => | ||
| validateWorkspaceFixtures(workspaceName) | ||
| ), | ||
| ) | ||
|
|
||
| // Collect errors | ||
| for (const result of validationResults) { | ||
| if (result !== null) { | ||
| errors.push(result) | ||
| } | ||
| } | ||
|
|
||
| return { | ||
| success: errors.length === 0, | ||
| errors, | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Formats validation errors into a readable error message | ||
| * @param errors - Array of validation errors | ||
| * @returns Formatted error message | ||
| */ | ||
| function formatValidationErrors(errors: FixtureValidationError[]): string { | ||
| const lines = [ | ||
| ' Fixture validation failed!\n', | ||
| `Found ${errors.length} workspace${errors.length === 1 ? '' : 's'} with missing or invalid fixtures:\n`, | ||
| ] | ||
|
|
||
| for (const error of errors) { | ||
| lines.push(`\n Workspace: ${error.workspaceName}`) | ||
| lines.push(` Path: ${error.expectedPath}`) | ||
| lines.push(` Missing: ${error.missing.join(', ')}`) | ||
| } | ||
|
|
||
| lines.push('\n\n Required: Each workspace must have a fixtures.ts file that exports:') | ||
| lines.push(' • small(): function returning small test dataset') | ||
| lines.push(' • medium(): function returning medium test dataset') | ||
| lines.push(' • large(): function returning large test dataset') | ||
| lines.push('\n Supports both named exports and default export object.') | ||
|
|
||
| return lines.join('\n') | ||
| } | ||
|
|
||
| /** | ||
| * Validates all workspace fixtures and throws if any are invalid | ||
| * @throws Error with detailed information about missing fixtures | ||
| */ | ||
| export async function validateFixturesOrThrow(): Promise<void> { | ||
| const result = await validateAllFixtures() | ||
|
|
||
| if (!result.success) { | ||
| // Errors are intentionally propagated and handled by bench.ts | ||
| throw new Error(formatValidationErrors(result.errors)) | ||
| } | ||
| } | ||
|
|
||
| // Made with Bob | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /** | ||
| * Fixture factory for array benchmarks | ||
| * Provides test data at different scales | ||
| */ | ||
|
|
||
| /** | ||
| * Returns a small dataset for quick benchmarks | ||
| */ | ||
| export function small(): number[] { | ||
| return Array.from({ length: 10 }, (_, index) => index) | ||
| } | ||
|
|
||
| /** | ||
| * Returns a medium-sized dataset for standard benchmarks | ||
| */ | ||
| export function medium(): number[] { | ||
| return Array.from({ length: 1000 }, (_, index) => index) | ||
| } | ||
|
|
||
| /** | ||
| * Returns a large dataset for stress testing | ||
| */ | ||
| export function large(): number[] { | ||
| return Array.from({ length: 100_000 }, (_, index) => index) | ||
| } | ||
|
|
||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.