# database-profile-plugin **Repository Path**: mirrors_hibernate/database-profile-plugin ## Basic Information - **Project Name**: database-profile-plugin - **Description**: Support for testing against multiple databases via profiles - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-08-08 - **Last Updated**: 2025-08-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README = Database Profile Plugin == Goal The idea of this plugin is to extend Gradle with the idea of named database profiles that a user could choose between when running tests. This allows the project to define a single set of tests but have them run them against a dynamic set of databases. == Applying the plugin plugins { ... id 'org.hibernate.testing.database-profile' version 'X.Y.Z' } This applies a DSL extension of type `DslExtension` to the project under the name `databases`. The following sections will break down the available options... == What is a profile? A profile defines the information needed to run the tests against a particular database instance. This includes information like any dependencies needed, the connection URL, etc. `Profile` is the class describing a profile. A profile can be defined in a few different ways, but all will ultimately create a `Profile` which all get added to the `DslExtension#profiles` attribute which is a Gradle `NamedDomainObjectContainer`. === In-line profile definition A profile can be defined directly in the `databases` DSL extension. E.g.: build.gradle ---- databases { ... profiles { // creates a Profile named "h2" h2 { hibernateProperty 'hibernate.connection.url', 'jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=10000' hibernateProperty 'hibernate.connection.username', 'sa' hibernateProperty 'hibernate.connection.password', 'sa' dependency 'com.h2database:h2:1.4.196' } } } ---- == Profile fragments Profiles can also be defined using a Gradle fragment file. The fragment is applied relative to the `profiles` `NamedDomainObjectContainer` == Basics The selection of a profile might imply a number of actions that must occur based on the profile selected - we might need to add extra jars to the `testRuntime` configuration, adjust properties files, etc. When applied, the plugin will: 1. Create a task named `applyDatabaseProfile` of type `ProfileTask` 2. For every available profile (see below), create a task named `processTestResources_` and a task named `test_` which do what they sound like they'd do :) `applyDatabaseProfile` is added to `processTestResources` as a finalizer. Each `test_` task is finalized by `test`. Each `processTestResources_` task depends on `processTestResources` and is finalized by `applyDatabaseProfile` [IMPORTANT] ---- Only one such `processTestResources_` or `test_` can be done at once ---- == Defining Profiles Available profiles are resolved using a directory search, as follows: 1. If the project is non-root, see if it defines a `${projectDir}/databases/` directory. If it does then search here first 2. If any custom search directories have been added, check these next. Custom directories can be added by specifying a `custom-profiles-dir` build property 3. Finally look at the project's parent project for a `${projectDir}/databases/` directory, up to the root project These directories are searched recursively. We leverage this in Hibernate to allow the standard _databases_ directory to hold local profiles too. That is achieved by a _.gitignore_ which says to ignore any directory named _local_ under the directory _databases_. So one option to provide custom profiles is to drop them in there. That has the benefit of not having to specify _custom_profiles_dir_ build property. Within these directories, the plugin looks for sub-directories which either: * contain a file named _matrix.gradle_. _matrix.gradle_ is a limited DSL Gradle file which currently understands just a specialized org.gradle.api.artifacts.Configuration reference named _jdbcDependency_. All that is a fancy way to say that _matrix.gradle_ allows you to specify some dependencies this database profile needs (JDBC drivers, etc). Any dependency artifacts named here get resolved using whatever resolvers (Maven, etc) are associated with the build. For example jdbcDependency { "mysql:mysql-connector-java:5.1.17" } * contain a directory named _jdbc_ which is assumed to hold jar file(s) needed for the profile. Such directories become the basis of a database profile made available to the build. The name of the profile is taken from the directory name. Database profiles can also contain a _resources_ directory. An example layout using _jdbc_ directory approach: ├── mysql50 │ ├── jdbc │ │ └── mysql-connector-java-5.1.9.jar │ └── resources │ └── hibernate.properties versus using _matrix.gradle_: ├── mysql50 │ ├── matrix.gradle │ └── resources │ └── hibernate.properties Either would result in a database profile named _mysql50_ ==Specifying the profile to use The profile to use can be specified in 2 ways: 1. Set `database_profile_name` build property to the name of the profile to use 2. Calling one of the `processTestResources_` or `test_` tasks == Plugin behavior During evaluation phase, the plugin locates all available profiles (see `ProfileLoader`) and creates the `applyDatabaseProfile` task (see `ProfileTask`). It delays as long as possible the determination of the specific profile to use. This is needed to make `processTestResources_` and `test_` tasks work. If no profile name is specified the behavior is to not perform any of the task actions. The task can contain 3 types of actions: * `ProfileTask#augment` * `ProfileTask#filterCopy` * `ProfileTask#extend` By default the plugin will overlay the profile's properties over top of the `${buildDir}/resources/test/hibernate.properties` file. This is a process called augmentation - a properties file is loaded into a `Properties` object and then the profile's properties are added over top of them and then written back out. A custom properties file augmentation can be requested using `ProfileTask#augment`. Builds can also request a filtered-copy using `ProfileTask#filterCopy`. A filtered-copy is basically a copy based on the provided CopySpec config closure extended profile properties replacements. E.g., Hibernate ORM uses this to process the `bundles` directory used to test JPA deployments) - used to replace info in XML, properties, etc Lastly, pretty generic actions can be requested using `ProfileTask#extend` which accepts an `Action` - during `doLast`, the task will call this action with the resolved profile. == Using with IDE Personally I plan to look again into having IntelliJ delegate to Gradle. That used to be dog slow, but maybe better today.... Anyway, you can also continue using the old `.. processTestResources -Pdb=derby copyResourcesToIntelliJOutFolder` approach. You can even do `... processTestResources_h2 copyResourcesToIntelliJOutFolder`. Once `applyDatabaseProfile` has applied the profile it will not re-apply the profile next time if either (a) profile name is null or (b) profile name is the same