Sequence contains more than one element an NancyBootstrapperBase class - unit-testing

I can't figure out why this exception was threw...
I have a unit test:
[Test]
public void Should_return_status_ok_when_route_exists()
{
// Given
var bootstrapper = new DefaultNancyBootstrapper();
var browser = new Browser(bootstrapper);
// When
var result = browser.Get("/", with =>
{
with.HttpRequest();
});
// Then
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
}
While browser variable was assigning, the exception threw in Nancy Bootstrapper Base class with follow stack trace
System.InvalidOperationException : Sequence contains more than one element
at System.Linq.Enumerable.SingleOrDefault(IEnumerable`1 source)
at Nancy.Bootstrapper.NancyBootstrapperBase`1.GetRootPathProvider() in NancyBootstrapperBase.cs: line 558
at Nancy.Bootstrapper.NancyBootstrapperBase`1.get_RootPathProvider() in NancyBootstrapperBase.cs: line 172
at Nancy.Bootstrapper.NancyBootstrapperBase`1.GetAdditionalInstances() in NancyBootstrapperBase.cs: line 514
at Nancy.Bootstrapper.NancyBootstrapperBase`1.Initialise() in NancyBootstrapperBase.cs: line 242
at Nancy.Testing.Browser..ctor(INancyBootstrapper bootstrapper) in Browser.cs: line 39
at Tests.Tests.Should_return_status_ok_when_route_exists() in Tests.cs: line 34

I've had the same problem recently. I was testing my bootstrapper by trying to resolve the Nancy module like this:
[Test]
public void PushModule_Is_Resolvable()
{
var pushModule = mUnderTest.GetModule(typeof (PushModule), new NancyContext());
Assert.That(pushModule, Is.Not.Null);
}
This yielded the exception described in the question. After reading Chris' answer I just configured that dll not to be copied to the output folder in Visual Studio:
Find the Nancy.Hosting.Self reference in the project that is tested.
Right-click the reference and choose "Properties".
Set Copy Local to false.
Clean and rebuild your solution.
This solved the issue for me.
I would have posted this as a comment to Chris' answer but since this is my very first post I can only post answers.

I've seen this with Nancy 0.16.1 on a fresh test assembly which references Nancy, Nancy.Testing and a project reference (in VS2010) to the main service assembly which contains my Modules.
The service assembly references Nancy.Hosting.Self.
The build for the test assembly pulls in Nancy.Hosting.Self.dll to the build folder and the test fails with the error you describe.
Removing the Hosting dll from the build folder by hand resolves the error and the test goes green e.g. delete MyTests\bin\Debug\Nancy.Hosting.Self.dll

I've experienced the same when testing with a project that refers to Nancy.Hosting.Self.
My workaround is to create a CustomBootstrapper and override RootPathProvider property.
class TestBootStrapper : DefaultNancyBootstrapper{
protected override IRootPathProvider RootPathProvider {
get {
return new FakeRootPathProvider();
}
}
}

Related

Asp.Net Core Dependency Injection doesn't work, if it is started from unmanaged/native

First i try to explain the story.
I wanted to extend an C++/MFC application with REST-APIs, and decided to use for this purpose Asp.Net-Core 5 in a library by bridging it to unmanaged code with C++/CLI library. (having a separete ASP application is doubled expenditure, and needed to be rewritten all the logic in C#. in that regard RESTful-Server should be in same process implemented.)
Asp-Host is started in that way; C++/MFC -> C++/CLI -> ASP-Library (ASP referenced in CLI, CLI referenced in Native)
First problem was; by building the host Microsoft.Extensions.Hosting.Abstractions-Assembly could not be resolved. I found that, "My CLI Library".runtimeconfig.json has wrong framework reference and causes it not to be resolved. That means generated runtimeconfig.json is wrong. After every build it has to be manually with AspNetCore instead of NETCore corrected. (Done in PostBuildEvent)
Next problem; during the ASP-Host build, ASP could not resolve "My ASP Library.dll"-Assembly (in reflection). This problem solved by OnAssemblyResolve event by giving the right path. I'm not sure whether it is correct solution. Because AppDomain.BaseDirectory is an empty string, maybe it is the cause of it, that the library could not found.
In AssemblyResolve event;
Assembly::LoadFrom(assemblyFile)
Finally i could start the server, and it works. Then needed to use dependency injection, and my service could not be resolved from the controller.
Then i used my ASP-Library in another C#-project to test and it works...
i'm sure that it doesn't work if the entry point of process is in unmanaged code.
public interface IServerImpl
{
void OnFail(String msg);
}
public class CServerImpl : IServerImpl
{
public void OnFail(String msg)
{
}
}
... in Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IServerImpl, CServerImpl>();
services.AddControllers();
}
... Controller
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private readonly IServerImpl _serverImpl;
public WeatherForecastController(ILogger<WeatherForecastController> logger, IServerImpl serverImpl)
{
_logger = logger;
_serverImpl = serverImpl;
}
...
}
Is there any workaround to have it working? Are those problems bug in Asp.Net-Core or what am i doing wrong?
Thanks in advance
The problem has been solved. Assembly resolving event with Assembly.LoadFrom() causes my ASP-assembly to be loaded (or mapped) twice. Loading it in different assembly-load-context means that, doubled Types, static variables and so on. In that regard my registered IServerImpl service searched in the controller with another IServerImpl type. Type names are identical, but not the same.
For more information see technical challenges: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext?view=net-5.0
Another issue on GitHub: https://github.com/dotnet/runtime/issues/39783
In assembly resolve event, i'm returning now the loaded assembly like that, instead of loading it again;
AppDomain.CurrentDomain.GetAssemblies()
.SingleOrDefault(asm => asm.FullName.StartsWith(args.Name.Split(',')[0] + ","))
still wellcome answers which clarifies "why my ASP-assembly not found from the framework?"

CakePHP 3.7 Shell commands inside a plugin couldn't execute

namespace Admin\Shell;
use Cake\Console\Shell;
class AdminAlertShell extends Shell{
...
...
}
Here 'Admin' is plugin, So I created this file inside the plugins folder structure.
File path : /plugins/Admin/src/Shell/AdminAlertShell.php
Tried to run this in CLI
bin/cake admin_alert
But an exception throws
Exception: Unknown command cake admin_alert. Run cake --help to get the list of valid commands. in [localpath/vendor/cakephp/cakephp/src/Console/CommandRunner.php, line 346]
It was working. But I don't know what happened to this. I had upgraded cakephp 3.5 to 3.7. But, I am not sure this caused the issue.
I just tracked down the source of the issue in my project.
Inside my plugin there was a file: src/Plugin.php
Inside this class there was the following lines of code:
/**
* #inheritDoc
*/
public function console(CommandCollection $commands): CommandCollection
{
// Add console commands here.
return $commands;
}
This was probably generated via bake.
I saw that the parent was not called. In the path is added in the parent.
Change this method to look like this:
/**
* #inheritDoc
*/
public function console(CommandCollection $commands): CommandCollection
{
// Add console commands here.
$commands = parent::console($commands);
return $commands;
}
Now the parent is called and the path is added to the command collection.
As a side note I also see the middleware is not calling its parent.
Think it would be a good idea to fix that one aswell.
As an alternative you can just clear out the class and all defaults should be used.
Hope this saves someone the hours it cost me to figure this one out.

In Unity3d test scripts, how do I call a static function from another class?

I have two files in a Unity3d project. One is a test script that runs in edit mode. The other is a single class with static functions that I'd like to call from the test scripts.
here's my test script:
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;
public class NewTestScript
{
[Test]
public void TestAnotherStaticFunction()
{
int a = NewBehaviourScript.FunctionUnderTest(1);
int b = 1;
// Use the Assert class to test conditions.
Assert.IsTrue(a == b);
}
}
here's my function under test:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
/// <summary>
/// the stupidest function in the world,
/// used to verify tests.
/// </summary>
public static int FunctionUnderTest(int a)
{
return a;
}
}
This gives me the error from the Unity compiler (I'm not building outside of Unity):
Assets/TestS/NewTestScript.cs(12,17): error CS0103: The name `NewBehaviourScript' does not exist in the current context
These are running in edit-mode.
I've tried adding and removing the SuperTestNameSpace namespace from the function under test and the calling code.
I've attempted adding/removing files from the .asmdef file that was autogenerated by unity, although this usually leads to other compile errors.
My previous unit test experience is largely in Visual Studio or VSCode, and I'm trying to get my unity3d test experience to match my prior test environment experiences.
Is there a fundamentally limited functionality in the edit-mode tests, or am I missing something stupid?
Further elaboration on the assemblies involved. It looks like there are two assemblies at play here: Assembly-CSharp.dll contains my code under test and TestS.dll contains my testing code. I believe my questions boils down to: how do I add a reference from the TestS.dll assembly to the Assembly-CSharp.dll. I'd know how to do this in Visual Studio (either via the context menu in VS or directly editing the csproj file), however I don't see how to do it in Unity3d. Any edit I make to the csproj file is frequently overwritten by unity, and while there is a 'references' section in the inspector (see picture) I can't add Assembly-CSharp.dll as a reference.
These are the inspector settings for TestS.asmdef. While there's an option to add references, I can't add a reference to Assembly-CSharp.dll, which is where my code-under-test lives.
Ok, I figured this out. There were two things going on:
Editor tests need to be underneath a folder called editor. It's really annoying that the unity editor doesn't do this for you.
You need to have an assembly definition for the code under test and add a reference from the test code to the newly created assembly definition. This must be done in the Unity editor UI.
by default, unity adds your script code to an assembly called Assembly-CSharp.dll, and, for reasons unknown, this assembly isn't referenced by my edit mode test code. I'm not sure if this is a bug in Unity or if it's by design, but explicitly creating and referencing the assembly definition has cleared things up.
The main issue is currently you are trying to call the
NewBehaviourScript(1);
constructor which does not exist...
instead of the method
using SuperTestNameSpace;
//...
NewBehaviourScript.FunctionUnderTest(1);
or alternatively with the namespace in the call directly
SuperTestNameSpace.NewBehaviourScript.FunctionUnderTest(1);
Also make sure the filename matches exactly the class name. So in your case it should be
NewBehaviourScript.cs
Note that the .cs is not printed by Unity in the Project view so there it should say NewBehaviourScript.
Why does it not compile with the using SuperTestNameSpace;? What is the error?
If that exception
Assets/TestS/NewTestScript.cs(14,17): error CS0103: The name `NewBehaviourScript' does not exist in the current context
is only shown in VisualStudio but the script compiling fine in Unity especially after adding a new script it helps to simply close and restart VS.
In some cases it also helps to close Unity and VS, remove all files and folders except Assets and ProjectSettings (and if you are under version control anything that belongs to it like e.g. .git, .gitignore, .gitattributes etc) in particular delete the Library, .vs folder and all .csproj and .sln files.
Than open Unity again and let it recompile everything.
Make sure the file that contains your NewBehaviourScript class IS NOT inside an Editor folder.
Move both the scripts in the Assets (root) folder and try again.

Unable to get Changesets in TFS Template 2013

I got a problem trying to develop a custom activity for a TFS template in TFS 2013.
My first step is to get the changesets associated with the build. And after a lot of tries and google I have always the same problems : my list is empty. My last attempt is from this article : http://www.colinsalmcorner.com/post/tfs-2013-default-build--the-getenvironmentvariablet-activity
Whatever I tried, in my custom activity I've always nothing.
public sealed class ChangeLogActivity : CodeActivity<IList<Changeset>>
{
[RequiredArgument]
public InArgument<IList<Changeset>> AssociatedChangesets { get; set; }
protected override IList<Changeset> Execute(CodeActivityContext context)
{
IList<Changeset> list = context.GetValue(this.AssociatedChangesets);
// list is empty, but not null
}
}
In my template, it's what I got :
Then my variables,
Then the property of GetEnvironmentVariable task
And Finally the properties of my activity
I don't know what I'm missing.
Plus, I don't know if it's related, even my TrackBuildWarning do nothing. I thought my context was not the good one, but how to verify it ?
I knew that just after posting my question I'll find the answer.
Simply, if between 2 successful builds no checkin was made, AssociatedChangeset will always be empty.
I can understand why, the build display is very tricky.
It says at the top "build was started by blabla with associated changeset 14"
So I supposed wrongly that I can always get this information...

Where should I put Velocity template files for a command line utility built with Maven?

I have a small command line utility project that I'm using Maven to manage. The utility is a very simple app to populate a Velocity template and dump the results to a new file. My problem is where to put my Velocity templates. When I put them in src/test/resources/foo/bar/baz, mvn test fails because it can't find the referenced template, even though it is clearly there in target/classes/foo/bar/baz, which is where the .class file for the test and the class under test are located. If I put the template in the top-level directory of the project, the test passes, but then I'm not following the Maven project structure, and I suspect that the actual packaged .jar file wouldn't function. What am I missing?
UPDATE:
Method under test:
public final void mergeTemplate(final String templateFileName, final Writer writer) throws ResourceNotFoundException, ParseErrorException, MethodInvocationException, IOException, Exception {
Velocity.init();
Velocity.mergeTemplate(templateFileName, Charset.defaultCharset().name(), context(), writer);
}
Test method:
#Test
public void testMergeTemplate() throws Exception {
final FooGenerator generator = new FooGenerator();
final StringWriter writer = new StringWriter();
generator.mergeTemplate("foo.yaml", writer);
Assert.assertEquals("Something went horribly, horribly wrong.", EXPECTED_RESULT, writer.toString().trim());
}
The only place I can place foo.yaml and have the tests pass is in the root directory of the project, i.e., as a peer of src and target.
You can programmatically configure TEMPLATE_ROOT as follows:
Properties props = new Properties();
props.put("file.resource.loader.path", templateRootDir);
VelocityEngine engine = new VelocityEngine();
engine.init(props);
engine.evaluate(...);
You should put them in src/main/resources/foo/bar/baz because they need to be included in the main jar file.
So it turns out that instead of using something like
generator.mergeTemplate("foo.yaml", writer);
I should use something like
InputStream fooStream = getClass().getResourceAsStream("foo.yaml");
generator.mergeTemplate(fooStream, writer);
You could just configure Velocity to use the ClasspathResourceLoader, instead of the default FileResourceLoader.
I have tried Velocity.setProperty() to set the properties similar to what was said above by #Jin Kim and was able to run it.
VelocityEngine ve = new VelocityEngine();
ve.setProperty(RunTimeConstants.RESOURCE_LOADER,"file");
ve.setProperty("file.resource.loader.path",templaterootdir);
ve.init();