PHPUnit and Laravel Config Caching

This week at work, I ran into a fun issue with a colleague while running some unit tests that I wanted to document here.

I was writing some new unit tests for a legacy codebase that’s been around a long time. For the sake of portability, I decided to use an in-memory SQLite database. After writing the tests and finishing the other work for the ticket, I opened a PR and went about my other tasks.

My colleague pulled down my ticket for testing and ran the tests. What should have been a very simple test was failing! What was weirder, is that the failing action was happening during one of the database migrations. The error isn’t important but for the sake of completeness, but it was a foreign key constraint error on the database.

After trying to debug stuff with them, we also noticed that his local database had been entirely nuked. Considering the test was running with the RefreshDatabase trait, I was starting to get an idea of what was going wrong.

What happened?

The empty database was the big clue that led me down the rabbit hole. I knew that running the database migrations is a slightly different process for in-memory vs. a real database, so I dug into that trait first.

This method in the call stack stuck out to me:

protected function usingInMemoryDatabase()
{
	return config('database.connections')[
		config('database.default')
	]['database'] == ':memory:';
}

If the config value is for the default database is :memory: then this would return true. Since PHPUnit overrides your .env when the tests are ran, this should be the correct value. Dumping it however, we get a different result.

For the config() function to be returning a different result than what is in a configuration file already, that must mean a config cache file exists. You can read more about how Laravel potentially includes that file here.

In our case, there was a config cache present, so when Laravel was booting to run the tests, that config was being used instead of PHPUnit’s environment variables.

To tie it back to the error we were seeing, since the local MySQL database was being used instead of the in-memory database, a migration with some outdated seeding code was throwing the foreign key constraint error. This is also a good reminder that MySQL and SQLite are not the same! If you are expecting foreign key constraint failures to be enforced in your tests, use the appropriate database for both your test suite, and when running your application.

The Solution

If this case, I decided it was best to try and fix the problem for the user running the tests. I modified the base TestCase.php as follows.

<?php

namespace Tests;

use Illuminate\Support\Facades\Hash;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        $app = require __DIR__ . '/../bootstrap/app.php';

        $app->make(Kernel::class)->bootstrap();

        Hash::driver('bcrypt')->setRounds(4);

        $this->clearCache($app); // Added this line.

        return $app;
    }

    protected function clearCache(Application $app)
    {
        // We don't have a cached config, so continue running the test suite.
        if (!$app->configurationIsCached()) {
            return;
        }

        $commands = ['clear-compiled', 'cache:clear', 'view:clear', 'config:clear', 'route:clear'];
        foreach ($commands as $command) {
            \Illuminate\Support\Facades\Artisan::call($command);
        }
        // Since the config is already loaded in memory at this point, 
        // we need to bail so refresh migrations are not ran on our
        // local database.
        throw new \Exception('Your configuration values were cached and have now been cleared. Please rerun the test suite.');
    }
}

If no config cache file is found, then we’re golden! Continue running the test suite. If we do find a config file, we run a few Artisan commands to clear all of those files and then throw an Exception. The exception is necessary since the config is already loaded into memory at this point. If the tests continued to run, all of the requested config values would be the old ones. While it may be possible to reset the config and continue running the tests, the utility of that is miniscule. Instead, we inform the user of the action that was taken and ask them to run the test suite again.

In an ideal world, you would never have a configuration cached locally as it’s main purpose is to speed up expensive disk operations in production, but alas, we don’t live in an ideal world! 😅


I want to give a shoutout to Joel Clermont for helping me debug what was going on and being a great rubber 🦆!

Running Multiple CLI Commands in One Terminal for Laravel Development

While working on Let Them Eat Cake 🍰 , I noticed when I was end-to-end testing the app locally, I need a few different things running at once:

  • Laravel Queue Worker – running queued jobs
  • Expose – Proxy for allowing external webhooks needed for my app
  • Stripe CLI – Passing Stripe webhooks to my app without using a proxy
  • Laravel Mix – Bundling static assets

Running each of these commands separately isn’t that big of a deal, but it can be a hassle to remember to start them all. This was very apparent yesterday as my computer decided it wanted to reboot every time it went to sleep! A short trip around town running errands with my wife and my computer restarted 3 times in a couple of hours; frustrating!

