How to output information about failure in a forward compatible way (extension hooks)? - phpunit

The question I have here is about how to build in a forward compatible way the problem I am facing. Technically, I know how to do it in the current version (8.5, looking to move to 9 soon), but what is officially supported, seems to not satisfy the needs I have and my fear of course, is to be blocked in the future with my current approach.
I am currently using PHPUnit extension hooks. Pretty much following the same exact example we have in the documentation: https://phpunit.readthedocs.io/en/9.5/extending-phpunit.html
For the sake of simplicity, I'll paste a slightly modified version:
<?php declare(strict_types=1);
namespace Vendor;
use PHPUnit\Runner\AfterLastTestHook;
use PHPUnit\Runner\AfterTestFailureHook;
use PHPUnit\Runner\BeforeFirstTestHook;
class TestExtension implements BeforeFirstTestHook, AfterLastTestHook, AfterTestFailureHook
{
public function executeBeforeFirstTest(): void
{
echo 'Testing with configuration value';
}
public function executeAfterLastTest(): void
{
echo 'Second config value is OK!';
}
public function executeAfterTestFailure(string $test, string $message, float $time): void
{
echo "Failed test took $time seconds";
}
}
However, this triggers an awkward result:
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.
Runtime: PHP 8.0.11 with Xdebug 3.0.4
Configuration: tests/unit.xml
Testing with configuration value....Failed test took 0.0055649280548096 seconds.. 6 / 6 (100%)Second config value is OK!
Time: 2.21 seconds, Memory: 38.00 MB
OK (6 tests, 9 assertions)
What I would like to do though, is much closer to what is possible to do with an instance of PHPUnit\Util\Printer which allows to append messages or information about the test and is render as part of the result. Upon failure, I would like to be able to see something along the lines of:
PHPUnit 8.5.21 by Sebastian Bergmann and contributors.
Runtime: PHP 8.0.11 with Xdebug 3.0.4
Configuration: /Users/sebastian.machuca/projects/cloud-dev-vm/bcappvm/codebases/bigcommerce/tests/unit.xml
Testing with configuration value......
Time: 47.63 seconds, Memory: 132.50 MB
There were 2 errors:
1) Vendor\Tests\TestMyClass::testSomeMethod
Failed test took 0.25880694389343 seconds
The problem here is that PHPUnit\Framework\TestListener is considered to be #deprecated and PHPUnit\Util\Printer is considered to be #internal with a clear "This class is not covered by the backward compatibility promise for PHPUnit" message.
So, again, the question here is about how to build in a forward compatible way. How could achieve the equivalent behaviour that today is possible with Printer Listeners, but using non internal and non deprecated functionality?

I don't know if it is possible to attach additional (structured) information to an error and extend the printer to take it into consideration.
If you're concerned about the command-line runner, a globally possible option might be to add output at the very end when the test-runner exits - at least for standard streams (e.g. stdout, standard output).
When you create the timing / error information, you pass them to another object you instantiate (e.g. on a static property or a different global variable) once that collects the messages/data.
That object's destructor is being called when PHP exits. You can then output the collected data more structured and for better reading (on standard output).
This does not answer on how to do it with Phpunit specifically, just saying so this is clearly stated and you're very much concerned about that. This is standard PHP behaviour.
For your interoperability problem, I'd wrap the functionality apart from how its triggered so that its more modular for future changes.
Next to that I'd check the Phpunit version and present a warning or similar so that if the version changes you get the chance to adopt if new functionality is available. Additionally you can pin the development utilities version with the repository (e.g. commmit composer.lock). Then it works what works and perhaps in the future there will be the interface you're looking for.
Unless you have to rely on what is available even if there isn't a backwards compatible promise for it.
And sure, there is always another option: Take part in the development in the Phpunit project and bring these things forward. Make it your own.

Related

Multiple SpringBootTests using EmbeddedKafka fails with "only one 'RetryTopicConfigurationSupport'"

