Fix tests

* reimplement config system to be a bit more intuitive.
pull/363/head
Connor Rigby 2017-09-12 09:51:31 -07:00
parent 68af2939a3
commit 487ce22cfc
23 changed files with 164 additions and 256 deletions

2
.gitignore vendored
View File

@ -42,6 +42,6 @@ dump.rdb
fwup-key.priv
.env
# secret config stuffs for dev environment.
config/auth_secret.exs
auth_secret.exs
flash_fw.sh
tmp

26
TODO.md 100644
View File

@ -0,0 +1,26 @@
# TODO
## Serial
- [ ] FW updates.
- [ ] Autodetect TTY. (Or use Configuration?)
## System
- [ ] OS updates.
- [ ] Key rotation for signed releases.
## Configuration
- [ ] Rewrite `configurator` web app.
- [ ] Only have configuration router up during configuration time.
## CeleryScript
- [ ] Implement _EVERY_ CS Node again.
## Logging
- [ ] Reimplement Logger
## HTTP
- [ ] Write tests for HTTP.
## Debug
- [ ] Implement `debug`/`developer` mode.

View File

@ -26,36 +26,24 @@ config :fs, path: "/tmp/images"
# Configure your our system.
# Default implementation needs no special stuff.
config :farmbot, :init, [
Farmbot.Bootstrap.Configurator
]
# See Farmbot.System.Supervisor and Farmbot.System.Init for details.
config :farmbot, :init, []
# Transports.
config :farmbot, :transport, [
Farmbot.BotState.Transport.GenMqtt
]
config :farmbot, :transport, []
# Configure Farmbot Behaviours.
config :farmbot, :behaviour, [
authorization: Farmbot.Bootstrap.Authorization,
# uncomment this line if you have a real arduino plugged in. You will also need
# ensure the config for `:uart_handler` is correct.
# firmware_handler: Farmbot.Firmware.UartHandler,
firmware_handler: Farmbot.Host.FirmwareHandlerStub,
system_tasks: Farmbot.Host.SystemTasks
]
config :farmbot, :uart_handler, [
tty: "/dev/ttyACM0"
]
config :nerves_firmware_ssh,
authorized_keys: [
File.read!(Path.join(System.user_home!, ".ssh/id_rsa.pub"))
]
config :bootloader,
init: [:nerves_runtime, :nerves_init_gadget],
app: :farmbot
case target do
"host" -> import_config("host/#{env}.exs")
_ ->
if File.exists?("config/#{target}/#{env}.exs") do
import_config("#{target}/#{env}.exs")
else
import_config("target/#{env}.exs")
end
end

View File

@ -0,0 +1,10 @@
use Mix.Config
# You should copy this file to config/host/auth_secret.exs
# And make sure to configure the credentials to something that makes sense.
config :farmbot, :authorization, [
email: "admin@admin.com",
password: "password123",
server: "http://localhost:3000"
]

View File

