How spring-cloud-function-deployer deploy/undeploy function at runtime? - spring-cloud-function

I am trying to build my own faas service.I want to support load the function at runtime.
#SpringBootApplication
#EnableScheduling
public class DeployerApplication {
FunctionCatalog catalog;
#Scheduled(cron = "0/5 * * * * ?")
void loadSomething() {
String[] args = new String[]{
"--spring.cloud.function.location=./faas-function/target/faas-function-1.0-SNAPSHOT-boot.jar",
"--spring.cloud.function.function-class=com.example.Tmp"};
ApplicationContext context = SpringApplication.run(TmpApplication.class, args);
catalog = context.getBean(FunctionCatalog.class);
}
public static void main(String[] args) {
SpringApplication.run(DeployerApplication.class, args);
}
#SpringBootApplication(proxyBeanMethods = false)
private static class TmpApplication {
}
}
but when I run those code, I got those
Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.boot:type=Admin,name=SpringApplication
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437) ~[na:1.8.0_201]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898) ~[na:1.8.0_201]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966) ~[na:1.8.0_201]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900) ~[na:1.8.0_201]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324) ~[na:1.8.0_201]
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522) ~[na:1.8.0_201]
at org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar.afterPropertiesSet(SpringApplicationAdminMXBeanRegistrar.java:129) ~[spring-boot-2.4.0.jar:2.4.0]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1847) ~[spring-beans-5.3.1.jar:5.3.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1784) ~[spring-beans-5.3.1.jar:5.3.1]
... 32 common frames omitted
How spring-cloud-function-deployer deploy/undeploy function at runtime?