We have an application that makes use of Spring Kafka's non blocking retries via the RetryableTopic annotation.
We are in the middle of upgrading spring-kafka from 2.8.4 to 2.9.0.
We have several SpringBootTests that makes use of EmbeddedKafka. Each of these tests are marked with DirtyContext and AutoConfigureMockMvc
After upgrading, the first test would run fine, but the later test would fail to start the application with
Constructor threw exception; nested exception is java.lang.IllegalStateException: Only one 'RetryTopicConfigurationSupport' is allowed
I understand that the RetryTopicConfigurationSupport tries to ensures only one instance of itself is ever instantiated. So in the use case of running multiple unit tests, which includes multiple different SpringBootTests, how do we avoid hitting this problem?
I have tried marking the context dirty, but of course that didn't solve the problem as RetryTopicConfigurationSupport is using a static variable to track whether it has been instantiated before or not.
I have tried NOT marking the ContextDirty, but the later tests would fail to start the application because the Port is already in use.
Appreciate any advise!
Looks like this problem has been addressed in spring-kafka 3.0 and backported to 2.9.3
https://github.com/spring-projects/spring-kafka/issues/2477

JVMVRFY012: VerifyError for JSTL Tags - Foreach & Set tags

IBM WAS: 8.5.5 Version
On JSP pages have & tags, I receive below error
Error 500: java.lang.Exception: java.lang.VerifyError: JVMVRFY012
stack shape inconsistent; class=com/ibm/_jsp/_desktop,
method=_jspx_meth_c_set_0(Ljavax/servlet/jsp/PageContext;)Z, pc=73;
Type Mismatch, argument 1 in signature
org/apache/jasper/el/ELContextWrapper.:(Ljavax/el/ELContext;Ljavax/el/FunctionMapper;)V
does not match Exception Details:
Location:
com/ibm/_jsp/_desktop._jspx_meth_c_set_0(Ljavax/servlet/jsp/PageContext;)Z
#73: JBinvokespecial Reason: Type
'org/apache/jasper/runtime/ProtectedFunctionMapper' (current frame,
stack[8]) is not assignable to 'javax/el/FunctionMapper'
Current Frame: bci: #73 flags: { } locals: { 'com/ibm/_jsp/_desktop',
'javax/servlet/jsp/PageContext', 'javax/servlet/jsp/JspWriter',
'org/apache/taglibs/standard/tag/rt/core/SetTag' } stack: {
'org/apache/taglibs/standard/tag/rt/core/SetTag', 'uninitialized',
'uninitialized', 'java/lang/String', 'javax/el/ExpressionFactory',
'uninitialized', 'uninitialized', 'javax/el/ELContext',
'org/apache/jasper/runtime/ProtectedFunctionMapper' } Stackmap Table:
append_frame(#128,Object[#127],Object[#231],integer)
On reading https://www.ibm.com/support/pages/ibm-java-linux-howto-resolving-javalangverifyerror-jvmvrfy012-stack-shape-inconsistent, understand that the reason could be
code is compiled against a different library than the one being used at runtime
a class tries to extend a class declared as final
a method tries to override a super method that is declared as final
a wrong argument is passed to a method
It does look to be #4 - but the same code works in Tomcat and does not work in IBM WAS and am unsure why WAS is passing an incorrect argument. Any suggestions on how we can resolve this issue?
You may want to explore Servlet/JSP version compatibility.
WAS: 8.5.5 reference
Servlet 3.0
JSP 2.2
If you happen to be using Spring Boot:
2.2.x and 2.1.x require Servlet 3.1+
2.0.x supports Servlet 3.0
This looks like a cross-linkage between the javax.el library in your application and the version packaged in the server. When using PARENT_LAST, any Java EE APIs you include in the application are loaded twice, once from the server and once from the application (because the application loader doesn't delegate that load to its parents). Depending on the other classes/packages in play, you can have an instance in which a class ends up directly referencing one instance of the class and indirectly (through some other reference) referencing the other instance, and the JVM will throw a VerifyError in that scenario.
The easiest answer: If you are not 200% sure you NEED the version of the javax.el classes in the app, remove them, and this specific error should be impossible. If you are definitely dependent on that version, then it becomes trickier, as it might require adding additional stuff to the application (to avoid picking stuff up from the server), or it may be that this specific library simply can't be safely overridden with PARENT_LAST loading. That analysis would require a deeper look at the error stack and possibly a dive into detail trace of the class loading.

Why am I seeing a large spike in Data ingestion from performance counter data?

From looking at my Cost Management reports for Application Insights, I've noticed a large spike in data ingestion related to Performance Counters.
Link to larger image
However, I'm not seeing any significant correlation in the number of requests spiking for the same period.
Link to larger image
What can I do to understand the root cause of this issue?
Additional Information
After some debugging, I was able to get to the bottom of this.
The usage spiked on Sep 7 and Sep 8 and then tapered off on the 9th and 10th.
The change that I made on the 6th Sept was to upgrade Microsoft.ApplicationInsights.AspNetCore from version 2.6.1 to version 2.7.1. Version 2.7.1 has ILogger integration baked in.
So, what I believe happened is that, after deploying the upgraded version of Microsoft.ApplicationInsights.AspNetCore, I may have had the Logging verbosity turned up too high for the performance counter telemetry data and subsequently changed it a couple of days later when I noticed it.
I hope this helps someone else who may run into this issue!
There is now a cleaner way to achieve the disabling of the PerformanceCounterModule (and other modules which cause excessive/unneeded logging);
services.AddApplicationInsightsTelemetry(options =>
{
options.EnablePerformanceCounterCollectionModule = false;
options.InstrumentationKey = configuration["ApplicationInsights:InstrumentationKey"];
});
Application Insights 2.7.1 has enabled ILogger captured by default, but it only captures Warning or above log messages. So unless you application is generating a lot of Warning or above level Ilogger logs, this should not result in a big spike in usage.
This behavior can be changed to filter logs further if too much logs are reported.
https://learn.microsoft.com/en-us/azure/azure-monitor/app/ilogger#control-logging-level
From the 1st screenshot you shared, it looks like performance counter is the only type which spiked - ilogger integration cannot explain this spike, as it only reports logs.
More logical explanation is the PerformanceCounter module itself which was NOT supported in versions earlier than 2.7.1. You can remove performance counter collection with the following snipped in ConfigureServices() method in startup.cs
using Microsoft.ApplicationInsights.DependencyCollector;
using Microsoft.ApplicationInsights.Extensibility.PerfCounterCollector;
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry();
// The following removes PerformanceCollectorModule to disable perf-counter collection.
var performanceCounterService = services.FirstOrDefault<ServiceDescriptor>(t => t.ImplementationType == typeof(PerformanceCollectorModule));
if (performanceCounterService != null)
{
services.Remove(performanceCounterService);
}
}

Why Symfony3 so slow?

I installed Symfony3 framework-standard-edition. I'm trying to open the home page(app.php prod) and it is loaded 300-400ms.
This is my profiler information:
also I use php7.
Why it is so long?
You can try to optimize Zend OPCache.
Here are some recommended settings
opcache.revalidate_freq
Basically put, how often (in seconds) should the code cache expire and check if your code has changed. 0 means it checks your PHP code every single request (which adds lots of stat syscalls). Set it to 0 in your development environment. Production doesn't matter because of the next setting.
opcache.validate_timestamps
When this is enabled, PHP will check the file timestamp per your opcache.revalidate_freq value.
When it's disabled, opcache.revaliate_freq is ignored and PHP files are NEVER checked for updated code. So, if you modify your code, the changes won't actually run until you restart or reload PHP (you force a reload with kill -SIGUSR2).
Yes, this is a pain in the ass, but you should use it. Why? While you're updating or deploying code, new code files can get mixed with old ones— the results are unknown. It's unsafe as hell
opcache.max_accelerated_files
Controls how many PHP files, at most, can be held in memory at once. It's important that your project has LESS FILES than whatever you set this at. For a codebase at ~6000 files, I use the prime number 8000 for maxacceleratedfiles.
You can run find . -type f -print | grep php | wc -l to quickly calculate the number of files in your codebase.
opcache.memory_consumption
The default is 64MB. You can use the function opcachegetstatus() to tell how much memory opcache is consuming and if you need to increase the amount.
opcache.interned_strings_buffer
A pretty neat setting with like 0 documentation. PHP uses a technique called string interning to improve performance— so, for example, if you have the string "foobar" 1000 times in your code, internally PHP will store 1 immutable variable for this string and just use a pointer to it for the other 999 times you use it. Cool.
This setting takes it to the next level— instead of having a pool of these immutable string for each SINGLE php-fpm process, this setting shares it across ALL of your php-fpm processes. It saves memory and improves performance, especially in big applications.
The value is set in megabytes, so set it to "16" for 16MB. The default is low, 4MB.
opcache.fast_shutdown
Another interesting setting with no useful documentation. "Allows for faster shutdown".
Oh okay. Like that helps me. What this actually does is provide a faster mechanism for calling the destructors in your code at the end of a single request to speed up the response and recycle php workers so they're ready for the next incoming request faster.
Set it to 1 and turn it on.
opcache=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=8000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.fast_shutdown=1
I hope it will help improve your performances
[EDIT]
You might also want to look at this answer:
Are Doctrine relations affecting application performance?
TheMrbikus, try some optimization with the following elements:
Use APC
Use Bootstrap files
Reference: http://symfony.com/doc/current/performance.html
Use the OPCache PHP7
Use Apache PHP-FPM.
E-mail sending process, and may slow down during the form rendering operations. Create a blank test Controller.

RocksDB cryptic error message

Does anyone understand what this RocksDB error refers to ?
/column_family.cc:275: rocksdb::ColumnFamilyData::~ColumnFamilyData():
Assertion `refs_ == 0' failed. Aborted (core dumped)
This is an assertion failure raised by RocksDB, and it intentionally terminates the execution of the program.
In general, assertions are used by programmers to ensure certain invariants in the program. Assertions have some runtime overhead, and therefore can be completely disabled. Often they are compiled into development or debug builds, but are omitted for production builds.
When an assertion fails, the program execution is intentionally aborted immediately by calling std::abort. This may lead to your OS writing a core dump (as it obviously did as the above message reveals), but if and where core dumps are written depends on the OS configuration.
In case of this specific assertion, the destructor of rocksdb::ColumnFamilyData raised the assertion because it requires its refs_ member to have a value of 0. refs_ is a reference counter and it makes sense to assert that no references are actually held when the object's destructor is called.
From just looking at the destructor code, it is unclear whether this is a bug in the RocksDB library itself, or an error caused by using it the wrong way, e.g. destroying column family objects when they are still in use by other objects.
For reference, here's the code part that raised the assertion (currently on line 365 in file rocksdb/db/column_family.cc):
ColumnFamilyData::~ColumnFamilyData() {
assert(refs_.load(std::memory_order_relaxed) == 0);
If the error persists, it may be useful if you provide the code that uses RocksDB here. Otherwise it may be impossible to find the error source.
The core dump may also provide useful information, because it contains the stack trace of the code that actually invoked the object's destructor.
I noticed that all column_family.cc errors (core_dumped, memory_order_relaxed and etc) occur after incorrect rocksdb installation. In my vagrant script i found true way.
instead of use
https://github.com/facebook/rocksdb/blob/master/INSTALL.md
i create script
cd /opt
git clone https://github.com/facebook/rocksdb.git
cd rocksdb
git checkout tags/v4.1
PORTABLE=1 make shared_lib
export LD_LIBRARY_PATH=/opt/rocksdb
LD_LIBRARY_PATH add better to your environment path(.bash_rc or /etc/environment)
Assertion refs_ == 0 fails on ~ColumnFamilyData() means the reference count of a column family is not zero when the column family is deleted. Most likely you have some un-deleted column family handles before closing the DB. Note that all column family handles must be deleted before closing the DB. Otherwise the assertion will fail.
// Before delete DB, you have to close All column families by calling
// DestroyColumnFamilyHandle() with all the handles.
static Status Open(const DBOptions& db_options, const std::string& name,
const std::vector<ColumnFamilyDescriptor>& column_families,
std::vector<ColumnFamilyHandle*>* handles, DB** dbptr);
To fix such assertion failure, making sure you delete all column family handles before closing the DB.

Resources