@ -0,0 +1,12 @@
use Mix.Config
# You should copy this file to config/host/auth_secret.exs
# And make sure to configure the credentials to something that makes sense.
config :farmbot, :authorization, [
email: "admin@admin.com",
password: "password123",
server: "http://localhost:3000",
token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbkBhZG1pbi5jb20iLCJpYXQiOjE1MDUwMDM1ODMsImp0aSI6ImIxZTM4ODJmLWJjYzMtNDcxNS04NTViLWVlZjBiZGQ0MTY0YSIsImlzcyI6Ii8vMTAuMTg2LjE5MC45MDozMDAwIiwiZXhwIjoxNTA4NDU5NTgzLCJtcXR0IjoiMTAuMTg2LjE5MC45MCIsIm9zX3VwZGF0ZV9zZXJ2ZXIiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2Zhcm1ib3QvZmFybWJvdF9vcy9yZWxlYXNlcy9sYXRlc3QiLCJmd191cGRhdGVfc2VydmVyIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9GYXJtYm90L2Zhcm1ib3QtYXJkdWluby1maXJtd2FyZS9yZWxlYXNlcy9sYXRlc3QiLCJib3QiOiJkZXZpY2VfMiJ9.kqsn8PIfReYRKlvqaIYsMZ5ai2TUP66ToqUX28V0Yt0xG7hY4eqBkLw8PWWgvCcx3J-xGr4wAKUdclkex-yZVU9L912eqFSrYSIkBKO4qUCS5Xtvc6MpdwI34r-JQckfoCs_G_PtTI1YNR8Rah8UyI4U8raIh_hjUmk5X0aWYxOqC9FgGfhtnR62RsYr1DzAKtf211g80VFUbQmE-9mIKBEVjPv5oiSzRo_FXovn_JaqG9JQkP-sabV4P9ItksJ9LNzwIZ_EYJCzM-838Ad6507CpbcpbVC6cN_WWKU0vP4L2Akvc4_0QLZ3TeY8UhgYqasPwcpOmvmzbyEJRFmZ1w"
]

View File

@ -0,0 +1,28 @@
use Mix.Config
unless File.exists?("config/host/auth_secret.exs") do
Mix.raise("You need to configure your dev environment. See `config/host/auth_secret.exs` for an example.\r\n")
end
import_config("auth_secret.exs")
# Configure your our system.
# Default implementation needs no special stuff.
config :farmbot, :init, [
]
# Transports.
config :farmbot, :transport, [
Farmbot.BotState.Transport.GenMqtt
]
# Configure Farmbot Behaviours.
config :farmbot, :behaviour, [
authorization: Farmbot.Bootstrap.Authorization,
# uncomment this line if you have a real arduino plugged in. You will also need
# ensure the config for `:uart_handler` is correct.
# firmware_handler: Farmbot.Firmware.UartHandler,
firmware_handler: Farmbot.Host.FirmwareHandlerStub,
system_tasks: Farmbot.Host.SystemTasks
]

View File

@ -0,0 +1,19 @@
use Mix.Config
unless File.exists?("config/host/auth_secret_test.exs") do
Mix.raise("You need to configure your test environment.\r\n")
end
import_config("auth_secret_test.exs")
config :farmbot, :init, []
# Transports.
config :farmbot, :transport, []
# Configure Farmbot Behaviours.
config :farmbot, :behaviour, [
authorization: Farmbot.Test.Authorization,
firmware_handler: Farmbot.Host.FirmwareHandlerStub,
system_tasks: Farmbot.Test.SystemTasks
]

View File

@ -0,0 +1,33 @@
use Mix.Config
# Configure your our system.
# Default implementation needs no special stuff.
config :farmbot, :init, [
# Farmbot.Bootstrap.Configurator
]
# Transports.
config :farmbot, :transport, [
Farmbot.BotState.Transport.GenMqtt
]
# Configure Farmbot Behaviours.
config :farmbot, :behaviour, [
authorization: Farmbot.Bootstrap.Authorization,
firmware_handler: Farmbot.Firmware.UartHandler,
system_tasks: Farmbot.Host.SystemTasks
]
config :farmbot, :uart_handler, [
tty: "/dev/ttyACM0"
]
config :nerves_firmware_ssh,
authorized_keys: [
File.read!(Path.join(System.user_home!, ".ssh/id_rsa.pub"))
]
config :bootloader,
init: [:nerves_runtime, :nerves_init_gadget],
app: :farmbot

View File

@ -0,0 +1,9 @@
use Mix.Config
import_config("dev.exs")
config :nerves_firmware_ssh,
authorized_keys: []
config :bootloader,
init: [:nerves_runtime],
app: :farmbot

View File

@ -72,4 +72,5 @@ defmodule Farmbot.Bootstrap.Authorization do
end
defp handle_error({:error, _reason} = error), do: error
defp handle_error({:error, :invalid, _} = error), do: error
end