Your question is very broad, so . . .
There is an integration test case in the project git repository as well as individual projects demonstrating several supported scenarios (i am sure you'll find the one that fits you), Please have a look and feel free to follow up with more concrete questions.

Related

Roslyn analyzer - resolving base classes deep does not work during editing

We have some custom roslyn analyzers for one of our .net project. Some of the rules need to analyze all base classes deep of a given ClassDeclaration. The problem is, that we also need the SematicModel which belongs to the base classes in order to resolve the GetDeclaredSymbol of that ClassDeclaration. Currently we are getting the SemanticModel by resolving it at the SyntaxNodeAnalysisContext.Compilation.
This works when compiling our project from the scratch, but when editing the code roslyn analyzers are also executed periodically.
Sometimes we are getting a System.ArgumentException mentioning the SyntaxTree is not part of the compilation.
Is there a save way to analyze all base classes of a given ClassDeclaration with the need to have the SemanticModel belonging to each base class as well as the SyntaxNode which is currently analysed. Please find the code below which shows how we are analyzing the base class currently.
Does anybody has an idea how to avoid the error mentioned above or what I am doing wrong?
public override void Initialize(AnalysisContext context)
{
context.RegisterCompilationStartAction(compilationContext =>
{
//... here we are collecting some base stuff from the compilationContext.Compilation
compilationContext.RegisterSyntaxNodeAction(syntaxNodeAnalysisContext =>
{
var classDeclaration = (ClassDeclarationSyntax)syntaxNodeAnalysisContext.Node;
var meAndBaseClasses = GetClassDeclarationsDeep(classDeclaration, compilationContext.Compilation);
// now we can analyze the current node because we have infos about all bases classes deep
}, SyntaxKind.ClassDeclaration);
});
}
protected IEnumerable<ClassDeclarationSyntax> GetClassDeclarationsDeep(ClassDeclarationSyntax classDeclaration, Compilation compilation)
{
foreach (var type in classDeclaration.GetMeAndBaseTypes(compilation.GetSemanticModel(classDeclaration.SyntaxTree)))
{
foreach (var partialType in GetClassDeclarations(type, compilation))
{
yield return partialType;
}
}
}
public static IEnumerable<INamedTypeSymbol> GetMeAndBaseTypes(this ClassDeclarationSyntax classDeclaration, SemanticModel semanticModel)
{
return GetMeAndBaseTypes(semanticModel.GetDeclaredSymbol(classDeclaration));
}
protected IEnumerable<ClassDeclarationSyntax> GetClassDeclarations(INamedTypeSymbol classType, Compilation compilation)
{
return classType.DeclaringSyntaxReferences.SelectMany(t => t.SyntaxTree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()).Where(t => SymbolEqualityComparer.Equals(classType, compilation.GetSemanticModel(t.SyntaxTree).GetDeclaredSymbol(t)));
}
public static IEnumerable<INamedTypeSymbol> GetMeAndBaseTypes(this INamedTypeSymbol type)
{
List<INamedTypeSymbol> types = new List<INamedTypeSymbol>();
while (type != null)
{
types.Add(type);
type = type.BaseType;
}
return types;
}

Mockito Inline Mock Maker - throws Exception - Argument passed to when() is not a mock

I wanted to mock static methods, hence used dependency "mockito-inline" 3.8 version instead of "mockito-core"
The static method mocks work fine but my old tests that mock interfaces fail with the below error
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
Reverting to using mockito-core solves the issue but then I would not be able to mock static methods
Is there any way we can choose different mockito engines (Subclass/Inline) for each class?
MockResolver fixed the issue as described in https://github.com/mockito/mockito/issues/1980
If you need to mock static methods and you cannot use mockito-inline you could do something like this with mockito-core:
public class MockitoUtil {
public static <T, S> void mockStaticMethod(Class<T> classToMock, String nameOfMethodToMock, S result) {
MockCreationSettings<T> settings = mock(MockCreationSettings.class);
when(settings.isSerializable()).thenReturn(true);
MockHandler<T> handler = new MockHandler<>() {
private static final long serialVersionUID = 1L;
#Override
public Object handle(Invocation invocation) throws Throwable {
String invokedMethodName = invocation.getMethod().getName();
if(!invokedMethodName.equals(nameOfMethodToMock)){
String message = "called %s on class %s, but only %s was implemented";
throw new Exception(String.format(message, invokedMethodName, classToMock.getName(), nameOfMethodToMock));
}
return result;
}
#Override
public MockCreationSettings<T> getMockSettings() { return null; }
#Override
public InvocationContainer getInvocationContainer() { return null; }
};
MockMaker.StaticMockControl<T> classToMockControl = Mockito
.framework()
.getPlugins()
.getInlineMockMaker()
.createStaticMock(classToMock, settings, handler);
classToMockControl.enable();
}
}
N.B. you should call classToMockControl.disable() after the static method invocation if you'd like to mock static methods of other classes in the same test

How to mock Microsoft.Extensions.Logging using Moq

I'm currently trying to get the following code to succeed at runtime:
public delegate void LogDelegate(LogLevel logLevel, EventId eventId, object state, Exception exception, Func<object, Exception, string> formatter);
public abstract class LoggingTestBase
{
private Mock<ILogger> _mockLogger;
public ILogger Setup(LogDelegate logCallback)
{
_mockLogger = new Mock<ILogger>(MockBehavior.Strict);
_mockLogger.Setup(logger => logger.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<Exception>(),
It.IsAny<Func<object, Exception, string>>()))
.Callback(logCallback);
return _mockLogger.Object;
}
}
The problem is, that I get a MockException once I run the test because the method that gets called is the generic ILogger.Log<FormattedLogValues>(...) which I obviously didn't setup.
Reading the existing answer to this and the Moq documentation I came to the conclusion that I should probably just mock the generic method with the correct type argument as shown above.
Here I stumbled into the next problem which brings me to the end of ideas:
In current versions of Microsoft.Extensions.Logging FormattedLogValues is no longer public but internal (following this PR) which makes impossible to mock the generic method that gets called in the end.
Has anyone successfully solved this issue?
How?
I have a similar issue. I just want to verify that a call to LogInformation is called. According to this -> https://github.com/aspnet/Extensions/issues/1319 It should probably be solved by Moq..
However, at the end there is an suggestion that you could use It.IsAnyType instead of object.. For you this would be something like:
_mockLogger.Setup(logger => logger.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
(Func<It.IsAnyType, Exception, string>) It.IsAny<object>()))
.Callback(logCallback);
I've not been able to make it work, but maybe this pushes you in the right direction?
The Verify solution explained and solved here:
https://adamstorr.azurewebsites.net/blog/mocking-ilogger-with-moq
, the Github source is here.
My personal circumstances don't call for verify, just Moq around the Log calls. So I have modified the code to be:
namespace my.xTests
{
public static class VerifyLoggingUtil
{
public static Mock<ILogger<T>> SetupLogging<T>(
this Mock<ILogger<T>> logger
)
{
Func<object, Type, bool> state = (v, t) => true;
logger.Setup(
x => x.Log(
It.Is<LogLevel>(l => true),
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => state(v, t)),
It.IsAny<Exception>(),
It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)));
return logger;
}
}
}
and in my xUnit test setup:
namespace my.xTests
{
public class myTests{
private Mock<Microsoft.Extensions.Logging.ILogger<sFTPAzFn.Logging>> moqlog;
private MockRepository mockRepository;
public myTests(){
this.mockRepository = new MockRepository(MockBehavior.Strict);
moqlog = this.mockRepository.Create<Microsoft.Extensions.Logging.ILogger<MyLoggingClass>>();
}
private IInterfaceUnderTest CreateService(){
var moqlogobject = moqlog.SetupLogging<MyLoggingClass>().Object;
return new ClassUnderTest(moqlogobject);
}
}
}

