Room Migration test failing : schema not found - testing

I'm try to implement android test for my room database, to test migrations. For this, I generated the schema needed, and I follow the step from the Android documentation.
When I run my migration test, it shows that the schema cannot be loaded, despite I added the assets line in the Gradle build. I added multiple other build types, it was not helping. I'm making something wrong, but I can't find where.
Room Version : 2.3.0
The error :
Cannot find the schema file in the assets folder. Make sure to include the exported json schemas in your test assert inputs. See https://developer.android.com/training/data-storage/room/migrating-db-versions#export-schema for details. Missing file: Asset file database.Sauvegarde/1.json not found
java.io.FileNotFoundException: Cannot find the schema file in the assets folder. Make sure to include the exported json schemas in your test assert inputs. See https://developer.android.com/training/data-storage/room/migrating-db-versions#export-schema for details. Missing file: Asset file database.Sauvegarde/1.json not found
at androidx.room.testing.MigrationTestHelper.loadSchema(MigrationTestHelper.java:326)
at androidx.room.testing.MigrationTestHelper.createDatabase(MigrationTestHelper.java:152)
at globalTests.migrations.MigrationTest.migrate1To2(MigrationTest.java:31)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:575)
at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:263)
at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
In test structure:
MigrationTest :
package globalTests.migrations;
import ...;
#RunWith(AndroidJUnit4.class)
public class MigrationTest {
private static final String TEST_DB = "migration-test";
#Rule
public MigrationTestHelper helper;
public MigrationTest() {
helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
Sauvegarde.class.getCanonicalName(),
new FrameworkSQLiteOpenHelperFactory());
}
#Test
public void migrate1To2() throws IOException {
SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);
// Prepare for the next version.
db.close();
// Re-open the database with version 2 and provide
// MIGRATION_1_2 as the migration process.
db = helper.runMigrationsAndValidate(TEST_DB, 2, true, Migrations.MIGRATION_1_2);
// MigrationTestHelper automatically verifies the schema changes,
// but you need to validate that the data was migrated properly.
}
}
gradle.build :
testOptions {
execution 'ANDROIDX_TEST_ORCHESTRATOR'
}
javaCompileOptions {
annotationProcessorOptions {
arguments += ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
sourceSets {
// Adds exported schema location as test app assets.
debug.assets.srcDirs += files("$projectDir/schemas".toString())
customDebugType.assets.srcDirs += files("$projectDir/schemas".toString())
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
test.assets.srcDirs += files("$projectDir/schemas".toString())
}
In schemas location :
The problem is like this one, but the solution not worked for me ...

Speaking from experience, one possible source of this issue is the stripping of assets during packaging, i.e., if you have something like the rule below. It seems like it should apply to the release build only, but, alas, it applies do debug as well and will remove your schema files from view.
buildTypes {
debug {...}
release {
aaptOptions {
ignoreAssetsPattern '!*.json'
}
}
}
Something else you could do is to look at what assets are visible to the various contexts you have available to you in the test itself:
println("Instrumentation context.assets")
var assets = InstrumentationRegistry.getInstrumentation().context.assets
assets.list("")?.forEachIndexed { index, it ->
println("$index -> $it")
}
println("Instrumentation targetContext.assets")
assets = InstrumentationRegistry.getInstrumentation().targetContext.assets
assets.list("")?.forEachIndexed { index, it ->
println("$index -> $it")
}
println("ApplicationProvider context.assets")
assets = ApplicationProvider.getApplicationContext<App>().assets
assets.list("")?.forEachIndexed { index, it ->
println("$index -> $it")
}

I found the problem,
Roboelectric didn't import my Android resources for the tests
you need to add this to Gradle:
testOptions {
unitTests{
includeAndroidResources = true
}
}
Source

Related

Unable to add duplicate strategy in gradle

Disclaimer: I am new to gradle, so it's likely I'm missing something simple.
Background: I am splitting a service into two services that will live in the same repo. The second service (tester) uses code from the first service (engine), which I have managed to tell gradle. But I have an issue.
Building the tester fails, giving the following error:
Execution failed for task ':engine:processResources'.
Entry application.properties is a duplicate but no duplicate handling strategy has been set
It seems this is a common issue in gradle that someone has already posted about. Unfortunately, pasting each of the responses in my build file has yielded nothing.
I've also tried the kotlin solutions in this thread with similar results: I keep getting the duplicate strategy not set error.
Surely I'm missing something but I can't for the life of me figure out what.
Tester build.gradle.kts Code
plugins {
kotlin("jvm") version "1.5.10"
kotlin("plugin.serialization") version "1.5.30"
id("net.linguica.maven-settings") version "0.5"
}
group = "my.group"
version = "1.0"
repositories {
mavenCentral()
maven(url = "my/url") {
name = "maven-snapshots"
authentication {
create<BasicAuthentication>("basic")
}
}
maven(url = "my/other/url") {
name = "maven-releases"
authentication {
create<BasicAuthentication>("basic")
}
}
}
//just trying all the things
rootProject.tasks.named("processResources", Copy::class.java) {
duplicatesStrategy = DuplicatesStrategy.WARN
}
tasks.withType<ProcessResources>() {
duplicatesStrategy = DuplicatesStrategy.WARN
}
tasks.withType<Copy>() {
duplicatesStrategy = DuplicatesStrategy.WARN
}
tasks.withType<Jar>() {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
dependencies {
implementation(project(":engine"))
}

Why do I need to reference a custom gradle config with square brackets?

I created a gradle build config just to download some dependencies. The documentation has been sparse, so I've piece together this working snippet based on random snippets and guesses.
configurations {
create("downloadDeps")
}
dependencies {
// JSON
configurations["downloadDeps"]("com.fasterxml.jackson.core:jackson-databind:2.13.3")
configurations["downloadDeps"]("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3")
}
repositories {
// internal repository
maven {
url = uri("...")
credentials {
username = System.getenv("ARTIFACTORY_USER") ?: System.getProperty("ARTIFACTORY_USER") as String
password = System.getenv("ARTIFACTORY_TOKEN") ?: System.getProperty("ARTIFACTORY_TOKEN") as String
}
}
}
tasks.register<Copy> ("downloadDeps") {
from(configurations["downloadDeps"])
into("lib/")
}
If I reference the "downloadDeps" dependency like configuration.downloadDeps or downloadDeps("com.fasterxml.jackson.core:jackson-databind:2.13.3"). I get an error about an unresolved reference to "downloadDeps".
Why does implementation("...") or configuration.implementation.get() work?
The documentation #Slaw provided helped me understand why I can do something like this:
implementation("group:artifact:1.0.0")
but not
myCustomConfig("group:artifact:1.0.0")
implementation being declared that way is supported because it comes from a plugin (the Kotlin/Java plugins)
The simplest way to associate a dependency with myCustomConfig would be to do this (see these docs):
"myCustomConfig"("group:artifact:1.0.0")

How to programmatically parse/retrieve user's parameters in Intellij project from Gradle build file

I need to retrieve some user specific parameters from Gradle build file in an Intellij project (build.gradle.kts)
Here a "build.gradle.kts" file content example I need to parse:
cutomParameters {
param1.set("any value")
sub_parameters1 {
sub_parameter1_1.set("foo")
}
subParameters2 {
subParameter21("foo")
subParameter22 {
subParameter221.set("foo")
}
}
}
I tried some code like this:
val connection: ProjectConnection =
GradleConnector.newConnector().forProjectDirectory(File(projectPath)).connect()
val model = connection.model(GradleBuild::class.java)
I can get the gradle build file using model.get().buildFile but how to retrieve the custom parameters described in the previous example?

Realm throws exception with empty unit test

In an Objective-C project, we started writing our new Unit Tests in Swift. I'm just now trying to create our first Unit Test of successfully saving the results of a parsed JSON. However, the test already fails during setup() due to the following error:
[ProjectTests.Project testInitializingOverlayCollectionCreatesAppropriateRealmObjects] : failed: caught "NSInvalidArgumentException", "+[RLMObjectBase ignoredProperties]: unrecognized selector sent to class 0x759b70
So apparently it tries to execute ignoredProperties on the RLMObjectBase class, and that method isn't implemented yet. Not sure how this happens, because I have yet to initialise anything, beyond creating a RLMRealms object with a random in-memory identifier.
ProjectTests.swift
import XCTest
class ProjectOverlayCollectionTests: XCTestCase {
var realm: RLMRealm!
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
let realmConfig = RLMRealmConfiguration()
realmConfig.inMemoryIdentifier = NSUUID().UUIDString
do {
realm = try RLMRealm(configuration: realmConfig) // <-- Crashes here.
}
catch _ as NSError {
XCTFail()
}
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testInitializingOverlayCollectionCreatesAppropriateRealmObjects() {
XCTAssertTrue(true)
}
}
Project-Bridging-Header.h
#import <Realm/Realm.h>
Podfile
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '7.1'
def shared_pods
pod 'Realm', '0.95.0'
end
target 'Project' do
shared_pods
end
target 'ProjectTests' do
shared_pods
end
As mentioned in the Realm documentation;
Avoid Linking Realm and Tested Code in Test Target
Remove the Realm pod from the ProjectTests target and all is right with the world.
Update: This answer is outdated. As #rommex mentions in a comment, following the current Realm installation documentation should link it to both your module and test targets without problems. However, I have not checked this.

Reusable aspects jar

We are going to start using aspectsJ in our production Java standalone apps soon. So, I am trying to come up with a jar that has aspects so I can weave them to the production apps without any code change.
I am trying to create a separate project (MyAspects.jar)for aspects and include them to the existing java class path to minimize code changes. While I am adding the aop.xml to the production application jar's META-INF folder.
While running the app, I am using -javaagent:pathto\aspectjweaver.jar and include MyAspects.jar in the folder that is on the classpath.
But when execute it, it errors out with below details. Including whole stacktrace.
I am using aspectjweaver-1.8.4.jar.
[AppClassLoader#553f5d07] info AspectJ Weaver Version 1.8.4 built on Thursday Nov 6, 2014 at 20:19:21 GMT
[AppClassLoader#553f5d07] info register classloader sun.misc.Launcher$AppClassLoader#553f5d07
[AppClassLoader#553f5d07] info using configuration file:/C:/riskEventLoader/lib/risk-event-loader.jar!/META-INF/aop.xml
[AppClassLoader#553f5d07] info register aspect com.aspect.generic.GenericAspect
Jan 12, 2015 8:37:15 AM org.aspectj.weaver.tools.Jdk14Trace error
SEVERE: register definition failed java.lang.RuntimeException: Cannot register non aspect: com$aspect$generic$GenericAspect , com.aspect.generic.GenericAspect
at org.aspectj.weaver.bcel.BcelWeaver.addLibraryAspect(BcelWeaver.java:219)
at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.registerAspects(ClassLoaderWeavingAdaptor.java:485)
at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.registerDefinitions(ClassLoaderWeavingAdaptor.java:304)
at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.initialize(ClassLoaderWeavingAdaptor.java:171)
at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.initialize(Aj.java:340)
at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.getWeavingAdaptor(Aj.java:345)
at org.aspectj.weaver.loadtime.Aj$WeaverContainer.getWeaver(Aj.java:319)
at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:113)
at org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:54)
at sun.instrument.TransformerManager.transform(TransformerManager.java:169)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:365)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Edit (by kriegaex):
I am adding some code snippets here which were previously posted as comments so as to make them more readable and qualify the question for reopening.
Aspect:
Please note that I have fixed some syntax errors, namely missing leading * signifying method return type in the two execution() pointcuts. I also simplified the logging statements.
package com.aspect.generic;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class GenericAspect {
#Pointcut("execution(* *(..))")
public void myTraceCall() {}
#Around("execution(* com.test.riskcheck..*(..))")
public Object myTrace(ProceedingJoinPoint thisJoinPoint) throws Throwable {
System.out.println("[BEFORE] " + thisJoinPoint);
Object retVal = null;
try {
retVal = thisJoinPoint.proceed();
} finally {
System.out.println("[AFTER] " + thisJoinPoint + " -> retval = " + retVal);
}
return retVal;
}
}
AspectJ LTW configuration file aop.xml:
I also simplified this file a bit. It still exposes the same problem as the one posted by the question's author for the same reason.
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<aspect name="com.aspect.generic.GenericAspect"/>
</aspects>
<weaver options="-verbose -showWeaveInfo">
<include within="com.test.riskcheck..*"/>
</weaver>
</aspectj>