View File

@ -1,12 +0,0 @@
defmodule Farmbot.Bootstrap.Configurator do
use GenServer
def start_link(_, opts) do
creds = [
email: "connor@farmbot.io",
password: "password123",
server: "https://staging.farmbot.io"
]
Application.put_env(:farmbot, :authorization, creds)
:ignore
end
end

View File

@ -98,11 +98,12 @@ defmodule Farmbot.Bootstrap.Supervisor do
end
end
defp actual_init(_args, email, pass, server) do
Logger.info "Beginning authorization: #{email} - #{server}"
defp actual_init(args, email, pass, server) do
Logger.info "Beginning authorization: #{@auth_task} - #{email} - #{server}"
# get a token
case @auth_task.authorize(email, pass, server) do
{:ok, token} ->
Logger.info "Successful authorization: #{@auth_task} - #{email} - #{server}"
children = [
supervisor(Farmbot.BotState.Supervisor, [token, [name: Farmbot.BotState.Supervisor ]]),
supervisor(Farmbot.HTTP.Supervisor, [token, [name: Farmbot.HTTP.Supervisor]]),
@ -113,6 +114,9 @@ defmodule Farmbot.Bootstrap.Supervisor do
# an application start fail and we would factory_reset from there,
# the error message is just way more useful here.
{:error, reason} -> Farmbot.System.factory_reset(reason)
# If we got invalid json, just try again.
# FIXME(Connor) Why does this happen?
{:error, :invalid, _} -> actual_init(args, email, pass, server)
end
end
end

View File

@ -1,3 +0,0 @@
defmodule Farmbot.Firmware.Handler do
@moduledoc "Handler for a firmware."
end

View File

@ -1,9 +0,0 @@
#!/bin/bash
SYSTEM=$1
export MIX_ENV=prod
export MIX_TARGET=$SYSTEM
echo "building firmware for $SYSTEM"
npm install
npm run build
mix deps.get
mix firmware

View File

@ -1,23 +0,0 @@
#!/bin/bash
# Collects all the various images and archives for constructing a release.
SYSTEM=$1
VERSION=$2
export MIX_ENV=prod
export MIX_TARGET=$SYSTEM
REL_DIR=release-$VERSION
mkdir -p $REL_DIR
FIRM_FILE=images/$MIX_ENV/$SYSTEM/farmbot.fw # the .fw file generated by `mix firmware`
FIRM_FILE_REL=$REL_DIR/farmbot-$SYSTEM-$VERSION.fw # where we want our formatted system
FIRM_FILE_REL_IMG=$REL_DIR/farmbot-$SYSTEM-$VERSION.img # same as the above file, but a .img file
SYSTEM_DIR=nerves/NERVES_SYSTEM_$SYSTEM # the NERVES_SYSTEM build dir
SYSTEM_TAR=$SYSTEM_DIR/nerves_system_$SYSTEM.tar.gz # the archive generated by `make system`
SYSTEM_TAR_REL=$REL_DIR/farmbot.rootfs-$SYSTEM-$VERSION.tar.gz # where we want our outputted archive to be
# copy the firmware file to the release file
cp $FIRM_FILE $FIRM_FILE_REL
# build an image from the release firmware
fwup -a -d $FIRM_FILE_REL_IMG -i $FIRM_FILE_REL -t complete
# copy the rootfs archive to the release dir
cp $SYSTEM_TAR $SYSTEM_TAR_REL

View File

@ -1,6 +0,0 @@
#!/bin/bash
SYSTEM=$1
echo "building system for $SYSTEM"
cd nerves/NERVES_SYSTEM_$SYSTEM
time make
make system

View File

@ -1,24 +0,0 @@
#!/bin/bash
SYSTEM=$1
NERVES_SYSTEM_BR_GIT="https://github.com/nerves-project/nerves_system_br"
NERVES_SYSTEM_BR_COMMIT="049d8e19b69b0f84084182d9bdd915e4eb431ed5"
if [ -d "nerves/NERVES_SYSTEM_$SYSTEM" ]; then
# Control will enter here if $DIRECTORY exists.
echo "NERVES_SYSTEM_$SYSTEM dir found."
else
echo "NERVES_SYSTEM_$SYSTEM dir not found."
CWD=$(pwd)
git clone $NERVES_SYSTEM_BR_GIT nerves/nerves_system_br
cd nerves/nerves_system_br
git checkout $NERVES_SYSTEM_BR_COMMIT
cd $CWD
fi
nerves/nerves_system_br/create-build.sh nerves/nerves_system_$SYSTEM/nerves_defconfig nerves/NERVES_SYSTEM_$SYSTEM
if [ ! -f nerves/nerves_system_br/buildroot/.farmbot_applied_patches_list ]; then
echo "Applying FarmbotOS patches"
nerves/nerves_system_br/buildroot/support/scripts/apply-patches.sh nerves/nerves_system_br/buildroot patches
cp nerves/nerves_system_br/buildroot/.applied_patches_list nerves/nerves_system_br/buildroot/.farmbot_applied_patches_list
nerves/nerves_system_br/create-build.sh nerves/nerves_system_$SYSTEM/nerves_defconfig nerves/NERVES_SYSTEM_$SYSTEM
fi

View File

@ -1,117 +0,0 @@
version = Path.join([__DIR__, "..", "VERSION"]) |> File.read! |> String.strip
IO.puts version
{commitish, _} = System.cmd("git", ["log", "--pretty=format:%hQQ%adQQ%f", "-1"])
thing = String.split(commitish, "QQ")
IO.puts "Finding private key."
priv_key_path = System.get_env("PRIV_KEY_FILE") || nil
if priv_key_path do
IO.puts("Found private key!")
else
IO.puts("Could not find private key!")
end
IO.puts "Building default portions"
initial = "# THIS FILE WAS GENERATED BY `build_makefile.exs`
# #{Enum.join(thing, "\n# ")}
default: rpi3
ifdef SILENT
.SILENT:
endif
dev_env:
\texport MIX_ENV=dev
prod_env:
\texport MIX_ENV=prod
clean:
\t$(info Cleaning)
\trm -rf nerves/NERVES_SYSTEM_*
\trm -rf nerves/nerves_system_br
\trm -rf npm-debug*
\trm -rf erl_crash.dump
\trm -rf doc
\trm -rf cover
\trm -rf deps
\trm -rf node_modules
\trm -rf cache
\trm -rf _build
\trm -rf images
\trm -rf images
\trm -rf latest-release
\trm Makefile
\telixir scripts/generate_makefile.exs
test: dev_env
\tscripts/run_tests.sh
travis_test: dev_env
\tscripts/run_travis_tests.sh
## End default portion.\n"
build_system_part = fn(sys) ->
"\n## begin #{sys} portion.
## #{sys} env
env-#{sys}: prod_env
\texport NERVES_TARGET=#{sys}
## #{sys} build
#{sys}: env-#{sys} system-#{sys} firmware-#{sys}
\t$(info Building stuff for #{sys})
## #{sys} create-build
create-build-#{sys}:
\tscripts/clone_system.sh #{sys}
## #{sys} system
system-#{sys}: create-build-#{sys}
\t$(info Building Linux System for #{sys})
\tscripts/build_system.sh #{sys}
## #{sys} firmware
firmware-#{sys}:
\t$(info Building Firmware for #{sys})
\tscripts/build_firmware.sh #{sys}
release-#{sys}: #{sys}
\tscripts/build_release_images.sh #{sys} #{version}
#{if priv_key_path, do: "\tscripts/sign_release.sh #{sys} #{version} #{priv_key_path}"}
## end #{sys} portion."
end
list = File.ls!("nerves")
only_systems = Enum.reduce(list, [], fn(d, acc) ->
case d do
# ignore nerves_system_br
"nerves_system_br" -> acc
"nerves_system_"<> sys -> [sys | acc]
_ -> acc
end
end)
initial_mod = Enum.reduce(only_systems, initial, fn(sys, acc) ->
IO.puts "Defining system: #{sys}"
acc <> build_system_part.(sys)
end)
IO.puts "Defining release for #{version}"
final = initial_mod <>
# "\n\n## Release will build all the systems.
# release: clean #{Enum.map(only_systems, fn(a) -> " release-"<>a end)}"
"\n\n## Release will build all the systems.
release: clean release-rpi3"
IO.puts "Writing file."
File.write("Makefile", final)
blah = "release-#{version}"
IO.puts blah
File.rm "./release-latest"
File.ln_s(blah, "./release-latest")

View File

@ -1,4 +0,0 @@
#!/bin/bash
export MIX_ENV=test
mix deps.get
mix all_test

View File

@ -1,7 +0,0 @@
#!/bin/bash
export MIX_ENV=test
mix deps.get
mix travis_test || { echo 'Tests failed!' ; exit 1; }
if [[ "$TRAVIS_BRANCH" == "staging" ]]; then
SILENT=true make release
fi

View File

@ -1,11 +0,0 @@
#!/bin/bash
SYSTEM=$1
VERSION=$2
PRIV_KEY_PATH=$3
REL_DIR=release-$VERSION
FIRM_FILE_REL=$REL_DIR/farmbot-$SYSTEM-$VERSION.fw
SIGNED_FIRM_FILE_REL=$REL_DIR/farmbot-$SYSTEM-$VERSION-signed.fw
MIX_ENV=prod MIX_TARGET=$SYSTEM mix firmware.sign $PRIV_KEY_PATH $SIGNED_FIRM_FILE_REL
mv $FIRM_FILE_REL $FIRM_FILE_REL.unsigned
mv $SIGNED_FIRM_FILE_REL $FIRM_FILE_REL

View File

@ -1,12 +0,0 @@
#!/bin/sh
CWD=`pwd`
mkdir /tmp/tty0tty
cd /tmp/tty0tty
git clone https://github.com/freemed/tty0tty .
cd module
make
sudo cp tty0tty.ko /lib/modules/$(uname -r)/kernel/drivers/misc/
sudo depmod
sudo modprobe tty0tty
sudo chmod 666 /dev/tnt*;
cd $CWD

View File

@ -1,6 +1,7 @@
defmodule FarmbotTestSupport do
@moduledoc "Test Helpers."
import Farmbot.DebugLog, only: [color: 1]
require Logger
defp error(err) do
"""
@ -16,6 +17,7 @@ defmodule FarmbotTestSupport do
end
def preflight_checks do
Logger.info "Starting Preflight Checks."
with {:ok, tkn} <- ping_api(),
:ok <- ping_mqtt(tkn) do
:ok
@ -28,14 +30,18 @@ defmodule FarmbotTestSupport do
server = Application.get_env(:farmbot, :authorization)[:server]
email = Application.get_env(:farmbot, :authorization)[:email]
password = Application.get_env(:farmbot, :authorization)[:password]
Logger.info "Preflight check: api: #{server}"
case Farmbot.Bootstrap.Authorization.authorize(email, password, server) do
{:error, _reason} -> :api
{:ok, tkn} -> {:ok, tkn}
{:ok, tkn} ->
Logger.info "Preflight check api complete."
{:ok, tkn}
end
end
defp ping_mqtt(tkn) do
url = Farmbot.Jwt.decode!(tkn).mqtt
Logger.info "Preflight check: mqtt: #{url}"
case :gen_tcp.connect(to_charlist(url), 1883, [:binary]) do
{:error, _} -> :mqtt
{:ok, port} -> :gen_tcp.close(port)