Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/unity-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Unity GSDK Tests

on:
pull_request:
paths:
- 'UnityGsdk/**'
- '.github/workflows/unity-tests.yml'

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Build
run: dotnet build UnityGsdk/Tests/Tests.csproj

- name: Test
run: dotnet test UnityGsdk/Tests/Tests.csproj --no-build
3 changes: 3 additions & 0 deletions UnityGsdk/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ sysinfo.txt
# Crashlytics generated file
crashlytics-build.properties

# Allow test project files
!Tests/Tests.csproj

# Packed Addressables
/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*

Expand Down
8 changes: 7 additions & 1 deletion UnityGsdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ Yup, PlayFab SDK and GSDK would reside in different folders in your Unity projec

### What do I need to do in order to use the Unity GSDK in a new project?

You can drag the `PlayFabSDK` folder to your Unity project. After that, you need to enable the scripring directive `ENABLE_PLAYFABSERVER_API` on your Build settings, like in [this screenshot](https://user-images.githubusercontent.com/8256138/81462605-a6d7ac80-9168-11ea-9748-110ed01095c2.png)
You can drag the `Assets/PlayFabSdk` folder to your Unity project. After that, you need to enable the scripting directive `ENABLE_PLAYFABSERVER_API` on your Build settings, like in [this screenshot](https://user-images.githubusercontent.com/8256138/81462605-a6d7ac80-9168-11ea-9748-110ed01095c2.png).

### What is the top-level `Tests/` folder?

The `Tests/` folder at the root of `UnityGsdk/` (next to `Assets/`) contains a standalone .NET (MSTest) project used by SDK maintainers and CI to validate the GSDK source files outside of the Unity engine. Because it lives **outside** the `Assets/` folder, the Unity Editor does not import or compile it, and it has no effect on your game project. You do **not** need to copy it when integrating the Unity GSDK — only the `Assets/PlayFabSdk` folder is required.

> Note: this is different from `Assets/Tests/`, which is an in-engine NUnit test assembly gated behind the `UNIT_TESTING` define and only compiled when that define is set.

### Heartbeats are failing when I run in container mode (no heartbeat error), what should I do?

Expand Down
227 changes: 227 additions & 0 deletions UnityGsdk/Tests/GSDKConfigurationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
namespace PlayFab.MultiplayerAgent.Tests
{
using System;
using System.Collections.Generic;
using Helpers;
using Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class GSDKConfigurationTests
{
private static readonly SimpleJsonInstance _jsonInstance = new SimpleJsonInstance();

[TestMethod]
public void ReadConfiguration_EmptyGameCertificates_Parsed()
{
string json = @"
{
""heartbeatEndpoint"": ""heartbeatendpoint"",
""sessionHostId"": ""serverid"",
""gameCertificates"": {}
}";

GSDKConfiguration config = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);
Assert.IsNotNull(config.GameCertificates);
Assert.AreEqual(0, config.GameCertificates.Count);
}

[TestMethod]
public void ReadConfiguration_MultipleGameCertificates_Parsed()
{
string json = @"
{
""heartbeatEndpoint"": ""heartbeatendpoint"",
""sessionHostId"": ""serverid"",
""gameCertificates"": {
""gameCert"": ""onetwothree"",
""gameCert2"": ""threefourfive""
}
}";

GSDKConfiguration config = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);
Assert.IsNotNull(config.GameCertificates);
Assert.AreEqual(2, config.GameCertificates.Count);
Assert.AreEqual("onetwothree", config.GameCertificates["gameCert"]);
Assert.AreEqual("threefourfive", config.GameCertificates["gameCert2"]);
}

[TestMethod]
public void ReadConfiguration_EmptyGamePorts_Parsed()
{
string json = @"
{
""heartbeatEndpoint"": ""heartbeatendpoint"",
""sessionHostId"": ""serverid"",
""gamePorts"": {}
}";

GSDKConfiguration config = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);
Assert.IsNotNull(config.GamePorts);
Assert.AreEqual(0, config.GamePorts.Count);
}

[TestMethod]
public void ReadConfiguration_MultipleGamePorts_Parsed()
{
string json = @"
{
""heartbeatEndpoint"": ""heartbeatendpoint"",
""sessionHostId"": ""serverid"",
""gamePorts"": {
""8080"": ""debug"",
""8081"": ""game""
}
}";

GSDKConfiguration config = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);
Assert.IsNotNull(config.GamePorts);
Assert.AreEqual(2, config.GamePorts.Count);
Assert.AreEqual("debug", config.GamePorts["8080"]);
Assert.AreEqual("game", config.GamePorts["8081"]);
}

[TestMethod]
public void ReadConfiguration_BuildMetadata_Parsed()
{
string json = @"
{
""heartbeatEndpoint"": ""heartbeatendpoint"",
""sessionHostId"": ""serverid"",
""buildMetadata"": {
""key1"": ""value1"",
""key2"": ""value2""
}
}";

GSDKConfiguration config = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);
Assert.IsNotNull(config.BuildMetadata);
Assert.AreEqual(2, config.BuildMetadata.Count);
Assert.AreEqual("value1", config.BuildMetadata["key1"]);
Assert.AreEqual("value2", config.BuildMetadata["key2"]);
}

