using System; using System.Reflection; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; using Tgstation.Server.Host.Utils; namespace Tgstation.Server.Host.Components.Chat.Providers.Tests { [TestClass] public sealed class TestIrcProvider { [TestMethod] public async Task TestConstructionAndDisposal() { Assert.ThrowsExactly(() => new IrcProvider(null, null, null, null, null, null)); var mockJobManager = new Mock(); Assert.ThrowsExactly(() => new IrcProvider(mockJobManager.Object, null, null, null, null, null)); var mockAsyncDelayer = new Mock(); Assert.ThrowsExactly(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, null, null, null, null)); var mockLogger = new Mock>(); Assert.ThrowsExactly(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, null, null, null)); var mockBot = new ChatBot { Name = "test", Instance = new Models.Instance(), Provider = ChatProvider.Irc }; Assert.ThrowsExactly(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockBot, null, null)); var mockAss = new Mock(); Assert.ThrowsExactly(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockBot, mockAss.Object, null)); var mockLogConf = new Mock>(); mockLogConf.SetupGet(x => x.CurrentValue).Returns(new FileLoggingConfiguration()); Assert.ThrowsExactly(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockBot, mockAss.Object, mockLogConf.Object)); mockBot.ConnectionString = new IrcConnectionStringBuilder { Address = "localhost", Nickname = "test", UseSsl = true, Port = 6667 }.ToString(); await new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockBot, mockAss.Object, mockLogConf.Object).DisposeAsync(); } static ValueTask InvokeConnect(IProvider provider, CancellationToken cancellationToken = default) => (ValueTask)provider.GetType().GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(provider, new object[] { cancellationToken }); [TestMethod] public async Task TestConnectAndDisconnect() { var actualToken = Environment.GetEnvironmentVariable("TGS_TEST_IRC_CONNECTION_STRING"); if (String.IsNullOrWhiteSpace(actualToken)) Assert.Inconclusive("Required environment variable TGS_TEST_IRC_CONNECTION_STRING isn't set!"); if (!new IrcConnectionStringBuilder(actualToken).Valid) Assert.Fail("TGS_TEST_IRC_CONNECTION_STRING is not a valid IRC connection string!"); using var loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); builder.SetMinimumLevel(LogLevel.Trace); }); var mockSetup = new Mock(); mockSetup .Setup(x => x.RegisterOperation(It.IsNotNull(), It.IsNotNull(), It.IsAny())) .Callback((job, entrypoint, cancellationToken) => job.StartedBy ??= new User { }) .Returns(ValueTask.CompletedTask); mockSetup .Setup(x => x.WaitForJobCompletion(It.IsNotNull(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(ValueTask.FromResult(true)); var mockJobManager = mockSetup.Object; var chatBot = new ChatBot { ConnectionString = actualToken, Provider = ChatProvider.Irc, Instance = new Models.Instance(), }; var mockLogConf = new Mock>(); mockLogConf.SetupGet(x => x.CurrentValue).Returns(new FileLoggingConfiguration()); await using var provider = new IrcProvider(mockJobManager, new AsyncDelayer(loggerFactory.CreateLogger()), loggerFactory.CreateLogger(), chatBot, Mock.Of(), mockLogConf.Object); Assert.IsFalse(provider.Connected); await InvokeConnect(provider); Assert.IsTrue(provider.Connected); await Task.Delay(2000); // IRC servers do not like it when you connect and disconnect in rapid succession await provider.Disconnect(default); Assert.IsFalse(provider.Connected); await Task.Delay(2000); // same as above await InvokeConnect(provider); await Task.Delay(2000); // make sure it stays connected after a reconnect attempt Assert.IsTrue(provider.Connected); await provider.Disconnect(default); Assert.IsFalse(provider.Connected); } } }