Add standalone unit tests and CI workflow for Unreal GSDK#194
Conversation
|
@copilot can you amend the Unreal README to mention that these files are not needed, when someone uses the Unreal GSDK? |
Added a "Directory structure" section to |
|
@copilot can you try again? |
Revised the README section in |
|
@copilot can you rebase? |
|
@copilot can you rebase? |
Rebased onto latest |
Co-authored-by: dgkanatsios <8256138+dgkanatsios@users.noreply.github.com>
…es are needed Co-authored-by: dgkanatsios <8256138+dgkanatsios@users.noreply.github.com>
…ecific files to copy Co-authored-by: dgkanatsios <8256138+dgkanatsios@users.noreply.github.com>
* Initial plan * Initial plan for Java GSDK unit tests Co-authored-by: dgkanatsios <8256138+dgkanatsios@users.noreply.github.com> * Add Java GSDK unit tests and CI workflow Add 84 unit tests across 8 test classes covering: - ConnectedPlayer data class - SessionHostHeartbeatInfo getters/setters and JSON deserialization - SessionConfig including ToMapAllStrings - Operation enum Gson serialization with @SerializedName casings - MaintenanceSchedule/MaintenanceEvent deserialization - JsonFileConfiguration config file parsing and validation - GameHostHealth/SessionHostStatus enum values - GameserverSDK public API constant keys Add .github/workflows/java-tests.yml CI workflow to run tests on PRs. Co-authored-by: dgkanatsios <8256138+dgkanatsios@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: dgkanatsios <8256138+dgkanatsios@users.noreply.github.com>
97b0ef1 to
4fae61a
Compare
There was a problem hiding this comment.
Pull request overview
Adds standalone (non-Unreal) C++ unit tests for the Unreal GSDK JSON contracts and wires them into CI, plus updates Unreal plugin documentation to clarify which files are required for integration.
Changes:
- Introduces standalone GoogleTest-based C++ tests under
UnrealPlugin/Tests(CMake + FetchContent + nlohmann/json). - Adds a GitHub Actions workflow to build/run those tests on PRs that touch
UnrealPlugin/**. - Updates Unreal plugin docs to explicitly list which plugin files/folders should be copied into a game project.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
UnrealPlugin/ThirdPersonMPGSDKSetup.md |
Clarifies which UnrealPlugin artifacts to copy into Plugins/PlayFabGSDK. |
UnrealPlugin/Tests/GSDKHeartbeatTests.cpp |
Adds standalone tests for heartbeat request/response JSON and operation handling. |
UnrealPlugin/Tests/GSDKConfigTests.cpp |
Adds standalone tests for JSON config parsing/round-tripping. |
UnrealPlugin/Tests/CMakeLists.txt |
CMake project for building/running the standalone Unreal GSDK tests. |
UnrealPlugin/README.md |
Adds “Plugin files” section describing minimal files needed for integration. |
.github/workflows/unreal-tests.yml |
New CI workflow to configure/build/ctest the standalone Unreal tests on PRs. |
| // Parse heartbeat interval | ||
| if (j.contains("nextHeartbeatIntervalMs")) | ||
| { | ||
| result.nextHeartbeatIntervalMs = j["nextHeartbeatIntervalMs"].get<int>(); | ||
| } | ||
|
|
There was a problem hiding this comment.
DecodeHeartbeatResponse only copies nextHeartbeatIntervalMs from JSON and returns it as-is. In the real Unreal implementation (FGSDKInternal::DecodeHeartbeatResponse), the interval is clamped to the configured minimum and defaults to the minimum when the field is missing. Consider modeling that behavior in this helper (e.g., pass/define a minimum interval and apply the clamp/default) so the standalone tests assert the same semantics as the plugin code.
| TEST_F(HeartbeatResponseTest, MissingHeartbeatIntervalDefaultsToZero) | ||
| { | ||
| std::string responseJson = R"({ | ||
| "operation":"Continue" | ||
| })"; | ||
|
|
||
| auto response = DecodeHeartbeatResponse(responseJson); | ||
| EXPECT_EQ(response.nextHeartbeatIntervalMs, 0); |
There was a problem hiding this comment.
This test asserts that a missing nextHeartbeatIntervalMs defaults to 0, but the Unreal GSDK sets NextHeartbeatIntervalMs to MinimumHeartbeatInterval when the field is absent. Updating the test expectation (and/or the standalone decode helper) to match the plugin behavior will prevent documenting an incorrect contract.
| TEST_F(HeartbeatResponseTest, MissingHeartbeatIntervalDefaultsToZero) | |
| { | |
| std::string responseJson = R"({ | |
| "operation":"Continue" | |
| })"; | |
| auto response = DecodeHeartbeatResponse(responseJson); | |
| EXPECT_EQ(response.nextHeartbeatIntervalMs, 0); | |
| TEST_F(HeartbeatResponseTest, MissingHeartbeatIntervalDefaultsToMinimum) | |
| { | |
| // Matches FConfigurationBase::GetMinimumHeartbeatInterval | |
| const int minimumHeartbeatInterval = 1000; | |
| std::string responseJson = R"({ | |
| "operation":"Continue" | |
| })"; | |
| auto response = DecodeHeartbeatResponse(responseJson); | |
| EXPECT_EQ(response.nextHeartbeatIntervalMs, minimumHeartbeatInterval); |
| static constexpr const char* TEST_DIR = "/tmp/gsdk_config_tests"; | ||
| std::string configFilePath; | ||
|
|
||
| void SetUp() override | ||
| { | ||
| std::filesystem::create_directories(TEST_DIR); | ||
| configFilePath = std::string(TEST_DIR) + "/testConfig.json"; | ||
| } |
There was a problem hiding this comment.
The tests write to a fixed /tmp/gsdk_config_tests/testConfig.json path. This is not portable (e.g., Windows) and can cause collisions if tests are run in parallel. Prefer using std::filesystem::temp_directory_path() plus a unique subdirectory/filename (e.g., std::filesystem::unique_path) and clean it up in TearDown().
| std::ofstream file(configFilePath); | ||
| file << config.dump(4); | ||
| } | ||
|
|
||
| json ReadConfigFromFile() | ||
| { | ||
| std::ifstream file(configFilePath); |
There was a problem hiding this comment.
WriteConfigToFile and ReadConfigFromFile don't verify that the file streams opened successfully before writing/parsing. Adding assertions (e.g., ASSERT_TRUE(file.is_open())) will make failures much easier to diagnose if the temp path is not writable or the file can't be created.
| std::ofstream file(configFilePath); | |
| file << config.dump(4); | |
| } | |
| json ReadConfigFromFile() | |
| { | |
| std::ifstream file(configFilePath); | |
| std::ofstream file(configFilePath); | |
| ASSERT_TRUE(file.is_open()) << "Failed to open config file for writing: " << configFilePath; | |
| file << config.dump(4); | |
| } | |
| json ReadConfigFromFile() | |
| { | |
| std::ifstream file(configFilePath); | |
| EXPECT_TRUE(file.is_open()) << "Failed to open config file for reading: " << configFilePath; | |
| if (!file.is_open()) | |
| { | |
| return json(); | |
| } |
.github/workflows/unreal-tests.ymlfor PRs affectingUnrealPlugin/**UnrealPlugin/README.mdclarifying which files are needed for integrationUnrealPlugin/ThirdPersonMPGSDKSetup.mdto list specific files to copy✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.