-
-
Notifications
You must be signed in to change notification settings - Fork 253
Add Oracle Free module #1242
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
collinmurd
wants to merge
12
commits into
testcontainers:main
Choose a base branch
from
collinmurd:main
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.
+356
−0
Open
Add Oracle Free module #1242
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
93f1402
created oraclefree module
collinmurd 9e61da1
add connection test & fix container env inputs
collinmurd a7ceceb
additional tests
collinmurd ab63cf3
some inline docs
collinmurd 969c970
use faststart to speed up tests a bit
collinmurd 534b70b
add index
collinmurd 833ebe3
fix formatting
collinmurd 30af900
oracle free docs
collinmurd 45966b7
fix oraclefree package
collinmurd 772a1bd
withDatabase validation
collinmurd 00bf441
treat default container name as no-op
collinmurd 3a1bb73
fix typo
collinmurd 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,23 @@ | ||
| # Oracle Free | ||
|
|
||
| ## Install | ||
|
|
||
| ```bash | ||
| npm install @testcontainers/oraclefree --save-dev | ||
| ``` | ||
|
|
||
| ## Examples | ||
|
|
||
| These examples use the following libraries: | ||
|
|
||
| - [oracledb](https://www.npmjs.com/package/oracledb) | ||
|
|
||
| npm install oracledb | ||
|
|
||
| Recommended to use an image from [this registry](https://hub.docker.com/r/gvenzl/oracle-free) and substitute for `IMAGE` | ||
|
|
||
| ### Start a database and execute queries | ||
|
|
||
| <!--codeinclude--> | ||
| [](../../packages/modules/oraclefree/src/oraclefree-container.test.ts) inside_block:customDatabase | ||
| <!--/codeinclude--> |
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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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 @@ | ||
| FROM gvenzl/oracle-free:slim-faststart | ||
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,39 @@ | ||
| { | ||
| "name": "@testcontainers/oraclefree", | ||
| "version": "11.12.0", | ||
| "license": "MIT", | ||
| "keywords": [ | ||
| "oracle", | ||
| "database", | ||
| "testing", | ||
| "docker", | ||
| "testcontainers" | ||
| ], | ||
| "description": "Oracle DB Free module for Testcontainers", | ||
| "homepage": "https://github.com/testcontainers/testcontainers-node#readme", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/testcontainers/testcontainers-node.git" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/testcontainers/testcontainers-node/issues" | ||
| }, | ||
| "main": "build/index.js", | ||
| "files": [ | ||
| "build" | ||
| ], | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "scripts": { | ||
| "prepack": "shx cp ../../../README.md . && shx cp ../../../LICENSE .", | ||
| "build": "tsc --project tsconfig.build.json" | ||
| }, | ||
| "dependencies": { | ||
| "testcontainers": "^11.12.0" | ||
| }, | ||
| "devDependencies": { | ||
| "oracledb": "^6.10.0", | ||
| "@types/oracledb": "^6.10.0" | ||
| } | ||
| } |
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 @@ | ||
| export { OracleDbContainer, StartedOracleDbContainer } from "./oraclefree-container"; |
107 changes: 107 additions & 0 deletions
107
packages/modules/oraclefree/src/oraclefree-container.test.ts
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,107 @@ | ||
| import oracledb from "oracledb"; | ||
| import { getImage } from "../../../testcontainers/src/utils/test-helper"; | ||
| import { OracleDbContainer, StartedOracleDbContainer } from "./oraclefree-container"; | ||
|
|
||
| const IMAGE = getImage(__dirname); | ||
|
|
||
| describe.sequential("OracleFreeContainer", { timeout: 240_000 }, () => { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These can run in parallel |
||
| describe("default configuration", () => { | ||
| let container: StartedOracleDbContainer; | ||
|
|
||
| beforeAll(async () => { | ||
| container = await new OracleDbContainer(IMAGE).start(); | ||
| }, 120_000); | ||
|
|
||
| afterAll(async () => { | ||
| await container.stop(); | ||
| }); | ||
|
|
||
| it("should connect and return a query result", async () => { | ||
| const connection = await oracledb.getConnection({ | ||
| user: container.getUsername(), | ||
| password: container.getPassword(), | ||
| connectString: container.getUrl(), | ||
| }); | ||
|
|
||
| const result = await connection.execute("SELECT 1 FROM DUAL"); | ||
| expect(result.rows![0]).toEqual([1]); | ||
|
|
||
| await connection.close(); | ||
| }); | ||
|
|
||
| it("should work with connection descriptor", async () => { | ||
| const connection = await oracledb.getConnection({ | ||
| user: container.getUsername(), | ||
| password: container.getPassword(), | ||
| connectString: container.getConnectionDescriptor(), | ||
| }); | ||
|
|
||
| const result = await connection.execute("SELECT 1 FROM DUAL"); | ||
| expect(result.rows![0]).toEqual([1]); | ||
|
|
||
| await connection.close(); | ||
| }); | ||
|
|
||
| it("should work with restarted container", async () => { | ||
| await container.restart(); | ||
|
|
||
| const connection = await oracledb.getConnection({ | ||
| user: container.getUsername(), | ||
| password: container.getPassword(), | ||
| connectString: container.getUrl(), | ||
| }); | ||
|
|
||
| const result = await connection.execute("SELECT 1 FROM DUAL"); | ||
| expect(result.rows![0]).toEqual([1]); | ||
|
|
||
| await connection.close(); | ||
| }); | ||
|
|
||
| it("should have default database name", async () => { | ||
| const connection = await oracledb.getConnection({ | ||
| user: container.getUsername(), | ||
| password: container.getPassword(), | ||
| connectString: container.getUrl(), | ||
| }); | ||
|
|
||
| const result = await connection.execute("SELECT SYS_CONTEXT('USERENV', 'CON_NAME') FROM DUAL"); | ||
| expect(result.rows![0]).toEqual(["FREEPDB1"]); | ||
|
|
||
| await connection.close(); | ||
| }); | ||
| }); | ||
|
|
||
| it("should treat default database names as no-op and reject empty names", () => { | ||
| const container = new OracleDbContainer(IMAGE); | ||
| expect(() => container.withDatabase("FREEPDB1")).not.toThrow(); | ||
| expect(() => container.withDatabase("freepdb1")).not.toThrow(); | ||
| expect(() => container.withDatabase("")).toThrow("Database name cannot be empty."); | ||
| }); | ||
|
|
||
| it("should set the custom database and user", async () => { | ||
| // customDatabase { | ||
| const customDatabase = "TESTDB"; | ||
| const customUsername = "CUSTOMUSER"; | ||
| const customPassword = "customPassword"; | ||
| await using container = await new OracleDbContainer(IMAGE) | ||
| .withDatabase(customDatabase) | ||
| .withUsername(customUsername) | ||
| .withPassword(customPassword) | ||
| .start(); | ||
|
|
||
| const connection = await oracledb.getConnection({ | ||
| user: container.getUsername(), | ||
| password: container.getPassword(), | ||
| connectString: container.getUrl(), | ||
| }); | ||
|
|
||
| const result = await connection.execute("SELECT SYS_CONTEXT('USERENV', 'CON_NAME') FROM DUAL"); | ||
| expect(result.rows![0]).toEqual([customDatabase]); | ||
|
|
||
| const resultUser = await connection.execute("SELECT USER FROM DUAL"); | ||
| expect(resultUser.rows![0]).toEqual([customUsername]); | ||
|
|
||
| await connection.close(); | ||
| // } | ||
| }); | ||
| }); | ||
115 changes: 115 additions & 0 deletions
115
packages/modules/oraclefree/src/oraclefree-container.ts
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,115 @@ | ||
| import { AbstractStartedContainer, GenericContainer, StartedTestContainer, Wait } from "testcontainers"; | ||
|
|
||
| /** Default Oracle listener port. */ | ||
| const ORACLEDB_PORT = 1521; | ||
| /** Default pluggable database name provided by the Oracle Free image. */ | ||
| const DEFAULT_DATABASE = "FREEPDB1"; | ||
|
|
||
| /** | ||
| * Testcontainers wrapper for Oracle Free. | ||
| * | ||
| * Supports configuring application user credentials and optional custom database creation. | ||
| */ | ||
| export class OracleDbContainer extends GenericContainer { | ||
| private username = "test"; | ||
| private password = "test"; | ||
| private database?: string = undefined; | ||
|
|
||
| constructor(image: string) { | ||
| super(image); | ||
| this.withExposedPorts(ORACLEDB_PORT); | ||
| this.withWaitStrategy(Wait.forLogMessage("DATABASE IS READY TO USE!")); | ||
| this.withStartupTimeout(120_000); | ||
| } | ||
|
|
||
| /** Sets the application username created at container startup. */ | ||
| public withUsername(username: string): this { | ||
| this.username = username; | ||
| return this; | ||
| } | ||
|
|
||
| /** Sets the password for both SYS and application user startup configuration. */ | ||
| public withPassword(password: string): this { | ||
| this.password = password; | ||
| return this; | ||
| } | ||
|
|
||
| /** Sets a custom application database/service name. */ | ||
| public withDatabase(database: string): this { | ||
collinmurd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (database.trim() === "") { | ||
| throw new Error("Database name cannot be empty."); | ||
| } | ||
|
|
||
| if (database.toUpperCase() === DEFAULT_DATABASE) { | ||
| this.database = undefined; | ||
| return this; | ||
| } | ||
|
|
||
| this.database = database; | ||
| return this; | ||
| } | ||
|
|
||
| /** Starts the container and returns a typed started container instance. */ | ||
| public override async start(): Promise<StartedOracleDbContainer> { | ||
| this.withEnvironment({ | ||
| ORACLE_PASSWORD: this.password, | ||
| APP_USER: this.username, | ||
| APP_USER_PASSWORD: this.password, | ||
| }); | ||
|
|
||
| if (this.database) { | ||
| this.withEnvironment({ | ||
| ORACLE_DATABASE: this.database, | ||
| }); | ||
| } | ||
|
|
||
| return new StartedOracleDbContainer( | ||
| await super.start(), | ||
| this.username, | ||
| this.password, | ||
| this.database ?? DEFAULT_DATABASE | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /** Represents a running Oracle Free test container with Oracle-specific accessors. */ | ||
| export class StartedOracleDbContainer extends AbstractStartedContainer { | ||
| constructor( | ||
| startedTestContainer: StartedTestContainer, | ||
| private readonly username: string, | ||
| private readonly password: string, | ||
| private readonly database: string | ||
| ) { | ||
| super(startedTestContainer); | ||
| } | ||
|
|
||
| /** Returns the mapped Oracle listener port. */ | ||
| public getPort(): number { | ||
| return this.getMappedPort(ORACLEDB_PORT); | ||
| } | ||
|
|
||
| /** Returns the configured application username. */ | ||
| public getUsername(): string { | ||
| return this.username; | ||
| } | ||
|
|
||
| /** Returns the configured password. */ | ||
| public getPassword(): string { | ||
| return this.password; | ||
| } | ||
|
|
||
| /** Returns the configured service/database name. */ | ||
| public getDatabase(): string { | ||
| return this.database; | ||
| } | ||
|
|
||
| /** Returns a host:port/database URL fragment. */ | ||
| public getUrl(): string { | ||
| return `${this.getHost()}:${this.getPort()}/${this.database}`; | ||
| } | ||
|
|
||
| /** Returns an Oracle connection descriptor string (TNS format). */ | ||
| public getConnectionDescriptor(): string { | ||
| return `(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=${this.getHost()})(PORT=${this.getPort()}))(CONNECT_DATA=(SERVICE_NAME=${this.database})))`; | ||
| } | ||
| } | ||
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,12 @@ | ||
| { | ||
| "extends": "./tsconfig.json", | ||
| "exclude": [ | ||
| "build", | ||
| "src/**/*.test.ts" | ||
| ], | ||
| "references": [ | ||
| { | ||
| "path": "../../testcontainers" | ||
| } | ||
| ] | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's pin the image version,
gvenzl/oracle-free:23.26.1-slim-faststartis equivalent to current latest. Dependabot will keep it up to date and will catch future breaking changes