Mocking Test : How-to refactor legacy singleton used in static

Well, I'm looking for the best way to refactor a (huge) legacy code-base and introducing some tests in it..There was no test framework. (yeah, I mean not at all)
It was an JEE 5 application. The goal is to revamp that in JEE7
Let me introduce a quick overview .
The end-users (those of them who are authorized) are free to evolve , configure many aspect of the application behavior by setting in the UI a bunch of preferences.
Theses are stored in an SQL table for the main part (the rest in some xml and properties files).
To fulfill this requirement, there is an #Startup object dedicated to build a sort-of huge map with all key-values.
Then all across the code base when a use case needs to adapt it's processing it checks the current value of the parameter(s) needed to its task.
A real case is that the app has to do a few operations on images;
For instance, Class ImgProcessing has to create thumbnail of a picture via this method :
Optional<Path> generateThumb_fromPath(Path origImg);
for this the method generateThumb_fromPath, calls Thumbnailer,
which uses a generic ImageProcessingHelper,
which holds a few set of generic image related tools and methods,
and specially an static method returning the wished dimensions of the thumbnail to be generated based on the original image constraints and some thumbnail preferences (keys = "THUMBNAIL_WIDTH" and "THUMBNAIL_HEIGHT").
These preferences are the user wishes for what size a thumbnail should have.
So far so good, nothing special.
Now the dark side of this :
The original JEE5 config loader is an bad old fashioned infamous singleton pattern as :
OldBadConfig {
private static OldBadConfig instance ;
public static getInstance(){
if(instance==null){
// create, initialize and populate our big preferences' map
}
return instance;
}
}
Then all across the whole code-base these preferences are used. In my refactoring effort I've already done using #Inject for injecting the singleton object.
But in static utilities ( no injection point available ) you have lots of this nasty calls :
OldBadConfig.getInstance.getPreference(key, defaultValue)
(Briefly I will explain that I use testNg + Mockito, I don't think the tools are relevant here, it seems to be more about an original terrible design,
but if I HAVE to change my toolbox (Junit or whatever) I will. But again I don't think the tooling is the root problem here. )
Trying to refactor the image part and make it test-friendly., I want to do this test with cut = instance of my Class Under Test:
#Test
public void firstTest(){
Optional<Path> op = cut.generateThumb_fromPath(targetPath);
// ..assertThatTheThumbnailWasCreated........
}
So in a few words ,
the execution flow will be like :
class under test --> some business implementation --> someutilities --> static_global_app_preference ---> other_class-othermethod.finalizingProcessing,
then return to the caller.
My testing effort halts here. How to mock the static_global_app_preference ?
How can I refactor the static_global_app_preference part from
*OldBadConfig.getInstance.getPreference(key, defaultValue)*
to something mockable where I could mock like :
Mockito.when(gloablConf.getPreference("THUMBNAIL_WIDTH", anyString)).thenReturn("32");
I've spent quite a time reading boks, blog posts etc all saying
'(these kind of) Singleton is EVIL'. You should NOT do that !
I think we all agree , thanks.
But what about a real word and effective solution to such really trivial, common tasks?
I can not add the singleton instance (or the preferences'map ) as parameters (because as it is already spread all across the code-base it will pollute all and every classes and methods . For instance in the exposed use case, it will pollute 5 methods in 4 classes just for one, poor, miserable, access to a parameter.
It's really not feasible.
So far I tried to refactor OldBadConfig class in two part : one with all initialization/write stuff,
and the other with only the read parts. that way I can at least make this a real JEE #Singleton and benefits from concurrent access once the startup is over and the configuration all loaded.
Then I tried to make this SharedGlobalConf accessible via a factory, called like :
SharedGlobalConf gloablConf= (new SharedGlobalConfFactory()).getShared();
then gloablConf.getPreference(key, defaultValue); is accessible.
It seems to be a little better than the original bottleneck, but didn't help at all for the testing part.
I thought the factory will ease everything but nothing like that comes out.
So there is my question :
For myself, I can split the OldBadConfig to an startup artefact doing the init and refesh, and to an SharedGlobalConf which is a JEE7 pure Singleton,
#Singleton
#ConcurrencyManagement(ConcurrencyManagementType.BEAN)
#Lock(LockType.READ)
Then, as for the legacy use case described here, How Can I make this reasonably mock-able ? Real word solutions are all welcomed.
Thanks sharing your wisdom and skills !
I will like to share my own answer.
Let's say we got these classes after the initial large OldBadConfig class was splitted :
#Startup AppConfigPopulator in charge of loading all information and populating the kind-of internal cache,
which is now a distinct SharedGlobalConf object. The populator is the only one in charge of feeding the SharedGlobalConf via :
#Override
public SharedGlobalConf sharedGlobalConf() {
if (sharedGlobalConf.isDirty()) {
this.refreshSharedGlobalConf();
}
return sharedGlobalConf;
}
private void refreshSharedGlobalConf() {
sharedGlobalConf.setParams(params);
sharedGlobalConf.setvAppTempPath_temp(getAppTempPath_temp());
}
In all components (by that I mean all Classes holding valid injection points) you just do your classic
#Inject private SharedGlobalConf globalConf;
For static utilities that can not do #Inject, we got an SharedGlobalConfFactory which handles the shared data to everything in a one-liner :
SharedGlobalConf gloablConf = (new SharedGlobalConfFactory()).getShared();
That way our old code base can be smoothly upgraded : #Inject in all valid components, And the (too many) old utilities that we can not reasonably rewrite them all in this refactoring step can get these
*OldBadConfig.getInstance.getPreference(key, defaultValue)*
,simply replaced by
(new SharedGlobalConfFactory()).getShared().getPreference(key, defaultValue);
And we are test-compliant and mockable !
Proof of concept :
A really critical Business demands is modeled in this class :
#Named
public class Usage {
static final Logger logger = LoggerFactory.getLogger(Usage.class);
#Inject
private SharedGlobalConf globalConf;#Inject
private BusinessCase bc;public String doSomething(String argument) {
logger.debug(" >>doSomething on {}", argument);
// do something using bc
Object importantBusinessDecision = bc.checks(argument);
logger.debug(" >>importantBusinessDecision :: {}", importantBusinessDecision);
if (globalConf.isParamFlagActive("StackOverflow_Required", "1")) {
logger.debug(" >>StackOverflow_Required :: TRUE");
// Do it !
return "Done_SO";
} else {
logger.debug(" >>StackOverflow_Required :: FALSE -> another");
// Do it another way
String resultStatus = importantBusinessDecision +"-"+ StaticHelper.anotherWay(importantBusinessDecision);
logger.debug(" >> resultStatus " + resultStatus);
return "Done_another_way " + resultStatus;
}
}
public void err() {
xx();
}
private void xx() {
throw new UnsupportedOperationException(" WTF !!!");
}
}
To get it's job done , we need a hand from our old companion StaticHelper :
class StaticHelper {
public static String anotherWay(Object importantBusinessDecision) {// System.out.println("zz #anotherWay on "+importantBusinessDecision);
SharedGlobalConf gloablConf = (new SharedGlobalConfFactory()).getShared();
String avar = gloablConf.getParamValue("deeperParam", "deeperValue");
//compute the importantBusinessDecision based on avar
return avar;
}
}
Usage of this =
#Named public class Usage {
static final Logger logger = LoggerFactory.getLogger(Usage.class);
#Inject
private SharedGlobalConf globalConf;
#Inject
private BusinessCase bc;
public String doSomething(String argument) {
logger.debug(" >>doSomething on {}", argument);
// do something using bc
Object importantBusinessDecision = bc.checks(argument);
logger.debug(" >>importantBusinessDecision :: {}", importantBusinessDecision);
if (globalConf.isParamFlagActive("StackOverflow_Required", "1")) {
logger.debug(" >>StackOverflow_Required :: TRUE");
// Do it !
return "Done_SO";
} else {
logger.debug(" >>StackOverflow_Required :: FALSE -> another");
// Do it another way
String resultStatus = importantBusinessDecision +"-"+ StaticHelper.anotherWay(importantBusinessDecision);
logger.debug(" >> resultStatus " + resultStatus);
return "Done_another_way " + resultStatus;
}
}
public void err() {
xx();
}
private void xx() {
throw new UnsupportedOperationException(" WTF !!!");
}}
As you see the old shared key/value holder is still used every where but this time, we can test
public class TestingAgainstOldBadStaticSingleton {
private final Boolean boolFlagParam;
private final String deepParam;
private final String decisionParam;
private final String argument;
private final String expected;
#Factory(dataProvider = "tdpOne")
public TestingAgainstOldBadStaticSingleton(String argument, Boolean boolFlagParam, String deepParam, String decisionParam, String expected) {
this.argument = argument;
this.boolFlagParam = boolFlagParam;
this.deepParam = deepParam;
this.decisionParam = decisionParam;
this.expected = expected;
}
#Mock
SharedGlobalConf gloablConf = (new SharedGlobalConfFactory()).getShared();
#Mock
BusinessCase bc = (new BusinessCase());
#InjectMocks
Usage cut = new Usage();
#Test
public void testDoSomething() {
String result = cut.doSomething(argument);
assertEquals(result, this.expected);
}
#BeforeMethod
public void setUpMethod() throws Exception {
MockitoAnnotations.initMocks(this);
Mockito.when(gloablConf.isParamFlagActive("StackOverflow_Required", "1")).thenReturn(this.boolFlagParam);
Mockito.when(gloablConf.getParamValue("deeperParam", "deeperValue")).thenReturn(this.deepParam);
SharedGlobalConfFactory.setGloablConf(gloablConf);
Mockito.when(bc.checks(ArgumentMatchers.anyString())).thenReturn(this.decisionParam);
}
#DataProvider(name = "tdpOne")
public static Object[][] testDatasProvider() {
return new Object[][]{
{"**AF-argument1**", false, "AF", "DEC1", "Done_another_way DEC1-AF"},
{"**AT-argument2**", true, "AT", "DEC2", "Done_SO"},
{"**BF-Argument3**", false, "BF", "DEC3", "Done_another_way DEC3-BF"},
{"**BT-Argument4**", true, "BT", "DEC4", "Done_SO"}};
}
The test is with TestNG and Mockito : it shows how we don't need to do the complex stuff (reading the sql table, the xml files etc..) but simply mock different set of values targeting just our sole business case. (if a nice fellow would accept to translate in other frameworks for those interested...)
As for the initial request was about the design allowing to reasonably refactor a -huge- existing code-base away from the 'static singleton anti-pattern' , while introducing tests and mocks I assume this a quite valid answer.
Will like to hear about your opinion and BETTER alternatives

JUnit on failure callback/method

Is there any possibility to trigger a method whenever a testcase or assertion fails, in order to do some things when a testcase fails (e.g. Screenshot while UI-Testing, writing an error log, and so on...).
Maybe there is something like an annotation, I did not yet notice.
Thanks in advance!
You can use the TestWatcher rule and implement your own failed method to take a screenshot or whatever you need to do upon test failure. Slightly modified example from the official documentation:
public static class WatchmanTest {
private static String watchedLog;
#Rule
public TestRule watchman = new TestWatcher() {
#Override
protected void failed(Throwable e, Description description) {
watchedLog += d + "\n";
// take screenshot, etc.
}
};
#Test
public void fails() {
fail();
}
}