Skip to content
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

Js/device testing #6964

Merged
merged 8 commits into from
Dec 1, 2023
Merged

Js/device testing #6964

merged 8 commits into from
Dec 1, 2023

Conversation

ironage
Copy link
Contributor

@ironage ironage commented Sep 8, 2023

First steps towards #6923
In order to run all the tests on a device, they need to be combined into a single application. This means invoking the core, sync and object-store tests all from the same runner. This new target is called CombinedTests. I have done this in a way that makes object libraries from all the sources, so that a developer can switch between the CombinedTests and an individual runner without having to recompile everything. The restructuring surfaced a cross project compile dependency in the TestUtil library which I solved in the code by replacing the outdated sync::PrimaryKey concept with Mixed.

To prove that this works, I changed the iOS simulator check on Jenkins to run the combined test app. This showed where we have sync tests relying on unimplemented code for the sync server on device, so I added guards on those sync tests to only compile them if we are not on a mobile platform. This allows the rest of the sync tests to run on.

☑️ ToDos

  • 📝 Changelog update
  • 🚦 Tests (or not relevant)
  • C-API, if public C++ API changed.

@cla-bot cla-bot bot added the cla: yes label Sep 8, 2023
@ironage ironage self-assigned this Sep 12, 2023
@ironage ironage marked this pull request as ready for review September 12, 2023 17:00
@@ -127,6 +127,7 @@ ClientHistory& get_history(DBRef db)
return get_replication(db).get_history();
}

#if !REALM_MOBILE // the server is not implemented on devices
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no functional changes to the code in this file, just moving tests under the !REALM_MOBILE flag if they used the server fixtures.

Comment on lines 31 to +32
c_api/c_api.cpp
c_api/c_api.c
c_api/c_api_file_tests.c
Copy link
Contributor Author

@ironage ironage Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

linking with cmake's OBJECT library exposed a bug that did not support two files of the same name because the system is looking for c_api.o and getting confused because it wasn't there (cmake generates two c_api_<id>.o files to differentiate the two)

@tgoyne
Copy link
Member

tgoyne commented Sep 13, 2023

Why do we need all of the tests combined into a single app? We can't just run each of the separate apps in parallel?

@ironage
Copy link
Contributor Author

ironage commented Sep 13, 2023

I'm not sure, that might be possible. @fealebenpae asked for this to help unblock him because it would simplify connecting to the device farm.


add_executable(CoreTests main.cpp test_all.cpp ${REQUIRED_TEST_FILES})
target_sources(CoreTests PUBLIC $<TARGET_OBJECTS:CoreTestLib>)
target_sources(CoreTests PUBLIC $<TARGET_OBJECTS:TestUtil>)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we link against TestUtil as a normal library instead of just including the object files directly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, my understanding is that object libraries are just a build time optimization for when the archive file is large enough that creating it takes a meaningful amount of time and space, but TestUtil hopefully is very small. If we're having to work around any of the object library quirks then we should probably just use a static library?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted TestUtil back to a static library.


if(MSVC)
# increase the number of sections supported in an obj file for the heavily templated tests
target_compile_options(CombinedTests PRIVATE /bigobj)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this make sense on the CombinedTests target? It's not actually compiling the source files where /bigobj is needed, aren't those part of the *TestLib targets?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed 👍

target_sources(CombinedTests PUBLIC $<TARGET_OBJECTS:ObjectStoreTestLib>)
if(REALM_ENABLE_SYNC)
target_sources(CombinedTests PUBLIC $<TARGET_OBJECTS:SyncTestLib>)
target_link_libraries(CombinedTests ObjectStoreTestLib CoreTestLib SyncTestLib Sync SyncServer Storage TestUtil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

target_sources with the $<TARGET_OBJECTS:myTgt> generator expression explicitly includes the object files in the link phase, target_link_libraries where one of the targets is an OBJECT library implies it. Only one should be necessary, I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. It turns out that target_sources just links the source files while target_link_libraries will do that as well as linking any transitively linked dependencies from the targets. The latter is what we want as it simplifies everything.

@@ -50,7 +50,7 @@ if(REALM_ENABLE_SYNC)
)
endif()

add_library(TestUtil STATIC ${TEST_UTIL_SOURCES} ${TEST_UTIL_HEADERS})
add_library(TestUtil OBJECT ${TEST_UTIL_SOURCES} ${TEST_UTIL_HEADERS})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think TestUtil has to be an OBJECT library, it can stay as static.

