diff --git a/.pubnub.yml b/.pubnub.yml index 51086c1b7..9a65f1e16 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,8 +1,13 @@ name: c-sharp -version: "7.3.9" +version: "7.3.10" schema: 1 scm: github.com/pubnub/c-sharp changelog: + - date: 2025-05-09 + version: v7.3.10 + changes: + - type: bug + text: "Specified dependency version for fixing synk reported issues." - date: 2025-05-09 version: v7.3.9 changes: @@ -892,7 +897,7 @@ features: - QUERY-PARAM supported-platforms: - - version: Pubnub 'C#' 7.3.9 + version: Pubnub 'C#' 7.3.10 platforms: - Windows 10 and up - Windows Server 2008 and up @@ -903,7 +908,7 @@ supported-platforms: - .Net Framework 4.6.1+ - .Net Framework 6.0 - - version: PubnubPCL 'C#' 7.3.9 + version: PubnubPCL 'C#' 7.3.10 platforms: - Xamarin.Android - Xamarin.iOS @@ -923,7 +928,7 @@ supported-platforms: - .Net Core - .Net 6.0 - - version: PubnubUWP 'C#' 7.3.9 + version: PubnubUWP 'C#' 7.3.10 platforms: - Windows Phone 10 - Universal Windows Apps @@ -947,7 +952,7 @@ sdks: distribution-type: source distribution-repository: GitHub package-name: Pubnub - location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.9.0 + location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.10.0 requires: - name: ".Net" @@ -1230,7 +1235,7 @@ sdks: distribution-type: source distribution-repository: GitHub package-name: PubNubPCL - location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.9.0 + location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.10.0 requires: - name: ".Net Core" @@ -1589,7 +1594,7 @@ sdks: distribution-type: source distribution-repository: GitHub package-name: PubnubUWP - location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.9.0 + location: https://github.com/pubnub/c-sharp/releases/tag/v7.3.10.0 requires: - name: "Universal Windows Platform Development" diff --git a/CHANGELOG b/CHANGELOG index 22f8c0604..30dbf6c9d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +v7.3.10 - May 09 2025 +----------------------------- +- Fixed: specified dependency version for fixing synk reported issues. + v7.3.9 - May 09 2025 ----------------------------- - Modified: changed the way the PubNub logger is injected into IHtttpClientService for better custom-transport-layers handling. diff --git a/src/Api/PubnubApi/Properties/AssemblyInfo.cs b/src/Api/PubnubApi/Properties/AssemblyInfo.cs index f51f14e50..3dbcd30c7 100644 --- a/src/Api/PubnubApi/Properties/AssemblyInfo.cs +++ b/src/Api/PubnubApi/Properties/AssemblyInfo.cs @@ -11,8 +11,8 @@ [assembly: AssemblyProduct("Pubnub C# SDK")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] -[assembly: AssemblyVersion("7.3.9.0")] -[assembly: AssemblyFileVersion("7.3.9.0")] +[assembly: AssemblyVersion("7.3.10.0")] +[assembly: AssemblyFileVersion("7.3.10.0")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. diff --git a/src/Api/PubnubApi/PubnubApi.csproj b/src/Api/PubnubApi/PubnubApi.csproj index 290a8fb24..5ba98460f 100644 --- a/src/Api/PubnubApi/PubnubApi.csproj +++ b/src/Api/PubnubApi/PubnubApi.csproj @@ -14,7 +14,7 @@ Pubnub - 7.3.9.0 + 7.3.10.0 PubNub C# .NET - Web Data Push API Pandu Masabathula PubNub @@ -22,7 +22,7 @@ http://pubnub.s3.amazonaws.com/2011/powered-by-pubnub/pubnub-icon-600x600.png true https://github.com/pubnub/c-sharp/ - Changed the way the PubNub logger is injected into IHtttpClientService for better custom-transport-layers handling. + Specified dependency version for fixing synk reported issues. Web Data Push Real-time Notifications ESB Message Broadcasting Distributed Computing PubNub is a Massively Scalable Web Push Service for Web and Mobile Games. This is a cloud-based service for broadcasting messages to thousands of web and mobile clients simultaneously diff --git a/src/Api/PubnubApiPCL/PubnubApiPCL.csproj b/src/Api/PubnubApiPCL/PubnubApiPCL.csproj index 2c393afe2..63d445a6a 100644 --- a/src/Api/PubnubApiPCL/PubnubApiPCL.csproj +++ b/src/Api/PubnubApiPCL/PubnubApiPCL.csproj @@ -14,7 +14,7 @@ PubnubPCL - 7.3.9.0 + 7.3.10.0 PubNub C# .NET - Web Data Push API Pandu Masabathula PubNub @@ -22,7 +22,7 @@ http://pubnub.s3.amazonaws.com/2011/powered-by-pubnub/pubnub-icon-600x600.png true https://github.com/pubnub/c-sharp/ - Changed the way the PubNub logger is injected into IHtttpClientService for better custom-transport-layers handling. + Specified dependency version for fixing synk reported issues. Web Data Push Real-time Notifications ESB Message Broadcasting Distributed Computing PubNub is a Massively Scalable Web Push Service for Web and Mobile Games. This is a cloud-based service for broadcasting messages to thousands of web and mobile clients simultaneously @@ -638,6 +638,7 @@ None + diff --git a/src/Api/PubnubApiUWP/PubnubApiUWP.csproj b/src/Api/PubnubApiUWP/PubnubApiUWP.csproj index 175510af0..810e11651 100644 --- a/src/Api/PubnubApiUWP/PubnubApiUWP.csproj +++ b/src/Api/PubnubApiUWP/PubnubApiUWP.csproj @@ -16,7 +16,7 @@ PubnubUWP - 7.3.9.0 + 7.3.10.0 PubNub C# .NET - Web Data Push API Pandu Masabathula PubNub @@ -24,7 +24,7 @@ http://pubnub.s3.amazonaws.com/2011/powered-by-pubnub/pubnub-icon-600x600.png true https://github.com/pubnub/c-sharp/ - Changed the way the PubNub logger is injected into IHtttpClientService for better custom-transport-layers handling. + Specified dependency version for fixing synk reported issues. Web Data Push Real-time Notifications ESB Message Broadcasting Distributed Computing PubNub is a Massively Scalable Web Push Service for Web and Mobile Games. This is a cloud-based service for broadcasting messages to thousands of web and mobile clients simultaneously diff --git a/src/Api/PubnubApiUnity/PubnubApiUnity.csproj b/src/Api/PubnubApiUnity/PubnubApiUnity.csproj index d0dc9b825..86a7b6160 100644 --- a/src/Api/PubnubApiUnity/PubnubApiUnity.csproj +++ b/src/Api/PubnubApiUnity/PubnubApiUnity.csproj @@ -15,7 +15,7 @@ PubnubApiUnity - 7.3.9.0 + 7.3.10.0 PubNub C# .NET - Web Data Push API Pandu Masabathula PubNub diff --git a/src/UnitTests/PubnubApi.Tests/AdditionalSubscribeTests.cs b/src/UnitTests/PubnubApi.Tests/AdditionalSubscribeTests.cs new file mode 100644 index 000000000..770ecceb7 --- /dev/null +++ b/src/UnitTests/PubnubApi.Tests/AdditionalSubscribeTests.cs @@ -0,0 +1,652 @@ +using System; +using NUnit.Framework; +using System.Threading; +using PubnubApi; +using System.Collections.Generic; +using MockServer; +using System.Diagnostics; +using System.Threading.Tasks; +using PubnubApi.EventEngine.Subscribe.Events; +using PubnubApi.Security.Crypto; +using PubnubApi.Security.Crypto.Cryptors; +using System.Net; + +namespace PubNubMessaging.Tests +{ + [TestFixture] + public class AdditionalSubscribeTests : TestHarness + { + private static readonly int manualResetEventWaitTimeout = 310 * 1000; + private static readonly string authKey = "myauth"; + private static readonly string channel = "hello_my_channel"; + private static string authToken; + + private static Pubnub pubnub; + private static Server server; + + private class CustomTestObject + { + public string Field1 { get; set; } + public int Field2 { get; set; } + public List Field3 { get; set; } + } + + public class TestLog : IPubnubLog + { + public void WriteToLog(string logText) + { + Debug.WriteLine(logText); + } + } + + [SetUp] + public static async Task Init() + { + UnitTestLog unitLog = new UnitTestLog(); + unitLog.LogLevel = MockServer.LoggingMethod.Level.Verbose; + server = Server.Instance(); + MockServer.LoggingMethod.MockServerLog = unitLog; + if (PubnubCommon.EnableStubTest) + { + server.Start(); + } + + if (!PubnubCommon.PAMServerSideGrant) { return; } + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + SecretKey = PubnubCommon.SecretKey, + AuthKey = authKey, + Secure = true + }; + server.RunOnHttps(true); + + pubnub = createPubNubInstance(config); + + string expected = "{\"message\":\"Success\",\"payload\":{\"level\":\"user\",\"subscribe_key\":\"demo-36\",\"ttl\":20,\"channel\":\"hello_my_channel\",\"auths\":{\"myAuth\":{\"r\":1,\"w\":1,\"m\":1}}},\"service\":\"Access Manager\",\"status\":200}"; + + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(string.Format("/v2/auth/grant/sub-key/{0}", PubnubCommon.SubscribeKey)) + .WithParameter("auth", authKey) + .WithParameter("channel", "hello_my_channel%2Chello_my_channel1%2Chello_my_channel2") + .WithParameter("m", "1") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("r", "1") + .WithParameter("requestid", "myRequestId") + .WithParameter("timestamp", "1356998400") + .WithParameter("ttl", "20") + .WithParameter("uuid", config.UserId) + .WithParameter("w", "1") + .WithParameter("signature", "hc7IKhEB7tyL6ENR3ndOOlHqPIG3RmzxwJMSGpofE6Q=") + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK)); + + if (string.IsNullOrEmpty(PubnubCommon.GrantToken)) + { + await GenerateTestGrantToken(pubnub); + } + authToken = PubnubCommon.GrantToken; + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [TearDown] + public static void Exit() + { + if (pubnub != null) + { + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + server.Stop(); + } + + [Test] + public static void ThenSubscribeWithEmptyChannelsShouldReturnException() + { + server.ClearRequests(); + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false + }; + server.RunOnHttps(false); + + pubnub = createPubNubInstance(config, authToken); + + Assert.Throws(() => + { + pubnub.Subscribe() + .Channels(new string[] { }) + .Execute(); + }); + } + + [Test] + public static void ThenSubscribeShouldHandleServerErrors() + { + server.ClearRequests(); + + bool receivedErrorMessage = false; + ManualResetEvent errorManualEvent = new ManualResetEvent(false); + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + LogVerbosity = PNLogVerbosity.BODY, + PubnubLog = new TestLog() + }; + server.RunOnHttps(false); + + SubscribeCallback listenerSubCallack = new SubscribeCallbackExt( + (o, m) => { }, + (o, p) => { }, + (o, s) => { + Debug.WriteLine($"{s.Operation} {s.Category} {s.StatusCode}"); + if (s.StatusCode != 200 || s.Error) + { + receivedErrorMessage = true; + errorManualEvent.Set(); + } + }); + + pubnub = createPubNubInstance(config, authToken); + pubnub.AddListener(listenerSubCallack); + + string expected = "{\"error\": \"Forbidden\", \"status\": 403}"; + + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "0") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.Forbidden)); + + pubnub.Subscribe().Channels(new[] { channel }).Execute(); + + errorManualEvent.WaitOne(manualResetEventWaitTimeout); + + Assert.IsTrue(receivedErrorMessage, "Subscribe should handle server errors properly"); + + pubnub.RemoveListener(listenerSubCallack); + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [Test] + public static void ThenSubscribeWithCustomObjectShouldReceiveCorrectType() + { + server.ClearRequests(); + + bool receivedCorrectType = false; + ManualResetEvent subscribeManualEvent = new ManualResetEvent(false); + ManualResetEvent messageManualEvent = new ManualResetEvent(false); + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false + }; + server.RunOnHttps(false); + + CustomTestObject testObject = new CustomTestObject + { + Field1 = "Test", + Field2 = 42, + Field3 = new List { "item1", "item2", "item3" } + }; + + SubscribeCallback listenerSubCallack = new SubscribeCallbackExt( + (o, m) => { + Debug.WriteLine("Message received: " + pubnub.JsonPluggableLibrary.SerializeToJsonString(m.Message)); + if (m.Message is CustomTestObject) + { + CustomTestObject received = m.Message as CustomTestObject; + if (received != null && received.Field1 == testObject.Field1 && + received.Field2 == testObject.Field2 && + received.Field3.Count == testObject.Field3.Count) + { + receivedCorrectType = true; + } + } + messageManualEvent.Set(); + }, + (o, p) => { }, + (o, s) => { + if (s.StatusCode == 200 && s.Category == PNStatusCategory.PNConnectedCategory) + { + subscribeManualEvent.Set(); + } + }); + + pubnub = createPubNubInstance(config, authToken); + pubnub.AddListener(listenerSubCallack); + + string expected = "{\"t\":{\"t\":\"14836303477713304\",\"r\":7},\"m\":[]}"; + + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "0") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK)); + + // Add a second subscribe response that includes a message + string messageJson = "{\"Field1\":\"Test\",\"Field2\":42,\"Field3\":[\"item1\",\"item2\",\"item3\"]}"; + expected = "{\"t\":{\"t\":\"14836303477713305\",\"r\":7},\"m\":[{\"a\":\"1\",\"b\":\"" + channel + "\",\"c\":\"" + channel + "\",\"d\":" + messageJson + ",\"e\":0,\"f\":\"0\",\"i\":\"Client-12345\",\"k\":\"demo-36\",\"s\":1,\"u\":{}}]}"; + + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "14836303477713304") + .WithParameter("tr", "7") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK)); + + pubnub.Subscribe().Channels(new[] { channel }).Execute(); + + subscribeManualEvent.WaitOne(manualResetEventWaitTimeout); + messageManualEvent.WaitOne(manualResetEventWaitTimeout); + + Assert.IsTrue(receivedCorrectType, "Subscribe should correctly deserialize to custom object type"); + + pubnub.RemoveListener(listenerSubCallack); + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [Test] + public static void ThenDisconnectAndReconnectShouldMaintainSubscription() + { + server.ClearRequests(); + + bool connectReceived = false; + bool reconnectReceived = false; + ManualResetEvent connectEvent = new ManualResetEvent(false); + ManualResetEvent reconnectEvent = new ManualResetEvent(false); + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false + }; + server.RunOnHttps(false); + + SubscribeCallback listenerSubCallack = new SubscribeCallbackExt( + (o, m) => { }, + (o, p) => { }, + (o, s) => { + Debug.WriteLine($"{s.Operation} {s.Category} {s.StatusCode}"); + if (s.StatusCode == 200 && s.Category == PNStatusCategory.PNConnectedCategory) + { + connectReceived = true; + connectEvent.Set(); + } + else if (s.StatusCode == 200 && s.Category == PNStatusCategory.PNReconnectedCategory) + { + reconnectReceived = true; + reconnectEvent.Set(); + } + }); + + pubnub = createPubNubInstance(config, authToken); + pubnub.AddListener(listenerSubCallack); + + string expected = "{\"t\":{\"t\":\"14836303477713304\",\"r\":7},\"m\":[]}"; + + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "0") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK)); + + // Add second request for reconnect + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "14836303477713304") + .WithParameter("tr", "7") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK)); + + pubnub.Subscribe().Channels(new[] { channel }).Execute(); + + connectEvent.WaitOne(manualResetEventWaitTimeout); + + // Disconnect + pubnub.Disconnect(); + + Thread.Sleep(2000); + + // Reconnect + pubnub.Reconnect(); + + reconnectEvent.WaitOne(manualResetEventWaitTimeout); + + Assert.IsTrue(connectReceived && reconnectReceived, "Disconnect and Reconnect should maintain subscription"); + + pubnub.RemoveListener(listenerSubCallack); + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [Test] + public static void ThenSubscribeWithQueryParamsShouldIncludeInRequest() + { + server.ClearRequests(); + + bool requestContainsQueryParams = false; + Dictionary queryParams = new Dictionary() + { + { "custom_param", "custom_value" }, + { "numeric_param", 123 } + }; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + LogVerbosity = PNLogVerbosity.BODY, + PubnubLog = new TestLog() + }; + server.RunOnHttps(false); + + pubnub = createPubNubInstance(config, authToken); + + string expected = "{\"t\":{\"t\":\"14836303477713304\",\"r\":7},\"m\":[]}"; + + // Set up a request that checks for our custom query parameters + var request = new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "0") + .WithParameter("uuid", config.UserId) + .WithParameter("custom_param", "custom_value") + .WithParameter("numeric_param", "123") + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK); + + server.AddRequest(request); + + ManualResetEvent subscribeManualEvent = new ManualResetEvent(false); + SubscribeCallback listenerSubCallack = new SubscribeCallbackExt( + (o, m) => { }, + (o, p) => { }, + (o, s) => { + if (s.StatusCode == 200) + { + subscribeManualEvent.Set(); + } + }); + + pubnub.AddListener(listenerSubCallack); + pubnub.Subscribe().Channels(new[] { channel }).QueryParam(queryParams).Execute(); + + subscribeManualEvent.WaitOne(manualResetEventWaitTimeout); + + Assert.IsTrue(requestContainsQueryParams, "Query parameters should be included in the request"); + + pubnub.RemoveListener(listenerSubCallack); + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [Test] + public static void ThenUnsubscribeFromNonSubscribedChannelShouldNotFail() + { + server.ClearRequests(); + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false + }; + server.RunOnHttps(false); + + pubnub = createPubNubInstance(config, authToken); + + // No exception should be thrown + pubnub.Unsubscribe().Channels(new[] { "non_existent_channel" }).Execute(); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [Test] + public static void ThenSubscribeWithEventEngineEnabledShouldUseEventEngine() + { + server.ClearRequests(); + + bool eventEngineUsed = false; + ManualResetEvent subscribeManualEvent = new ManualResetEvent(false); + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + EnableEventEngine = true // Explicitly enable event engine + }; + server.RunOnHttps(false); + + SubscribeCallback listenerSubCallack = new SubscribeCallbackExt( + (o, m) => { }, + (o, p) => { }, + (o, s) => { + Debug.WriteLine($"{s.Operation} {s.Category} {s.StatusCode}"); + if (s.StatusCode == 200 && s.Category == PNStatusCategory.PNConnectedCategory) + { + // Verify that the event engine is used by checking that the status event has + // proper data from event engine + eventEngineUsed = s.AffectedChannels != null && s.AffectedChannels.Contains(channel); + subscribeManualEvent.Set(); + } + }); + + pubnub = createPubNubInstance(config, authToken); + pubnub.AddListener(listenerSubCallack); + + string expected = "{\"t\":{\"t\":\"14836303477713304\",\"r\":7},\"m\":[]}"; + + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "0") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK)); + + pubnub.Subscribe().Channels(new[] { channel }).Execute(); + + subscribeManualEvent.WaitOne(manualResetEventWaitTimeout); + + Assert.IsTrue(eventEngineUsed, "Event Engine should be used when enabled"); + + pubnub.RemoveListener(listenerSubCallack); + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [Test] + public static void ThenSubscribeWithNoChannelsButChannelGroupsShouldWork() + { + server.ClearRequests(); + + bool connectReceived = false; + ManualResetEvent connectEvent = new ManualResetEvent(false); + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false + }; + server.RunOnHttps(false); + + string channelGroup = "my_channel_group"; + + SubscribeCallback listenerSubCallack = new SubscribeCallbackExt( + (o, m) => { }, + (o, p) => { }, + (o, s) => { + Debug.WriteLine($"{s.Operation} {s.Category} {s.StatusCode}"); + if (s.StatusCode == 200 && s.Category == PNStatusCategory.PNConnectedCategory) + { + connectReceived = true; + connectEvent.Set(); + } + }); + + pubnub = createPubNubInstance(config, authToken); + pubnub.AddListener(listenerSubCallack); + + string expected = "{\"t\":{\"t\":\"14836303477713304\",\"r\":7},\"m\":[]}"; + + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/,/0", PubnubCommon.SubscribeKey)) + .WithParameter("channel-group", channelGroup) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "0") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK)); + + pubnub.Subscribe().ChannelGroups(new[] { channelGroup }).Execute(); + + connectEvent.WaitOne(manualResetEventWaitTimeout); + + Assert.IsTrue(connectReceived, "Subscribe with only channel groups should work"); + + pubnub.RemoveListener(listenerSubCallack); + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [Test] + public static void ThenResetTimeTokenShouldStartSubscriptionFromBeginning() + { + server.ClearRequests(); + + bool timeTokenReset = false; + ManualResetEvent connectEvent = new ManualResetEvent(false); + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false + }; + server.RunOnHttps(false); + + pubnub = createPubNubInstance(config, authToken); + + // First normal connection with timetoken + string expected = "{\"t\":{\"t\":\"14836303477713304\",\"r\":7},\"m\":[]}"; + + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "0") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK)); + + // Second request should reset timetoken back to 0 if reset flag is true + var secondRequest = new Request() + .WithMethod("GET") + .WithPath(String.Format("/v2/subscribe/{0}/{1}/0", PubnubCommon.SubscribeKey, channel)) + .WithParameter("heartbeat", "300") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("tt", "0") // This verifies timetoken reset + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(HttpStatusCode.OK); + + server.AddRequest(secondRequest); + + ManualResetEvent subscribeManualEvent = new ManualResetEvent(false); + SubscribeCallback listenerSubCallack = new SubscribeCallbackExt( + (o, m) => { }, + (o, p) => { }, + (o, s) => { + if (s.StatusCode == 200 && s.Category == PNStatusCategory.PNConnectedCategory) + { + subscribeManualEvent.Set(); + } + }); + + pubnub.AddListener(listenerSubCallack); + pubnub.Subscribe().Channels(new[] { channel }).Execute(); + + subscribeManualEvent.WaitOne(manualResetEventWaitTimeout); + + // Disconnect and reconnect with reset flag + pubnub.Disconnect(); + Thread.Sleep(1000); + pubnub.Reconnect(true); // true = reset timetoken + + Thread.Sleep(3000); // Give time for the second request to be processed + + Assert.IsTrue(timeTokenReset, "Reconnect with reset timetoken should reset the timetoken to 0"); + + pubnub.RemoveListener(listenerSubCallack); + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + } +} \ No newline at end of file diff --git a/src/UnitTests/PubnubApi.Tests/WhenAMessageIsPublished.cs b/src/UnitTests/PubnubApi.Tests/WhenAMessageIsPublished.cs index 4b6e376d8..e76c81214 100644 --- a/src/UnitTests/PubnubApi.Tests/WhenAMessageIsPublished.cs +++ b/src/UnitTests/PubnubApi.Tests/WhenAMessageIsPublished.cs @@ -1887,5 +1887,547 @@ public static void IfMobilePayloadThenPublishReturnSuccess() Assert.IsTrue(payload != null, "FAILED - IfMobilePayloadThenPublishReturnSuccess"); } + + [Test] + public static void ThenPublishWithTtlShouldReturnSuccessCodeAndInfo() + { + server.ClearRequests(); + + bool receivedPublishMessage = false; + long publishTimetoken = 0; + + string channel = "hello_my_channel"; + string message = messageForUnencryptPublish; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + }; + if (PubnubCommon.PAMServerSideRun) + { + config.SecretKey = PubnubCommon.SecretKey; + } + else if (!string.IsNullOrEmpty(authToken) && !PubnubCommon.SuppressAuthKey) + { + config.AuthKey = authToken; + } + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + string expected = "[1,\"Sent\",\"14722484585147754\"]"; + + // The request should include a ttl parameter + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/publish/{0}/{1}/0/{2}/0/{3}", PubnubCommon.PublishKey, PubnubCommon.SubscribeKey, channel, "%22Pubnub%20Messaging%20API%201%22")) + .WithParameter("ttl", "24") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(System.Net.HttpStatusCode.OK)); + + manualResetEventWaitTimeout = 310 * 1000; + + ManualResetEvent publishManualEvent = new ManualResetEvent(false); + pubnub.Publish().Channel(channel).Message(message).Ttl(24) + .Execute(new PNPublishResultExt((r, s) => + { + if (r != null && s.StatusCode == 200 && !s.Error) + { + publishTimetoken = r.Timetoken; + receivedPublishMessage = true; + } + publishManualEvent.Set(); + })); + publishManualEvent.WaitOne(manualResetEventWaitTimeout); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + Assert.IsTrue(receivedPublishMessage, "Publish with TTL Failed"); + } + + [Test] + public static void ThenPublishWithShouldStoreFalseShouldReturnSuccessCodeAndInfo() + { + server.ClearRequests(); + + bool receivedPublishMessage = false; + long publishTimetoken = 0; + + string channel = "hello_my_channel"; + string message = messageForUnencryptPublish; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + }; + if (PubnubCommon.PAMServerSideRun) + { + config.SecretKey = PubnubCommon.SecretKey; + } + else if (!string.IsNullOrEmpty(authToken) && !PubnubCommon.SuppressAuthKey) + { + config.AuthKey = authToken; + } + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + string expected = "[1,\"Sent\",\"14722484585147754\"]"; + + // The request should include a store parameter with value 0 + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/publish/{0}/{1}/0/{2}/0/{3}", PubnubCommon.PublishKey, PubnubCommon.SubscribeKey, channel, "%22Pubnub%20Messaging%20API%201%22")) + .WithParameter("store", "0") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(System.Net.HttpStatusCode.OK)); + + manualResetEventWaitTimeout = 310 * 1000; + + ManualResetEvent publishManualEvent = new ManualResetEvent(false); + pubnub.Publish().Channel(channel).Message(message).ShouldStore(false) + .Execute(new PNPublishResultExt((r, s) => + { + if (r != null && s.StatusCode == 200 && !s.Error) + { + publishTimetoken = r.Timetoken; + receivedPublishMessage = true; + } + publishManualEvent.Set(); + })); + publishManualEvent.WaitOne(manualResetEventWaitTimeout); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + Assert.IsTrue(receivedPublishMessage, "Publish with ShouldStore false Failed"); + } + + [Test] + public static void ThenPublishWithMetaShouldReturnSuccessCodeAndInfo() + { + server.ClearRequests(); + + bool receivedPublishMessage = false; + long publishTimetoken = 0; + + string channel = "hello_my_channel"; + string message = messageForUnencryptPublish; + Dictionary metaData = new Dictionary + { + { "sender", "unit-test" }, + { "timestamp", 12345 } + }; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + }; + if (PubnubCommon.PAMServerSideRun) + { + config.SecretKey = PubnubCommon.SecretKey; + } + else if (!string.IsNullOrEmpty(authToken) && !PubnubCommon.SuppressAuthKey) + { + config.AuthKey = authToken; + } + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + string expected = "[1,\"Sent\",\"14722484585147754\"]"; + + // The request should include a meta parameter + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/publish/{0}/{1}/0/{2}/0/{3}", PubnubCommon.PublishKey, PubnubCommon.SubscribeKey, channel, "%22Pubnub%20Messaging%20API%201%22")) + .WithParameter("meta", "%7B%22sender%22%3A%22unit-test%22%2C%22timestamp%22%3A12345%7D") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(System.Net.HttpStatusCode.OK)); + + manualResetEventWaitTimeout = 310 * 1000; + + ManualResetEvent publishManualEvent = new ManualResetEvent(false); + pubnub.Publish().Channel(channel).Message(message).Meta(metaData) + .Execute(new PNPublishResultExt((r, s) => + { + if (r != null && s.StatusCode == 200 && !s.Error) + { + publishTimetoken = r.Timetoken; + receivedPublishMessage = true; + } + publishManualEvent.Set(); + })); + publishManualEvent.WaitOne(manualResetEventWaitTimeout); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + Assert.IsTrue(receivedPublishMessage, "Publish with Meta Failed"); + } + + [Test] + public static void ThenPublishWithCustomMessageTypeShouldReturnSuccessCodeAndInfo() + { + server.ClearRequests(); + + bool receivedPublishMessage = false; + long publishTimetoken = 0; + + string channel = "hello_my_channel"; + string message = messageForUnencryptPublish; + string customType = "custom-type"; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + }; + if (PubnubCommon.PAMServerSideRun) + { + config.SecretKey = PubnubCommon.SecretKey; + } + else if (!string.IsNullOrEmpty(authToken) && !PubnubCommon.SuppressAuthKey) + { + config.AuthKey = authToken; + } + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + string expected = "[1,\"Sent\",\"14722484585147754\"]"; + + // The request should include a custom_message_type parameter + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/publish/{0}/{1}/0/{2}/0/{3}", PubnubCommon.PublishKey, PubnubCommon.SubscribeKey, channel, "%22Pubnub%20Messaging%20API%201%22")) + .WithParameter("custom_message_type", customType) + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(System.Net.HttpStatusCode.OK)); + + manualResetEventWaitTimeout = 310 * 1000; + + ManualResetEvent publishManualEvent = new ManualResetEvent(false); + pubnub.Publish().Channel(channel).Message(message).CustomMessageType(customType) + .Execute(new PNPublishResultExt((r, s) => + { + if (r != null && s.StatusCode == 200 && !s.Error) + { + publishTimetoken = r.Timetoken; + receivedPublishMessage = true; + } + publishManualEvent.Set(); + })); + publishManualEvent.WaitOne(manualResetEventWaitTimeout); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + Assert.IsTrue(receivedPublishMessage, "Publish with CustomMessageType Failed"); + } + + [Test] + public static void ThenPublishWithAllOptionsShouldReturnSuccessCodeAndInfo() + { + server.ClearRequests(); + + bool receivedPublishMessage = false; + long publishTimetoken = 0; + + string channel = "hello_my_channel"; + string message = messageForUnencryptPublish; + string customType = "notification"; + Dictionary metaData = new Dictionary + { + { "sender", "unit-test" }, + { "priority", "high" } + }; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + }; + if (PubnubCommon.PAMServerSideRun) + { + config.SecretKey = PubnubCommon.SecretKey; + } + else if (!string.IsNullOrEmpty(authToken) && !PubnubCommon.SuppressAuthKey) + { + config.AuthKey = authToken; + } + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + string expected = "[1,\"Sent\",\"14722484585147754\"]"; + + // The request should include all parameters + server.AddRequest(new Request() + .WithMethod("POST") + .WithPath(String.Format("/publish/{0}/{1}/0/{2}/0", PubnubCommon.PublishKey, PubnubCommon.SubscribeKey, channel)) + .WithParameter("store", "0") + .WithParameter("ttl", "10") + .WithParameter("meta", "%7B%22sender%22%3A%22unit-test%22%2C%22priority%22%3A%22high%22%7D") + .WithParameter("custom_message_type", customType) + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(System.Net.HttpStatusCode.OK)); + + manualResetEventWaitTimeout = 310 * 1000; + + ManualResetEvent publishManualEvent = new ManualResetEvent(false); + pubnub.Publish().Channel(channel).Message(message) + .ShouldStore(false) + .Ttl(10) + .Meta(metaData) + .CustomMessageType(customType) + .UsePOST(true) + .Execute(new PNPublishResultExt((r, s) => + { + if (r != null && s.StatusCode == 200 && !s.Error) + { + publishTimetoken = r.Timetoken; + receivedPublishMessage = true; + } + publishManualEvent.Set(); + })); + publishManualEvent.WaitOne(manualResetEventWaitTimeout); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + Assert.IsTrue(receivedPublishMessage, "Publish with all options Failed"); + } + + [Test] + public static void ThenPublishWithCustomQueryParamsShouldReturnSuccessCodeAndInfo() + { + server.ClearRequests(); + + bool receivedPublishMessage = false; + long publishTimetoken = 0; + + string channel = "hello_my_channel"; + string message = messageForUnencryptPublish; + Dictionary queryParams = new Dictionary + { + { "custom_param", "custom_value" }, + { "numeric_param", 42 } + }; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + }; + if (PubnubCommon.PAMServerSideRun) + { + config.SecretKey = PubnubCommon.SecretKey; + } + else if (!string.IsNullOrEmpty(authToken) && !PubnubCommon.SuppressAuthKey) + { + config.AuthKey = authToken; + } + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + string expected = "[1,\"Sent\",\"14722484585147754\"]"; + + // The request should include the custom query parameters + server.AddRequest(new Request() + .WithMethod("GET") + .WithPath(String.Format("/publish/{0}/{1}/0/{2}/0/{3}", PubnubCommon.PublishKey, PubnubCommon.SubscribeKey, channel, "%22Pubnub%20Messaging%20API%201%22")) + .WithParameter("custom_param", "custom_value") + .WithParameter("numeric_param", "42") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(System.Net.HttpStatusCode.OK)); + + manualResetEventWaitTimeout = 310 * 1000; + + ManualResetEvent publishManualEvent = new ManualResetEvent(false); + pubnub.Publish().Channel(channel).Message(message).QueryParam(queryParams) + .Execute(new PNPublishResultExt((r, s) => + { + if (r != null && s.StatusCode == 200 && !s.Error) + { + publishTimetoken = r.Timetoken; + receivedPublishMessage = true; + } + publishManualEvent.Set(); + })); + publishManualEvent.WaitOne(manualResetEventWaitTimeout); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + Assert.IsTrue(receivedPublishMessage, "Publish with custom query parameters Failed"); + } + + [Test] +#if NET40 + public static void ThenExecuteAsyncWithAllParametersShouldReturnSuccessCodeAndInfo() +#else + public static async Task ThenExecuteAsyncWithAllParametersShouldReturnSuccessCodeAndInfo() +#endif + { + server.ClearRequests(); + + string channel = "hello_my_channel"; + string message = messageForUnencryptPublish; + string customType = "notification"; + Dictionary metaData = new Dictionary + { + { "sender", "unit-test" }, + { "priority", "high" } + }; + Dictionary queryParams = new Dictionary + { + { "custom_param", "custom_value" } + }; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + Secure = false, + }; + if (PubnubCommon.PAMServerSideRun) + { + config.SecretKey = PubnubCommon.SecretKey; + } + else if (!string.IsNullOrEmpty(authToken) && !PubnubCommon.SuppressAuthKey) + { + config.AuthKey = authToken; + } + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + string expected = "[1,\"Sent\",\"14722484585147754\"]"; + + // The request should include all parameters + server.AddRequest(new Request() + .WithMethod("POST") + .WithPath(String.Format("/publish/{0}/{1}/0/{2}/0", PubnubCommon.PublishKey, PubnubCommon.SubscribeKey, channel)) + .WithParameter("store", "0") + .WithParameter("ttl", "10") + .WithParameter("meta", "%7B%22sender%22%3A%22unit-test%22%2C%22priority%22%3A%22high%22%7D") + .WithParameter("custom_message_type", customType) + .WithParameter("custom_param", "custom_value") + .WithParameter("pnsdk", PubnubCommon.EncodedSDK) + .WithParameter("requestid", "myRequestId") + .WithParameter("uuid", config.UserId) + .WithResponse(expected) + .WithStatusCode(System.Net.HttpStatusCode.OK)); + +#if NET40 + PNResult result = Task.Factory.StartNew(async () => await pubnub.Publish().Channel(channel).Message(message) + .ShouldStore(false) + .Ttl(10) + .Meta(metaData) + .CustomMessageType(customType) + .QueryParam(queryParams) + .UsePOST(true) + .ExecuteAsync()).Result.Result; +#else + PNResult result = await pubnub.Publish().Channel(channel).Message(message) + .ShouldStore(false) + .Ttl(10) + .Meta(metaData) + .CustomMessageType(customType) + .QueryParam(queryParams) + .UsePOST(true) + .ExecuteAsync(); +#endif + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + + Assert.IsNotNull(result, "Result should not be null"); + Assert.IsNotNull(result.Result, "Result.Result should not be null"); + Assert.AreEqual(200, result.Status.StatusCode, "StatusCode should be 200"); + Assert.IsFalse(result.Status.Error, "Error should be false"); + } + + [Test] + public static void ThenEmptyChannelNameShouldThrowException() + { + server.ClearRequests(); + + string channel = ""; + string message = messageForUnencryptPublish; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + }; + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + Assert.Throws(() => + { + pubnub.Publish() + .Channel(channel) + .Message(message) + .Execute(new PNPublishResultExt((r, s) => { })); + }); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } + + [Test] + public static void ThenNullCallbackShouldThrowException() + { + server.ClearRequests(); + + string channel = "hello_my_channel"; + string message = messageForUnencryptPublish; + + PNConfiguration config = new PNConfiguration(new UserId("mytestuuid")) + { + PublishKey = PubnubCommon.PublishKey, + SubscribeKey = PubnubCommon.SubscribeKey, + }; + server.RunOnHttps(true); + pubnub = createPubNubInstance(config, authToken); + + Assert.Throws(() => + { + pubnub.Publish() + .Channel(channel) + .Message(message) + .Execute(null); + }); + + pubnub.Destroy(); + pubnub.PubnubUnitTest = null; + pubnub = null; + } } }