Today I decided to look into some potential solutions. I had a few basic requirements while I was looking around.

  1. It needs to be easy to start and modify for each new project – this also implies some flexibility. No sudo password required nonsense.
  2. I can stop all running processes with SIGINT (CTRL+C)
  3. All process output is still visible so I can see compile errors or bad requests.
  4. Process output is in one terminal window/tab (optional – but I wanted it!)

A little searching and some testing later and I think I’ve come to a nice solution that gives me plenty of control and flexibility.

One of the first tools I discovered was moreutils, a package you can install with brew that essentially adds a handful of helpful CLI utilities. The name is play on coreutils, a set of packages included in most Linux distros. Specifically, there is a package called parallels that seemed to be just what I was looking for. It has lots of extra features and can start lots of parallel processes and close them all at once. The reason I ultimately chose not to go this route, was in case I work on any of my projects with other developers. Given the simplicity of my use case compared to the feature set of the package, it was honestly overkill. This also means my project is that much more portable between machines and developers. I keep my own dotfiles, but if I can avoid complexity, I like to try that route first. 🙂

The Solution

Ultimately, I settled on a little shell script courtesy of this Ask Ubuntu thread. Here is my adaptation:

#!/bin/bash
sh ./startexpose &
P1=$!
php artisan queue:listen &
P2=$!
stripe listen --forward-to eat-cake.test/stripe/webhook &
P3=$!
wait $P1 $P2 $P3

A quick rundown. The first process is essentially another wrapper with some Expose configuration details. The output from this is a big tail-ing table of incoming requests. The second is my queue worker. I opt for queue:listen here so the worker will automatically restart itself when any code in my application changes. Output from this command is a line for every queued job that is processed. Third is the Stripe CLI, which needs to be configured beforehand, but is a once every 90 day thing. Seeing as it has access to my payment data, I’m okay with the hassle tradeoff.

I’m still debating on whether or not to include my Laravel Mix watch command in this, and I might add a runtime flag for it, but without trying it for any reasonable length of time yet, I’m guessing I’ll need to start/stop the watcher to do production compiles more often than anything else. The other commands can run mostly unmonitored unless I need to check something, but I tend to get a lot more feedback when I inevitably screw up the closing brackets in a JS file. 😬

Hope this helps you out! Feel free to ask any questions here or send me a tweet @DaronSpence. ✌️

Back on the horse, maybe? January 2021

Fuck, 2020 felt like a dumpster fire to a lot of people in the world, and that means me too!

Note: please excuse me if it feels like I’m rambling. It’s late and I’m typing this on a keyboard I’m not really used to so it takes longer to get my thoughts out with extra editing.

I’m just so disappointed in myself. I know it’s late as of the time of this writing, but I think that might just point towards something I feel is true. I know what I need to do, but overcoming that split second instinct to run towards the comfortable is obviously hard to ignore.

Just now, I thought it might be a good idea to go to Whataburger just to get some unsweet tea, since they’re the only place open late with anything close to fresh tea. But I know I’ll be tempted to order something else in that drive thru line. It’s too easy and I’m looking for any excuse.

In 2019, my wife bought me a coat on a random trip to the mall. It’s a very nice peacoat that cost her a lot of money, but she knew how much I missed my old one and she figured I deserved it for whatever reason. I really like it and I got a lot of compliments on how good I looked when I wore it out and about, especially with people I had not seen in a year or two.

It finally got cold enough this past month to warrant wearing a coat outside more. I got up a 6am to get ready to volunteer at church, when I realized it would be an excellent day to wear the pea coat. I was devastated when it didn’t fit. I almost wore it to prove to myself it was possible. I could have stretched it out and done up the buttons, but I knew deep down in that instant, that I was lying to myself and it wasn’t worth it. I reached over a few hangers and grabbed the biggest coat I owned, which is also much to insulated for indoor wearing, and zipped it up. I distinctly remember my hand passing over the 4 other jackets in my closet and settling on this one. It’s much to big, but it’s comfortable and it hides my imperfections. It hides the overeating I’ve done for months.

But it can’t really hide me from myself…

So tonight, I’m writing something. Maybe it’s more empty promises. I’m not sure. I’ve saved a few of my favorite salad restaurants in a Google map, hopeful that I’ll turn to them in my next moment of weakness, but I’m not sure I’ve convinced myself yet.

I think I’ve barely convinced myself this blog is worth posting.

Meh

I think I’m burnt out. Wow. Super surprising. The real question, is what the fuck am I burnt out on?