@fealebenpae
Copy link
Member

In order to run this on an actual device on iOS we need to set up a proper app machinery with an entrypoint ViewController, I think, which only needs to call into combined_tests.cpp's main() in -viewDidLoad. AFAIK on iOS the system watchdog will kill the app if it hasn't started processing app lifecycle messages on its main thread within a few seconds so we can't just block in our main() without calling UIApplicationMain() with an appropriate delegate.

@fealebenpae
Copy link
Member

@tgoyne we're gearing up for running tests on AWS Device Farm devices and it's gonna save us a lot of time per run if we run all the tests in a combined package, instead of in parallel, and it will save on boilerplate in CI to set the runs up as well. This additional overhead is why we never bothered to run sync tests on iOS or Android simulator/emulators until now, for example.

@tgoyne
Copy link
Member

tgoyne commented Sep 15, 2023

Why would it save any time per run?

The only reason we weren't running sync tests on iOS was because they needed the changes here to be able to compile on iOS, not because there was anything difficult about executing them. I had actually set everything up to run the sync tests in the ios simulator on Jenkins and then commented it out when I discovered that the tests didn't compile.

@fealebenpae
Copy link
Member

Why would it save any time per run?

This is strictly for AWS Device Farm. When running the .NET tests on an Android device there the actual tests run in ~4 minutes, but the total step is ~9 minutes. I have seen similar overhead when doing manual tests with iOS devices on Device Farm. AWS just has some overhead for setting up and winding down tests on devices that we can avoid if we group tests together instead of in distinct executables.

@tgoyne
Copy link
Member

tgoyne commented Sep 15, 2023

Ah, that makes sense then.

@coveralls-official
Copy link

coveralls-official bot commented Sep 15, 2023

Pull Request Test Coverage Report for Build james.stone_439

  • 433 of 500 (86.6%) changed or added relevant lines in 5 files are covered.
  • 53 unchanged lines in 11 files lost coverage.
  • Overall coverage increased (+0.02%) to 91.681%

Changes Missing Coverage Covered Lines Changed/Added Lines %
test/util/compare_groups.cpp 20 28 71.43%
test/object-store/test_runner.cpp 101 160 63.13%
Files with Coverage Reduction New Missed Lines %
src/realm/sync/noinst/client_impl_base.hpp 1 93.91%
src/realm/sync/noinst/server/server.cpp 1 76.02%
test/test_query2.cpp 1 99.08%
src/realm/table_view.cpp 2 94.18%
src/realm/sort_descriptor.cpp 3 93.7%
src/realm/util/file.cpp 3 81.73%
src/realm/alloc_slab.cpp 5 92.89%
src/realm/index_string.cpp 6 87.84%
src/realm/bplustree.cpp 7 75.72%
src/realm/sync/noinst/client_impl_base.cpp 10 85.13%
Totals Coverage Status
Change from base Build 1873: 0.02%
Covered Lines: 231791
Relevant Lines: 252824

💛 - Coveralls

@ironage
Copy link
Contributor Author

ironage commented Sep 19, 2023

In order to run this on an actual device on iOS we need to set up a proper app machinery with an entrypoint ViewController, I think, which only needs to call into combined_tests.cpp's main() in -viewDidLoad. AFAIK on iOS the system watchdog will kill the app if it hasn't started processing app lifecycle messages on its main thread within a few seconds so we can't just block in our main() without calling UIApplicationMain() with an appropriate delegate.

@fealebenpae I believe we can change test/unit-tests-ios/ViewController.mm to become like test/combined_tests.cpp and we should be good to go. Though I am not sure how to compile or run the project there. Do you know how, or should I reach out to the swift team for assistance?

@tgoyne
Copy link
Member

tgoyne commented Sep 21, 2023

I tried to run this locally on a device. It initially failed because the "Bundle name" field in Info.plist was empty. After manually setting that (and the development team) I was able to run the tests on device and it all passed. I'm not sure offhand how to set that field in cmake.

@ironage
Copy link
Contributor Author

ironage commented Nov 29, 2023

@tgoyne @fealebenpae how about we merge these build changes in as a first step. Then the final work to hook up devices can be done in a smaller PR when we get time for it? That would save this branch from going stale.

@ironage ironage merged commit e593a5f into master Dec 1, 2023
2 checks passed
@ironage ironage deleted the js/device-testing branch December 1, 2023 01:56
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants