public async void TryInvokeFromCacheAsync_WithoutTypeParameter_IsThreadSafe() { // Arrange HttpNodeJSService testSubject = CreateHttpNodeJSService(); await testSubject.InvokeFromStringAsync(_dummyExportsMultipleFunctionsModule, DUMMY_CACHE_IDENTIFIER, "incrementNumber").ConfigureAwait(false); // Act const int numThreads = 5; var threads = new List <Thread>(); for (int i = 0; i < numThreads; i++) { var thread = new Thread(() => testSubject.TryInvokeFromCacheAsync(DUMMY_CACHE_IDENTIFIER, "incrementNumber").GetAwaiter().GetResult()); threads.Add(thread); thread.Start(); } foreach (Thread thread in threads) { thread.Join(); } // Assert int result = await testSubject.InvokeFromStringAsync <int>(_dummyExportsMultipleFunctionsModule, DUMMY_CACHE_IDENTIFIER, "getNumber").ConfigureAwait(false); Assert.Equal(numThreads + 1, result); }
public void InvokeFromStreamAsync_WithTypeParameter_WithRawStreamModule_IsThreadSafe() { // Arrange const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act var results = new ConcurrentQueue <DummyResult>(); const int numThreads = 5; var threads = new List <Thread>(); for (int i = 0; i < numThreads; i++) { var thread = new Thread(() => { MemoryStream memoryStream = CreateMemoryStream(_dummyReturnsArgModule); results.Enqueue(testSubject.InvokeFromStreamAsync <DummyResult>(memoryStream, args: new[] { dummyArg }).GetAwaiter().GetResult()); }); threads.Add(thread); thread.Start(); } foreach (Thread thread in threads) { thread.Join(); } // Assert Assert.Equal(numThreads, results.Count); foreach (DummyResult result in results) { Assert.Equal(dummyArg, result.Result); } }
public void InvokeFromStringAsync_WithTypeParameter_WithModuleFactory_IsThreadSafe() { // Arrange HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act var results = new ConcurrentQueue <int>(); const int numThreads = 5; var threads = new List <Thread>(); for (int i = 0; i < numThreads; i++) { var thread = new Thread(() => results.Enqueue(testSubject. InvokeFromStringAsync <int>(_dummyExportsMultipleFunctionsModule, DUMMY_CACHE_IDENTIFIER, "incrementAndGetNumber").GetAwaiter().GetResult())); threads.Add(thread); thread.Start(); } foreach (Thread thread in threads) { thread.Join(); } // Assert Assert.Equal(numThreads, results.Count); // Module shouldn't get cached more than once, we should get exactly [1,2,3,4,5] List <int> resultsList = results.ToList(); resultsList.Sort(); for (int i = 0; i < numThreads; i++) { Assert.Equal(resultsList[i], i + 1); } }
public async void InvokeFromFileAsync_WithoutTypeParameter_IsThreadSafe() { // Arrange HttpNodeJSService testSubject = CreateHttpNodeJSService(projectPath: _projectPath); // Act const int numThreads = 5; var threads = new List <Thread>(); for (int i = 0; i < numThreads; i++) { var thread = new Thread(() => testSubject. InvokeFromFileAsync(DUMMY_EXPORTS_MULTIPLE_FUNCTIONS_MODULE_FILE, "incrementNumber").GetAwaiter().GetResult()); threads.Add(thread); thread.Start(); } foreach (Thread thread in threads) { thread.Join(); } // Assert int result = await testSubject.InvokeFromFileAsync <int>(DUMMY_EXPORTS_MULTIPLE_FUNCTIONS_MODULE_FILE, "getNumber").ConfigureAwait(false); Assert.Equal(numThreads, result); }
public async void InMemoryInvokeMethods_LoadRequiredModulesFromNodeModulesInProjectDirectory() { // Arrange const string dummyCode = @"public string ExampleFunction(string arg) { // Example comment return arg + ""dummyString""; }"; HttpNodeJSService testSubject = CreateHttpNodeJSService(projectPath: _projectPath); // Act string result = await testSubject.InvokeFromStringAsync <string>(@"const prismjs = require('prismjs'); require('prismjs/components/prism-csharp'); module.exports = (callback, code) => { var result = prismjs.highlight(code, prismjs.languages.csharp, 'csharp'); callback(null, result); };", args : new[] { dummyCode }).ConfigureAwait(false); // Assert const string expectedResult = @"<span class=""token keyword"">public</span> <span class=""token keyword"">string</span> <span class=""token function"">ExampleFunction</span><span class=""token punctuation"">(</span><span class=""token keyword"">string</span> arg<span class=""token punctuation"">)</span> <span class=""token punctuation"">{</span> <span class=""token comment"">// Example comment</span> <span class=""token keyword"">return</span> arg <span class=""token operator"">+</span> <span class=""token string"">""dummyString""</span><span class=""token punctuation"">;</span> <span class=""token punctuation"">}</span>"; Assert.Equal(expectedResult, result); }
public async void AllInvokeMethods_ReceiveAndLogStdoutOutput(string dummyLogArgument, string expectedResult) { // Arrange var resultStringBuilder = new StringBuilder(); HttpNodeJSService testSubject = CreateHttpNodeJSService(resultStringBuilder); // Act await testSubject. InvokeFromStringAsync <string>($@"module.exports = (callback) => {{ console.log({dummyLogArgument}); callback(); // Does not work // process.stdout.end(); // process.on(finish, () => callback()); // Does not work // process.stdout.write('', 'utf8', () => callback()); }}").ConfigureAwait(false); Thread.Sleep(1000); ((IDisposable)_serviceProvider).Dispose(); string result = resultStringBuilder.ToString(); // Assert Assert.Equal($"{nameof(LogLevel.Information)}: {expectedResult}\n", result, ignoreLineEndingDifferences: true); }
public void InvokeFromFileAsync_IsThreadSafe() { // Arrange const string dummyModule = "dummyModule.js"; const string dummyResultString = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act var results = new ConcurrentQueue <DummyResult>(); const int numThreads = 5; var threads = new List <Thread>(); for (int i = 0; i < numThreads; i++) { var thread = new Thread(() => results.Enqueue(testSubject.InvokeFromFileAsync <DummyResult>(dummyModule, args: new[] { dummyResultString }).GetAwaiter().GetResult())); threads.Add(thread); thread.Start(); } foreach (Thread thread in threads) { thread.Join(); } // Assert Assert.Equal(numThreads, results.Count); foreach (DummyResult result in results) { Assert.Equal(dummyResultString, result.Result); } }
public void InvokeFromFileAsync_WithTypeParameter_IsThreadSafe() { // Arrange const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(projectPath: _projectPath); // Act var results = new ConcurrentQueue <DummyResult>(); const int numThreads = 5; var threads = new List <Thread>(); for (int i = 0; i < numThreads; i++) { var thread = new Thread(() => results.Enqueue(testSubject. InvokeFromFileAsync <DummyResult>(DUMMY_RETURNS_ARG_MODULE_FILE, args: new[] { dummyArg }).GetAwaiter().GetResult())); threads.Add(thread); thread.Start(); } foreach (Thread thread in threads) { thread.Join(); } // Assert Assert.Equal(numThreads, results.Count); foreach (DummyResult result in results) { Assert.Equal(dummyArg, result.Result); } }
public async void TryInvokeFromCacheAsync_WithTypeParameter_IsThreadSafe() { // Arrange const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); await testSubject.InvokeFromStringAsync <DummyResult>(_dummyReturnsArgModule, DUMMY_CACHE_IDENTIFIER, args : new[] { dummyArg }).ConfigureAwait(false); // Act var results = new ConcurrentQueue <(bool, DummyResult)>(); const int numThreads = 5; var threads = new List <Thread>(); for (int i = 0; i < numThreads; i++) { var thread = new Thread(() => results.Enqueue(testSubject. TryInvokeFromCacheAsync <DummyResult>(DUMMY_CACHE_IDENTIFIER, args: new[] { dummyArg }).GetAwaiter().GetResult())); threads.Add(thread); thread.Start(); } foreach (Thread thread in threads) { thread.Join(); } // Assert Assert.Equal(numThreads, results.Count); foreach ((bool success, DummyResult value) in results) { Assert.True(success); Assert.Equal(dummyArg, value.Result); } }
public async void TryInvokeFromCacheAsync_WithoutTypeParameter_ReturnsFalseIfModuleIsNotCached() { // Arrange HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act bool success = await testSubject.TryInvokeFromCacheAsync(DUMMY_CACHE_IDENTIFIER).ConfigureAwait(false); // Assert Assert.False(success); }
public async void InvokeFromFileAsync_WithTypeParameter_InvokesFromFile() { const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(projectPath: _projectPath); // Act DummyResult result = await testSubject. InvokeFromFileAsync <DummyResult>(DUMMY_RETURNS_ARG_MODULE_FILE, args : new[] { dummyArg }).ConfigureAwait(false); // Assert Assert.Equal(dummyArg, result.Result); }
public async void InvokeFromFileAsync_InvokesJavascript() { const string dummyResultString = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act DummyResult result = await testSubject. InvokeFromFileAsync <DummyResult>("dummyModule.js", args : new[] { dummyResultString }).ConfigureAwait(false); // Assert Assert.Equal(dummyResultString, result.Result); }
public void HttpNodeJSService_FileWatching_GracefulShutdownEnabled_MoveToNewProcess_Setup() { var services = new ServiceCollection(); services.AddNodeJS(); services.Configure <OutOfProcessNodeJSServiceOptions>(options => options.EnableFileWatching = true); _serviceProvider = services.BuildServiceProvider(); _httpNodeJSService = _serviceProvider.GetRequiredService <INodeJSService>() as HttpNodeJSService; // Warmup. First run starts a Node.js process. _httpNodeJSService.InvokeFromStringAsync(DUMMY_WARMUP_MODULE).GetAwaiter().GetResult(); }
public async void TryInvokeFromCacheAsync_WithTypeParameter_ReturnsFalseIfModuleIsNotCached() { // Arrange HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act (bool success, DummyResult value) = await testSubject.TryInvokeFromCacheAsync <DummyResult>(DUMMY_CACHE_IDENTIFIER, args : new[] { "success" }).ConfigureAwait(false); // Assert Assert.False(success); Assert.Null(value); }
public async void AllInvokeMethods_ThrowInvocationExceptionIfNoExportNameSpecifiedAndModuleExportsIsNotAFunction() { // Arrange HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act InvocationException result = await Assert.ThrowsAsync <InvocationException>(() => testSubject.InvokeFromStringAsync <DummyResult>("module.exports = {result: 'not a function'};")). ConfigureAwait(false); // Assert Assert.StartsWith("The module \"module.exports = {result:...\" does not export a function.", result.Message); }
public async void InvokeFromStreamAsync_WithTypeParameter_WithRawStreamModule_InvokesFromStream() { // Arrange const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); MemoryStream memoryStream = CreateMemoryStream(_dummyReturnsArgModule); // Act DummyResult result = await testSubject.InvokeFromStreamAsync <DummyResult>(memoryStream, args : new[] { dummyArg }).ConfigureAwait(false); // Assert Assert.Equal(dummyArg, result.Result); }
public async void AllInvokeMethods_InvokeAsyncJavascriptMethods() { // Arrange const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act DummyResult result = await testSubject. InvokeFromStringAsync <DummyResult>("module.exports = async (resultString) => {return {result: resultString};}", args : new[] { dummyArg }).ConfigureAwait(false); // Assert Assert.Equal(dummyArg, result.Result); }
public async void InvokeFromStringAsync_InvokesJavascript() { // Arrange const string dummyResultString = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act DummyResult result = await testSubject. InvokeFromStringAsync <DummyResult>("module.exports = (callback, resultString) => callback(null, {result: resultString});", args : new[] { dummyResultString }).ConfigureAwait(false); // Assert Assert.Equal(dummyResultString, result.Result); }
public async void AllInvokeMethods_ThrowInvocationExceptionIfThereIsNoModuleExportWithSpecifiedExportName() { // Arrange const string dummyExportName = "dummyExportName"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act InvocationException result = await Assert.ThrowsAsync <InvocationException>(() => testSubject.InvokeFromStringAsync <DummyResult>("module.exports = (callback) => callback(null, {result: 'success'});", DUMMY_CACHE_IDENTIFIER, dummyExportName)). ConfigureAwait(false); // Assert Assert.StartsWith($"The module {DUMMY_CACHE_IDENTIFIER} has no export named {dummyExportName}.", result.Message); }
public async void InvokeFromStringAsync_WithoutTypeParameter_WithRawStringModule_InvokesFromString() { const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(projectPath: _projectPath); // Act await testSubject.InvokeFromStringAsync(_dummyExportsMultipleFunctionsModule, DUMMY_CACHE_IDENTIFIER, "setString", new[] { dummyArg }).ConfigureAwait(false); // Assert DummyResult result = await testSubject. InvokeFromStringAsync <DummyResult>(_dummyExportsMultipleFunctionsModule, DUMMY_CACHE_IDENTIFIER, "getString").ConfigureAwait(false); Assert.Equal(dummyArg, result.Result); }
public async void InvokeFromStringAsync_WithTypeParameter_WithModuleFactory_InvokesFromCacheIfModuleIsCached() { // Arrange const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); await testSubject.InvokeFromStringAsync(_dummyExportsMultipleFunctionsModule, DUMMY_CACHE_IDENTIFIER, "setString", new[] { dummyArg }).ConfigureAwait(false); // Act DummyResult result = await testSubject. InvokeFromStringAsync <DummyResult>(() => null, DUMMY_CACHE_IDENTIFIER, "getString").ConfigureAwait(false); // Assert Assert.Equal(dummyArg, result.Result); }
public async void AllInvokeMethods_ThrowInvocationExceptionIfModuleExportWithSpecifiedExportNameIsNotAFunction() { // Arrange const string dummyExportName = "dummyExportName"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act InvocationException result = await Assert.ThrowsAsync <InvocationException>(() => testSubject.InvokeFromStringAsync <DummyResult>($"module.exports = {{{dummyExportName}: 'not a function'}};", exportName: dummyExportName)). ConfigureAwait(false); // Assert Assert.StartsWith($"The export named {dummyExportName} from module \"module.exports = {{dummyEx...\" is not a function.", result.Message); }
public async void AllInvokeMethods_ThrowInvocationExceptionIfModuleHasNoExports() { // Arrange const string dummyModule = "return null;"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act InvocationException result = await Assert.ThrowsAsync <InvocationException>(() => testSubject.InvokeFromStringAsync <DummyResult>(dummyModule)). ConfigureAwait(false); // Assert Assert.StartsWith($"The module \"{dummyModule}...\" has no exports. Ensure that the module assigns a function or an object containing functions to module.exports.", result.Message); }
public async void InvokeFromFileAsync_WithoutTypeParameter_InvokesFromFile() { const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(projectPath: _projectPath); // Act await testSubject.InvokeFromFileAsync(DUMMY_EXPORTS_MULTIPLE_FUNCTIONS_MODULE_FILE, "setString", new[] { dummyArg }).ConfigureAwait(false); // Assert DummyResult result = await testSubject. InvokeFromFileAsync <DummyResult>(DUMMY_EXPORTS_MULTIPLE_FUNCTIONS_MODULE_FILE, "getString").ConfigureAwait(false); Assert.Equal(dummyArg, result.Result); }
public async void TryInvokeFromCacheAsync_WithTypeParameter_InvokesFromCacheIfModuleIsCached() { // Arrange const string dummyArg = "success"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); await testSubject.InvokeFromStringAsync <DummyResult>(_dummyReturnsArgModule, DUMMY_CACHE_IDENTIFIER, args : new[] { dummyArg }).ConfigureAwait(false); // Act (bool success, DummyResult value) = await testSubject.TryInvokeFromCacheAsync <DummyResult>(DUMMY_CACHE_IDENTIFIER, args : new[] { dummyArg }).ConfigureAwait(false); // Assert Assert.True(success); Assert.Equal(dummyArg, value.Result); }
public async void TryInvokeFromCacheAsync_ReturnsFalseIfModuleIsNotCached() { // Arrange const string dummyResultString = "success"; const string dummyCacheIdentifier = "dummyCacheIdentifier"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act (bool success, DummyResult value) = await testSubject.TryInvokeFromCacheAsync <DummyResult>(dummyCacheIdentifier, args : new[] { dummyResultString }).ConfigureAwait(false); // Assert Assert.False(success); Assert.Null(value); }
public async void AllInvokeMethods_InvokeASpecificExportIfExportNameIsNotNull() { // Arrange const string dummyArg = "success"; const string dummyExportName = "dummyExportName"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act DummyResult result = await testSubject. InvokeFromStringAsync <DummyResult>($"module.exports = {{ {dummyExportName}: (callback, resultString) => callback(null, {{result: resultString}}) }};", exportName : dummyExportName, args : new[] { dummyArg }).ConfigureAwait(false); // Assert Assert.Equal(dummyArg, result.Result); }
public async void AllInvokeMethods_ThrowInvocationExceptionIfInvokedAsyncMethodThrowsError() { // Arrange const string dummyErrorString = "error"; HttpNodeJSService testSubject = CreateHttpNodeJSService(); // Act InvocationException result = await Assert.ThrowsAsync <InvocationException>(() => testSubject.InvokeFromStringAsync <DummyResult>("module.exports = async (errorString) => {throw new Error(errorString);}", args: new[] { dummyErrorString })). ConfigureAwait(false); // Assert Assert.StartsWith(dummyErrorString, result.Message); // Complete message includes the stack }
public async void TryInvokeFromCacheAsync_WithoutTypeParameter_InvokesFromCacheIfModuleIsCached() { // Arrange HttpNodeJSService testSubject = CreateHttpNodeJSService(); await testSubject.InvokeFromStringAsync(_dummyExportsMultipleFunctionsModule, DUMMY_CACHE_IDENTIFIER, "incrementNumber").ConfigureAwait(false); // Act bool success = await testSubject.TryInvokeFromCacheAsync(DUMMY_CACHE_IDENTIFIER, "incrementNumber").ConfigureAwait(false); // Assert Assert.True(success); int result = await testSubject.InvokeFromStringAsync <int>(_dummyExportsMultipleFunctionsModule, DUMMY_CACHE_IDENTIFIER, "getNumber").ConfigureAwait(false); Assert.Equal(2, result); }
public async void InMemoryInvokeMethods_LoadRequiredModulesFromFilesInProjectDirectory() { // Arrange HttpNodeJSService testSubject = CreateHttpNodeJSService(projectPath: _projectPath); // Current directory is <test project path>/bin/debug/<framework> // Act int result = await testSubject.InvokeFromStringAsync <int>(@"const value = require('./dummyReturnsValueModule.js'); module.exports = (callback) => { callback(null, value); };").ConfigureAwait(false); // Assert Assert.Equal(10, result); // dummyReturnsValueModule.js just exports 10 }