In the past few weeks, I’ve tried to look at every area of my life and take a break from what I can. My coworkers graciously picked up my slack at work for a few days, though I know my productivity since coming back has suffered. It’s so hard to focus. I can usually wake up after a good night’s sleep, 8 hours or more, and then by the time I walk to my office, the dread has set in.

Nature helps somewhat. I’ll make a move outdoors and I can feel somewhat rejuvenated, but the feeling is fleeting. I’ve tried visiting friends and family and again, I get that same temporary satisfaction of human contact, but then I have to retreat home to my cutout in the uptown skyline.

Pair that with the complete and total dietary failure and it just feels worse. I can’t help but dive into this self sabotage headfirst; concern for my future self thrown to the wind in search of momentary satisfaction.

And then the pity party afterwards. The catharsis of complaining to myself and to others. Synapses of satisfaction firing for a brief moment before they power down for another solitary serenade. It feels freeing to bitch and complain to the 3 people who I know will read this; some possessing real power to drastically alter my life, for better and worse.

I don’t know what to do. I probably definitely need a therapist, but the looming of Covid-Part-2 Electric Boogaloo has kept me away from professionals and amateurs alike. Instead I have you.

Thanks for listening, but I don’t blame you for leaving my sorry ass alone either.

Intermittent Fasting Update – August 2020

My weigh in this morning was 241.4 but the average for the month is a little higher. As you can see from the below chart, this past 12 months has been ups and downs. You can see the gradual decline from my past posts discussing my progress before falling off the wagon.

This month has been interesting for sure. At the start of the month, I took a road trip with my 16 year old brother from Texas up to the Great Lakes. During our trip I stuck to my eating windows but went absolutely hog wild with what we ate. We were having a good time trying all of the local food and enjoying each other’s company.

Side note: Wisconsin cheese curds are fucking amazing…

Me

I thought I’d mention something else here as well that my wife keeps bringing up.

My current ritual is to weigh in on Friday mornings right after I wake up and use the bathroom. Depending on what I’m doing in regards to work, this might be 9-10am even if I wake up at 8am. During that time from rise to first bathroom break, I do not drink any water. I also try to not go ham with the water on Thursday night. My thought is that if I wake up and chug a 32oz cup of water, that I’ve essentially “gained” 2 pounds. In terms of keeping an accurate track of my weight loss numbers, this seems like an okay practice.

My wife thinks is unhealthy to think of water in such a negative way. I’m not sure if we’re having some sort of miscommunication as I’ve tried explaining it different way and she says she understands and still thinks it’s problematic. Tell me your thoughts. I’m interested to hear them!

My weekly routine

I’ve had various people ask about my routine so I thought I’d update the internet here with what I’m doing and what’s working currently. If I change something in between these posts I’ll try to remember to make a not of it in future posts.

Sunday

At the start of the week, I’m usually volunteering with my local church. Eating is a social activity we usually partake in with friends so I keep Sunday’s a bit lax. Obviously with Covid-19, we’re not going to church or seeing friends, but I still eat Dinner and sometimes a light lunch. I aim to stop all food intake by 10 PM.

Monday

This is a fasting day. No food, only water and my meds (asthma pills and some supplements). Ask your doctor if your medicine needs to be taken with food. Mine do not.

Tuesday

Around 5-6 PM (or later) I’ll eat dinner with the goal of finishing by 10 PM. My current diet consists of two meals from https://www.cleaneatzkitchen.com/ and then a bag of popcorn if I’m still hungry. I’ve really been trying to eat my food slower and allow the hormones to work their magic to make me feel full. The problem I still have to a degree is my ability to inhale food at such a rate that my body can’t even react to being full.

Most of the time I’ll start my fasting timer right after I finish eating, irregardless of the time. Bed time is around midnight.

Wednesday

Basically a repeat of Tuesday. I may eat an extra serving of some frozen vegetables in preparation for Thursday, but it depends.

Thursday

Another full fasting day! No food, just water and my meds. Like I mentioned before, I try to not go crazy with the liquids after 10pm or so because of weigh in on Friday morning. Basically I just want to ensure that I’ll have to pee soon after waking up and that my body is actually getting rid of the extra water I don’t need.

Friday

Weigh in day! I have a lot of work calls on Friday’s so it’s a busy morning. If I have to use the bathroom, I’ll do that and then immediately weigh myself. Tracking is always done in my birthday suit for maximum results and easier reproduction.

