I am developing an elixir application and deploying that application via Elixir Releases and Docker. All of that is going fine and I can use environment variables for runtime configuration.
For local development I wanted to use dotenv and the way I'd like to set up my project is that I want to read configuration from my config/*.exs files.
Now I found out that Mix is not available in Elixir releases so the proposed solution of dotenv for configuring .exs files via environment variables will fail on production start.
defmodule App.Application do
use Application
def start(_type, _args) do
unless Mix.env == :prod do
Dotenv.load
Mix.Task.run("loadconfig")
end
# ... the rest of your application startup
end
end
Result
(UndefinedFunctionError) function Mix.env/0 is undefined (module Mix is not available)
I was wondering if I can just on compile time determine whether I'm in production mode and just leave out the dotenv load section:
I came up with this:
defmodule Roundhay.Application do
def start(_type, _args) do
quote do
unquote(unless Mix.env() == :prod, do: load_env())
end
# load rest of application
end
defp load_env do
Dotenv.load()
Mix.Task.run("loadconfig")
end
end
But that just yields the same problem.
Is there any way I can just omit the whole block existing when compiling in production mode?
Did you read the top section of the docs you linked to?
WARNING: Not compatible with Elixir releases
It seems like what you're trying to do is not supported by that library, because it fundamentally relies on Mix being available at runtime.
There is also a comment on a closed issue recommending against trying to use macros, as you are doing:
It is entirely possible that you could inject your secrets into the
compiled result through macro use. It would totally possible without
realizing you had done it.
Additionally, many apps do not build in the same environment they
deploy, and this has caused issues repeatedly for users of this
library, who inadvertently inject values into the compiled result that
are blank because a macro inserted them at compile time but they are
only available at run time in the production environment
Another way you could do it is to follow standard Elixir patterns for config, and use a tool like tool like direnv to set your environment for running the release locally.
I'm using C++98, and besides the standard library, I only have access to an old version of Boost (which thankfully has Boost Test). The documentation though is daunting, long, and I just don't know where to begin.
I have some experience doing unit testing in Java (and I'm looking for unit testing in C++), and I've seen test packages that contain the unit test code separate from the src package, and I also saw Where do you put your unit test? as well as Unit Testing with Boost and Eclipse. Their suggestions vary, and present reasoning for different packaging structures for separating test code from production code, or having them together.
Before I even started looking into Boost Test, I created this structure within Eclipse (perhaps erroneously):
-- ProjectName
|-- Debug
|-- src
|-- test
and I wrote another main method to run test functions. Eclipse didn't like that, because I had two main methods in the same project. I fumbled around through Project Properties and didn't find anything useful for separating my production code from test code when building (linking, really). My temporary fix was to just use g++ in the terminal and ad hoc compile just my "test" code.
I found something suggesting on Boost::Test -- generation of Main()? that Boost actually generated its own main method, so this is currently my plan of attack for unit testing, especially for having a library of testing tools already available.
What is the conventional way of organizing unit tests for C++?
How do I get started with Boost Test? (Boost is already installed)
Is there anything I need to change in Eclipse to be able to run my Boost unit tests separate from my production code within the IDE? (One of the nice things about IntelliJ, with Java, is how it'll automatically run any main method you like with a click) -- The goal here to be able to build and run my tests within Eclipse.
Should my tests be in a separate Eclipse project? (this was suggested in an answer to the second SO question I linked)
Edit: I found this article for an introduction to Boost Test, but it doesn't discuss how it can be handled within an IDE setting.
I figured out how to do this on my own, and I'll document my solution for others who are just starting with C++ as well and need to do testing of their code. There currently is no good introduction anywhere that I could find. Here are the resources that I used though (and found useful):
C++ Unit Testing With Boost Test which introduces Boost Test in a much better fashion than Boost's documentation.
Where do you put your unit test? which discusses the most conventional ways of doing tests with C++.
unit test in eclipse g++ which discusses Eclipse build configurations which allow testing
The C++ convention for testing is like that of other coding languages, just write your tests in a directory called test under the project. Using Boost Test requires that you link the unit test framework: -l boost_unit_test_framework which in Eclipse:
Right click on your project, go to Properties, C/C++ Build, Settings, Tool Settings, GCC C++ Linker, Libraries, and add the library name boost_unit_test_framework (add -mt to the name if you require multithreading; additionally, once the testing build configuration exists, you can go back and choose just that configuration to link the library -- it'll reduce the size of your executable for your other builds).
To be able to run the unit tests in Eclipse separate from your main method, we need to establish a new build configuration. That way, Eclipse knows to exclude your source file with a main method when you're executing your tests.
Click on Project, Build Configurations, Manage..., and select New... and call it Test (or something other than test). Choose your existing configuration so that we'll inherit properties from the production build.
Next, we need to differentiate the build configurations from one another so when we build them, they actually correspond to the production and test builds.
Right click on test, Resource Configurations, Exclude from Build..., and select the builds that represent your production build (i.e. Debug and or Release). Once done with that, right click on your source file with your main method, and exclude that from the Test build.
There's still some things we need to change. We don't have any test code yet, but we still can't run our test build, nor would our test build know about resources existing in src because Eclipse wouldn't automatically include those source files. They're practically invisible to your test code in test.
Right click on your project, go to Properties, C/C++ Build, Settings, Tool Settings, GCC C++ Compiler, Includes, and add the path /.../workspace/ProjectName.
Now to be able to run your test build in Eclipse, it needs to know what executable you're expecting the IDE to run.
Click on Run, Run Configurations..., and looking at your current run configuration, consolidate these settings by giving, for example, a debug build the name "Debug Build", the C/C++ Application "Debug/Artifact_Name", and the Build Configuration "Debug". Next, create a new run configuration, and call it something like "Test Build", set C/C++ Application to "Test/Artifact_Name", and ensure the build configuration is Test.
Now you'll be able to switch between running production code and test code by selecting either the "active" build configuration or running the correct run configuration.
Finally, here's an example of a unit test with Boost Test once all of this is set up:
//unit_tests.cpp
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE someModuleName
#include <boost/test/unit_test.hpp>
#include <src/some_object.h>
struct template_objects {
some_object x;
template_objects() {
BOOST_TEST_MESSAGE("Setting up testing objects");
}
~template_objects() {
BOOST_TEST_MESSAGE("Tearing down testing objects");
}
}
BOOST_FIXTURE_TEST_SUITE(testSuiteName, template_objects)
BOOST_AUTO_TEST_CASE(testCase1) {
x.update();
BOOST_CHECK(x.is_up_to_date());
}
BOOST_AUTO_TEST_CASE(testCase2) {
BOOST_CHECK(x.is_not_up_to_date());
}
BOOST_AUTO_TEST_SUITE_END()
This demonstrates some critical things about using Boost Test:
defining BOOST_TEST_DYN_LINK is recommended; you need to define a way of linking the testing framework before including any of Boost's libraries
you must name the "module" something, doesn't have to be the file name
to get automated setup up and teardown of objects before entering test cases, Boost Test has fixtures, which allow you to call an object's pre-existing state multiple times
the struct is what groups these fixtures, and it's implied that your object should have a well defined constructor and destructor for automatic scoping (if you didn't call new, you don't need delete in teardown)
test suites are just a way of logically grouping your test cases (I haven't tested it yet, but you can probably break up your suites into multiple files for better logical separation)
Additional tidbit: to make Boost Test more verbose, go to your run configuration for the test build, and add the argument --log_level=test_suite.
I want to support the usage of 'debugger' statements locally and on the development deployment but not when it gets to staging or production.
I'm using Ember-cli with environments and am not understanding how to define the jshint or eslint directives differently.
By design we can configure both linting libraries differently via their configuration files for app code & test code via .eslintrc or .jshintrc files which reside at the root folder and the tests folder. So even though we can have different rules for these categories of code, we can't differentiate them per environment.
The reason it might not make sense to do so is because the assets that get generated after the build process that gets deployed doesn't necessarily need to conform to these rules since transpilers like babel (may) optimize generated code for us.
While I don't understand the need to keep debugger statements after a debugging session in the codebase, you can use broccoli-strip-debug to remove them automatically in production builds and disable the debugger flag in the linting configuration altogether which gets you the setup you're looking for.
When Xcode shows a preprocessor macro of DEBUG=1 in its Build Settings, is this equivalent to typing a preprocessor macro manually, such as #define DEBUG 1 ?
Yes, that corresponds to the "-DDEBUG=1" preprocessor option which is equivalent to a macro definition #define DEBUG 1 that is read before any source file is processed.
Yes, But only in the Debug configuration. If you add #define DEBUG 1 to your code then DEBUG will be defined in both the Release and Debug configurations. Different actions use different build configurations
Action | Configuration
--------------------------
Run | Debug
Test | Debug
Profile | Release
Analyze | Debug
Archive | Release
So by defining DEBUG in the Build Settings you can add code that only runs in your local builds. But not in your Ad Hoc or App store versions.
#ifdef DEBUG
[self.tapGestureRecognizer addTarget:self action:#selector(segueHiddenDevMenu:)];
#endif
This code adds a developer only menu to "Nuke and Pave the Database", "Add 10000 new records to the Database", Create the Default Image View. Stuff the users should not play with. And hidden functionality that would get your app rejected.
Setting up environment variables for hundreds of tests get old very quick. Is there a way to declare an environmental variable globally in Eclipse?
Can this be done in Eclipse? Can this be done outside of Eclipse?
It seems that the only way to do it is to enable "Run all tests in the selected project .." and set Environment variables once there.
If you want to run a single test, and that test requires an environment variable set, it looks like you need to set that environment variable as part of that tests's settings.
In windows use the "start" command to spawn eclipse from command line with defined variables (linux has similar functionality)
Make file starteclipse.cmd
================================
SET VAR1=SOMEVALUE
SET VAR2=SOMEVALUE
start d:\eclipse\eclipse.exe
================================
From command line go to the dir with starteclipse.cmd file and run it.
This will spawn eclipse with proper environment settings.
I also find it frustrating having to set env vars one by one.
If you own the code and have a chance to change it, you'd be better off using a System property instead, which can be passed as VMArgs -Dprop=val.
You can set VM args in a global level - Preferences | Java | Installed JREs, and Plugin Development | Target platform.
Even if you can't change the code, most well civilised java libs support properties as well if not more than env vars- so it's worth double checking.
(of course it's not an option for external processes).