I am trying to write a simple custom function extension for WS02 (4.2.0). My function basically takes in a String and returns the upper case. This is meant to be a first step POC for a more advanced custom function.
I implemented a class that extended the org.wso2.siddhi.core.executor.function.FunctionExecutor class, and created a ams.siddhiext file. I then packaged the class and the siddhiext in a JAR file using the maven-bundle plugin.
My function class looks like this
public class AnomalyDetector extends FunctionExecutor {
private final static Logger LOG = LoggerFactory.getLogger(AnomalyDetector
.class);
#Override
protected void init(ExpressionExecutor[] expressionExecutors, ExecutionPlanContext executionPlanContext) {
LOG.info("In AD:init()");
}
#Override
protected Object execute(Object[] objects) {
return null;
}
#Override
protected Object execute(Object o) {
LOG.info("In AD:process(" + o.toString() + ")");
String eventData = (String) o;
LOG.info("Event data : " + eventData);
if (eventData != null) {
return eventData.toUpperCase();
} else {
return "Null event data";
}
}
#Override
public void start() {
LOG.info("In AD:start()");
}
#Override
public void stop() {
}
#Override
public Map<String, Object> currentState() {
return null;
}
#Override
public void restoreState(Map<String, Object> map) {
}
#Override
public Attribute.Type getReturnType() {
return Attribute.Type.STRING;
}
}
I then put the jar in the /repository/components/lib/ since /repository/components/dropins/ did not pick it up.
I have 2 issues that are blocking me currently.
I wanted to write a simple execution plan that takes a value from an input stream (String), invoke my custom function and write the output to an export stream.
#Plan:name('AMSExecutionPlan')
#Import('AMSStream:1.0.0')
define stream amsStream (metrics_json string);
#Export('AnomalyStream:1.0.0')
define stream anomalyStream (anomaly string);
from amsStream
select ams:findAnomaly(metrics_json) as anomaly
insert into anomalyStream
I get the following validation error.
What could be wrong with my execution plan?
Whenever I change my custom function class, rebuild the jar and replace it in the wso2 classpath, and then restart ws02, I dont see the changes reflected in ws02. The log lines that I print out in my custom function class reflect an older version of the code. What should I do to make changes to my Custom function class on a live ws02 instance?
Thanks in advance!
Can you bundle the jar as an OSGI bundle and try? There can be a issue when converting your jar to an OSGI bundle.
Validation error you have pointed suggest that your extension is not returning the return type properly. But I can see you have implemented getReturnType() correctly. So may be your source and actual running code might not be synced up due to issue 2. So let's address that first.
In WSO2 servers lib folder is used to add non-OSGi dependencies and dropins for OSGi dependencies. Fact that it works in lib and not in dropins suggest that your jar is not packed as a bundle. To achieve that please follow below pom file from String extension. There are two things to note.
[1] Usage of bundle packaging
[2] Usage of bundle plugin
Update your pom referencing this and then you will be able to add your bundle to dropins directly. Also this is the reason why your changes are not reflected. When you add your jar to lib server will internally convert it to an OSGi bundle and add to dropins. Now when you update the jar in lib again the one in dropins will not get updated. It will be the old bundle. Hence changes are not reflected. This issue will also go away when you update the pom and build the bundle correctly.
[1] https://github.com/wso2/siddhi/blob/v3.1.0/modules/siddhi-extensions/string/pom.xml#L29
[2] https://github.com/wso2/siddhi/blob/v3.1.0/modules/siddhi-extensions/string/pom.xml#L57
Hope this helps!!
Related
I have an AWS Lambda Web API and I'm trying to use code that I've used before to load the appsettings.json into memory.
In appsettings.json I have this:
{
"AppSettings": {
"TestValue": "Some value"
}
}
In StartUp.cs I have this:
public class Startup
{
public static IConfiguration Configuration { get; private set; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
And in SomeController.cs I have this:
public class SapController : ControllerBase
{
private readonly AppSettings _appSettings;
public SapController(IOptionsMonitor<AppSettings> optionsMonitor)
{
_appSettings = optionsMonitor.CurrentValue;
}
The problem is, under the Mock Lambda Test Tool the _appSettings properties are all null.
I really don't want to load the appsettings using special case code, as seen in this post and described here. I really thought it should load as normal. Am I wrong with this opinion?
Is it really necessary to load appsettings under the mock lambda test tool using this code?:
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
So, it turns out that for some reason the appsettings is not being passed in to my constructors. So my controller now has this in the constructor:
public MyController(IConfiguration configuration)
{
_appSettings = configuration.GetSection(nameof(AppSettings)).Get<AppSettings>();
}
The short of it appears to be that I need to acquire the AppSettings instance from the Configuration instance, rather than having it passed in via IoC.
I still don't know why, but at least this works.
Try right-clicking your appsettings.Development.json file and set Copy to Output Directory to Copy always. This will ensure that it will be copied to the same directory as your executable upon build, and your app will find and load it.
You can add the file to your .gitignore if you don't want it to be part of your deployment package. Regardless, it will not be read in Production.
I have an extension method which is used to read a particular claim from the current ClaimsPrincipal. But I also need to check this value against a list of items which I have in the appsettings.json.
I had this working by using a ConfigurationBuilder() to read the appsettings directly in much the same way as the startup does, although instead of using
.SetBasePath(Directory.GetCurrentDirectory())
as I do in the startup, I was using
.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))
Which although isn't pretty, works fine.
However, when the Unit tests are run none of the following get me to where the appsettings are
Directory.GetCurrentDirectory()
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
and I cannot see a way of getting the IHostingEnvironment or something similar into the extension method to read out the appsettings, or indeed to ditch the ConfigurationBuilder() and get at IOptions in the extension method, in such a way that the unit test and the running code will work correctly.
I assume there must be a way of doing this? Although I expect that I should simply not be trying at all and lift the check against the list of items into another class entirely...
Putting business logic that may ever require dependencies into static methods is not recommended. This makes it difficult to inject dependencies into them. Options are few:
Redesign the static method into a service so dependencies can be injected through the constructor. (Recommended)
public class Foo : IFoo
{
private readonly IOptions<FooOptions> optionsAccessor;
public Foo(IOptions<FooOptions> optionsAccessor)
{
this.optionsAccessor = optionsAccessor ??
throw new ArgumentNullException(nameof(optionsAccessor));
}
public void DoSomething()
{
var x = this.optionsAccessor;
// Same implementation as your static method
}
}
Inject the dependencies as parameters of the extension method.
public static void DoSomething(this object o, IOptions<FooOptions> optionsAccessor)
{
// Implementation
}
Redesign the static method to be a facade over an abstract factory like this example.
I have inherited some code that isn't tested and which loads a resource using a method like :
SomeClass.class.getClassLoader().getResource("somefile");
I've written the following test but there are 0 interactions with the Mock class loader I've created. Can anyone comment on whether this type of test is possible.
public enum SomeClass {
INSTANCE;
public boolean someMethod() {
URL pathToLicense = SomeClass.class.getClassLoader().getResource("somefile");
return false;
}
}
#Test
public void testLicenseWorkflow(){
ClassLoader cl = PowerMockito.mock(ClassLoader.class);
File f = new File("someFile");
assertTrue(f.exists());
logger.info(f.getCanonicalPath() );
when(cl.getResource("somefile")).thenReturn(f.toURL());
verify(cl).getResource("somefile");
assertTrue(SomeClass.INSTANCE.someMethod());
}
Update - Adding a resources via Classloader
I've also tried the following but the someMethod this doens't seem to work either
new URLClassLoader(((URLClassLoader) SomeClass.INSTANCE.getClass().getClassLoader()).getURLs()) {
#Override
public void addURL(URL url) {
super.addURL(url);
logger.info("Calling add URL");
}
}.addURL(f.toURI().toURL());
You are not passing cl to anything. You prepare a mock for a classloader but then proceed to load the resource with another classloader, the one that loaded SomeClass. That is why you have 0 interactions in your mock.
And about your first question, it is possible if somehow you pass your mocked classloader to the method that actually loads the resource. For example, something like
public boolean someMethod(Classloader loader) {
URL pathToLicense = loader.getResource("somefile");
return false;
}
But I have to say that IMO, this test is not very useful, you should be mocking your own components, not java classes. If your goal mocking the classloader is to inject a different file when testing, a better approach is to change your code to receive a Stream and inject a stream connected to the file in production and in testing inject a stream connected to an element in memory.
In other words, resources make for bad testing when they need to be changed at test time
I hope someone has already faced and solved this issue, and can point me to the correct direction.
So I have rest of my unit tests working: Core.Tests has tests for ViewModels to see they are working properly. Now I would like to set up a test project for Phone.Tests that would only test out the binding. So suppose on the login page, something get's entered into the username text box, and that value should be updated in ViewModel and vice-versa.
As a testing framework, I am using WP Toolkit Test framework, and not MS one; WP Toolkit framework runs on the phone itself, meaning it has access to the UI thread.
In theory a test is supposed to look like following:
[TestMethod]
[Asynchronous]
public void Username_Update_View_Should_Update_Model()
{
const string testUsername = "Testing";
var usernameTextBox = GetUiElement<PhoneTextBox>("UsernamePhoneTextBox");
// initial value
Assert.AreEqual(null, _viewModel.Authorization.Username, "Default value should be blank");
//
usernameTextBox.Text = testUsername;
//
Assert.AreEqual(testUsername, _viewModel.Authorization.Username, "Binding not set for {0}", "Username");
}
private T GetUiElement<T>(string name) where T : UIElement
{
return (T)_view.FindName(name);
}
Now, I need to somehow create the view in [TestInitialize] method, and this is what I think I have setup wrong.
I have tried creating the ViewModel manually; then I created the View manually, and binded both DataContext and ViewModel (just to be on safe side) to created viewModel.
At this point, I am expecting changing one property on any one should update the other.
Of-course the error is my test fails. I can't figure out if I should be looking at a custom presenter (all the examples seem to be for ios, droid.) I also tried the following:
public class TestAppStart : MvxNavigatingObject, IMvxAppStart
{
public void Start(object hint = null)
{
ShowViewModel<UserLoginViewModel>();
}
}
and then on my testInitialize I thought I could start it, but I guess I need to find RegisterAppStart and once that's done, try to get the view back from RootFrame.
There must be an easier way... anyone??
Thanks in advance.
Edited: I have got this following as Base Test
public abstract class BaseTest
{
private IMvxIoCProvider _ioc;
protected IMvxIoCProvider Ioc
{
get
{
return _ioc;
}
}
public void Setup()
{
ClearAll();
}
protected virtual void ClearAll()
{
MvxSingleton.ClearAllSingletons();
_ioc = MvxSimpleIoCContainer.Initialize();
_ioc.RegisterSingleton(_ioc);
_ioc.RegisterSingleton((IMvxTrace)new DebugTrace());
InitialiseSingletonCache();
InitialiseMvxSettings();
MvxTrace.Initialize();
AdditionalSetup();
}
private static void InitialiseSingletonCache()
{
MvxSingletonCache.Initialize();
}
protected virtual void InitialiseMvxSettings()
{
_ioc.RegisterSingleton((IMvxSettings)new MvxSettings());
}
protected virtual void AdditionalSetup()
{
_ioc.RegisterSingleton(Mock.Of<ISettings>);
_ioc.RegisterSingleton<IApplicationData>(() => new ApplicationData());
_ioc.RegisterSingleton<IPlatformSpecific>(() => new PlatformSpecific());
_ioc.RegisterSingleton<IValidatorFactory>(() => new ValidatorFactory());
//
_ioc.RegisterType<IMvxMessenger, MvxMessengerHub>();
}
}
On my TestClass initialize, I call base.Setup(), which does setup except the ViewDispatcher. Unfortunately I can't figure out how to use that dispatcher:
I guess really the question I am asking is: how do I get a View through MvvmCross.
PS: I am actually surprised that most don't test the bindings; isn't it where the most amount of mistakes is likely to happen? I am pretty sure the project compiles even if I had bad binding :) scary kind of reminds me of early asp days.
PS: I have actually got another testProject that tests the ViewModels; on that testProject I have managed to hookup following the guidelines at
http://blog.fire-development.com/2013/06/29/mvvmcross-unit-testing-with-autofixture/
Which works beautifully; and also uses autoFixture, NSubstitute and xUnit: and I can't use any of them in Phone Test project.
From my experience, testing the bindings themselves is pretty unusual - most developers stop their testing at the ViewModel and ValueConverter level.
However, if you want to test the bindings, then this should be possible. I suspect the only problem in your current tests is that you haven't initialised any of the MvvmCross infrastructure and so MvxViewModel isn't able to propagate INotifyPropertyChanged events.
If you want to initialise this part of the MvvmCross infrastructure, then be sure to initialise at least:
the MvvmCross IoC container
the MvvmCross main thread dispatcher
This is similar to what is done in the unit tests in the N=29 video - see https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-29-TipCalcTest/TipCalcTest.Tests/FirstViewModelTests.cs#L57
For your app, you can do this using something like:
public static class MiniSetup
{
public static readonly MiniSetup Instance = new MiniSetup();
private MiniSetup()
{
}
public void EnsureInitialized(Context applicationContext)
{
if (MvxSimpleIoCContainer.Instance != null)
return;
var ioc = MvxSimpleIoCContainer.Initialize();
ioc.RegisterSingleton<IMvxTrace>(new MvxDebugOnlyTrace());
MvxTrace.Initialize();
var mockDispatcher = new SimpleDispatcher();
Ioc.RegisterSingleton<IMvxMainThreadDispatcher>(simpleDispatcher);
}
}
where SimpleDispatcher is something like:
public class SimpleDispatcher
: MvxMainThreadDispatcher
{
public readonly List<MvxViewModelRequest> Requests = new List<MvxViewModelRequest>();
public bool RequestMainThreadAction(Action action)
{
action();
return true;
}
}
If you want further MvvmCross functionality available (e.g. ShowViewModel navigation), then you'll need to provide further services - e.g. things like IMvxViewDispatcher - as the number of these increases, you might be better off just running through a full MvxSetup process (like your main app's Setup does)
Im reading "The art of unit testing" atm and im having some issues with using properties to pass in an interface. The book states the following: "If you want parameters to be optional, use property getters/setters, which is a better way of defining optional parameters than adding different constructors to the class for each dependency."
The code for the property example is as follows:
public class LogAnalyzer
{
private IExtensionManager manager;
public LogAnalyzer ()
{
manager = new FileExtensionManager();
}
public IExtensionManager ExtensionManager
{
get { return manager; }
set { manager = value; }
}
public bool IsValidLogFileName(string fileName)
{
return manager.IsValid(fileName);
}
}
[Test]
Public void
IsValidFileName_NameShorterThan6CharsButSupportedExtension_ReturnsFalse()
{
//set up the stub to use, make sure it returns true
...
//create analyzer and inject stub
LogAnalyzer log = new LogAnalyzer ();
log.ExtensionManager=someFakeManagerCreatedEarlier;
//Assert logic assuming extension is supported
...
}
When/how would i use this feature?? The only scenario i can think of (This is probably wrong!) is if i had two methods in one class,
Method1() retrieves the database connection string from the config file and contains some form of check on the retrieved string.
Method2() then connect to the database and returns some data. The check here could be that that returned data is not null?
In this case, to test Method1() i could declare a stub that implements the IExtensionManager Interface, where the stub has a string which should pass any error checks i have in method1().
For Method2(), i declare a stub which implements the interface, and declare a datatable which contains some data, in the stub class. id then use the properties to assign this to the private manager variable and then call Method2?
The above may be complete BS, so if it is, id appreciate it if someone would let me know and ill remove it.
Thanks
Property injection used to change object's behavior after it was created.
BTW your code is tight coupled to FileExtensionManager, which is concrete implementation of IExtensionManager. How you are going to test LogAnalyzer with default manager? Use constructor injection to provide dependencies to your objects - this will make them testable:
public LogAnalyzer (IExtensionManager manager)
{
this.manager = manager();
}