After that, it’s water and meds until 5-6 PM for dinner. Same meals as the previous week, though I’ve been known to grab some Wingstop on the weekend. Aim to finish eating by 10 PM.

Saturday

A repeat of my other eating days basically. If we were having social events, I’m sometimes less picky about eating times, but I still aim for 16 hours fasted as least. Rarely do we have events before noon so in those cases I would politely decline anything until later in the day. If we do have breakfast plans with someone, I’d probably eat, but opt for as low carb as possible. Eggs, bacon, vegetables. An omelette does sound pretty good right now. 🙂

Re: Food choices

I’ve historically made pretty terrible food choices. Weighing 310 pounds is evidence enough of that. Self control when it comes to food has been very difficult for me, and frankly a lot of other things as well.

I’m very spontaneous and when I want something I tend to get it pretty quickly afterwards. New toys, going somewhere, eating something. I’ve really had to work at controlling these urges and work on planning ahead of time.

As part of embracing more planning and self control, I opted to purchase pre-cooked meals in bulk. I’ve essentially removed any ability to cheat by limiting myself to these pre-purchased meals and a handful of pre-approved snacks!

So far, I have to admit that it seems to be working. I’m not tracking it explicitly, but my daily calorie intake on feasting days is somewhere around 1200-1600 calories. For a dude who still weighs 240 pounds, this is a significant deficit from what my body needs to function, thereby forcing it to burn more fat.

During my first attempt at this last year, I would say I was normally eating more than 2,000 calories a day making my own food. The portion sizes were larger mainly, and I wasn’t afraid to load up on low carb, yet calorie rich, liquids like ranch or butter.

I wonder when I’ll get to eat “normal” food again but for now this is working. Especially with the world in a state of quasi-lockdown, it is nice to not have to worry about making grocery store runs. My wife buys food for herself on her way to / from work.

Conclusion

If you have questions, feel free to leave a comment or reach out on Twitter @daronspence . I’m sometimes slow to reply here on the site, but if more people comment it might motivate me 🙃

Also feel free to join my fasting circle on the app I use. iOS only though! Sorry! https://lifefastingtracker.app.link/z3D7qHg2W8

Ecolink Door Sensor Z-Wave Shenanigans

Problem: Door Sensor won’t connect to Z-Wave Network

Model: DWZWAVE2.5-ECO

At our office, we have a small Z-Wave network setup running a Raspberry Pi and Home Assistant, specifically Hassbian because at the time of our purchase the newest Pi 3B+ was not supported for Hass.io.

On the Z-Wave network we have a single door sensor on the front door that theoretically notifies us when someone enters the office. Long story short, we had it setup remotely and after 3 days of shipping via USPS, it didn’t work at the physical office. Bummer!

Now, a few months later, I’m here to troubleshoot in person while in town helping out with other things. I set the thing up in the first place so it shouldn’t be too hard to fix right? Wrong again!

The EcoLink Door Sensor seems to be a decent product. It has pretty good range; ours is located about 30 feet away from the controller. The controller is inside a giant metal server rack and behind a solid wall. Not the best conditions for sure! The manual however is complete and total garbage. Below you will find the steps to completely remove the device and re-add it to your network.

Reset the Device

To properly “reset” the device you must first determine if it’s currently connected. In my case, the sensor actually thought it was still connected to something. Placing a magnet against it would cause the green LED to give one long flash. In this case here’s how you fix it.

  1. Check that your battery is not dead. If the sensor has been unconnected from a Z-Wave network for a while, it’s likely tried to pair itself continuously and drained the battery.
  2. Navigate to your Z-Wave controller software and initiate a node removal. In Home Assistant, there is a button called “Remove Node”. Press it.
  3. Remove the cover and battery from the device for 5-8 seconds. Do not wait too long though or the node removal will time out. Within 20 seconds of initiating the node removal should be fine.
  4. Plug the battery back in with the cover removed. The LED should flash continuously if it was successfully removed. (Note: these steps will remove the device from any Z-Wave network it was previously connected to)
  5. Click the “Add Node” button on your Z-Wave control software while the LED is blinking.
  6. Remove the battery for 5-8 seconds and then replace the battery. The LED blinking pattern should change and stop soon after pairing.

At this point, you should see confirmation of the added node in your controller software. To complete the process, run a network heal to make sure everything is communicating efficiently.

Now you should be able to monitor the state of your sensor in Home Assistant.

If you have any questions, leave a comment or shoot me a tweet @DaronSpence