[TestMethod]
public void ReadConfiguration_AllFieldsSet_Parsed()
{
string json = @"
{
""heartbeatEndpoint"": ""testEndpoint"",
""sessionHostId"": ""testServerId"",
""vmId"": ""testVmId"",
""logFolder"": ""testLogFolder"",
""sharedContentFolder"": ""testSharedContentFolder"",
""certificateFolder"": ""testCertFolder"",
""publicIpV4Address"": ""1.2.3.4"",
""fullyQualifiedDomainName"": ""test.example.com"",
""gameCertificates"": { ""cert1"": ""thumbprint1"" },
""buildMetadata"": { ""key1"": ""value1"" },
""gamePorts"": { ""port1"": ""1111"" }
}";

GSDKConfiguration config = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);
Assert.AreEqual("testEndpoint", config.HeartbeatEndpoint);
Assert.AreEqual("testServerId", config.SessionHostId);
Assert.AreEqual("testVmId", config.VmId);
Assert.AreEqual("testLogFolder", config.LogFolder);
Assert.AreEqual("testSharedContentFolder", config.SharedContentFolder);
Assert.AreEqual("testCertFolder", config.CertificateFolder);
Assert.AreEqual("1.2.3.4", config.PublicIpV4Address);
Assert.AreEqual("test.example.com", config.FullyQualifiedDomainName);
Assert.AreEqual("thumbprint1", config.GameCertificates["cert1"]);
Assert.AreEqual("value1", config.BuildMetadata["key1"]);
Assert.AreEqual("1111", config.GamePorts["port1"]);
}

[TestMethod]
public void ReadConfiguration_EnvironmentVariables_Captured()
{
string originalTitleId = Environment.GetEnvironmentVariable("PF_TITLE_ID");
string originalBuildId = Environment.GetEnvironmentVariable("PF_BUILD_ID");
string originalRegion = Environment.GetEnvironmentVariable("PF_REGION");

Environment.SetEnvironmentVariable("PF_TITLE_ID", "testTitleId");
Environment.SetEnvironmentVariable("PF_BUILD_ID", "testBuildId");
Environment.SetEnvironmentVariable("PF_REGION", "testRegion");

try
{
var config = new GSDKConfiguration();
Assert.AreEqual("testTitleId", config.TitleId);
Assert.AreEqual("testBuildId", config.BuildId);
Assert.AreEqual("testRegion", config.Region);
}
finally
{
Environment.SetEnvironmentVariable("PF_TITLE_ID", originalTitleId);
Environment.SetEnvironmentVariable("PF_BUILD_ID", originalBuildId);
Environment.SetEnvironmentVariable("PF_REGION", originalRegion);
}
Comment thread
dgkanatsios marked this conversation as resolved.
}

[TestMethod]
public void ReadConfiguration_GameServerConnectionInfo_Parsed()
{
string json = @"
{
""heartbeatEndpoint"": ""heartbeatendpoint"",
""sessionHostId"": ""serverid"",
""gameServerConnectionInfo"": {
""publicIpV4Address"": ""10.0.0.1"",
""gamePortsConfiguration"": [
{
""name"": ""game"",
""serverListeningPort"": 7777,
""clientConnectionPort"": 30000
}
]
}
}";

GSDKConfiguration config = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);
Assert.IsNotNull(config.GameServerConnectionInfo);
Assert.AreEqual("10.0.0.1", config.GameServerConnectionInfo.PublicIPv4Address);
}

[TestMethod]
public void ReadConfiguration_OptionalFieldsNull_DefaultsUsed()
{
string json = @"
{
""heartbeatEndpoint"": ""testEndpoint"",
""sessionHostId"": ""testServerId""
}";

GSDKConfiguration config = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);
Assert.AreEqual("testEndpoint", config.HeartbeatEndpoint);
Assert.AreEqual("testServerId", config.SessionHostId);
Assert.IsNull(config.LogFolder);
Assert.IsNull(config.SharedContentFolder);
Assert.IsNull(config.CertificateFolder);
}

[TestMethod]
public void SerializeAndDeserialize_RoundTrip_PreservesData()
{
var config = new GSDKConfiguration
{
HeartbeatEndpoint = "testEndpoint",
SessionHostId = "testServerId",
LogFolder = "testLogFolder"
};
config.GameCertificates["cert1"] = "thumbprint1";
config.GamePorts["port1"] = "1111";
config.BuildMetadata["key1"] = "value1";

string json = _jsonInstance.SerializeObject(config);
GSDKConfiguration deserialized = _jsonInstance.DeserializeObject<GSDKConfiguration>(json);

Assert.AreEqual(config.HeartbeatEndpoint, deserialized.HeartbeatEndpoint);
Assert.AreEqual(config.SessionHostId, deserialized.SessionHostId);
Assert.AreEqual(config.LogFolder, deserialized.LogFolder);
Assert.AreEqual("thumbprint1", deserialized.GameCertificates["cert1"]);
Assert.AreEqual("1111", deserialized.GamePorts["port1"]);
Assert.AreEqual("value1", deserialized.BuildMetadata["key1"]);
}
}
}
Loading
Loading