# Flutter Integration Test Server in Debian 11 Nspawn Container - Trent's Blog
Trent's blog of mostly technical documentations.

Skip to content

# Flutter Integration Test Server in Debian 11 Nspawn Container

date: 2021-09-24

## Introduction

### Performance

Your Debian Server is way more powerful than your laptop or desktop and flutter integration_tests suck.

### Ergonomics

You have an Android Emulator (or a real device) connected to the machine that you are sitting in front of for reference, and now you can run integration_tests on a different device without having to juggle adb connections on the same machine.

### Nspawn Tho?

Because containers unlike virtual machines access the full power of the host, but nspawn containers are peristent like virtual machines, sparing you the cognitive overhead of dealing with the ephemerality of docker containers and/or of herding cats.

And you already have nspawn, it's build into systemd. Even including the (virtual) network interfaces.

### Documentation

Let's face it: setting up an Android Development Environment is a nightmare.

So don't just follow this guide; follow this guide a repetition of three times, building your own step-by-step guide for yourself as you go. Your brain will thank you.

## Host Preparation (Debian 11)

1. install `systemd-container` and `debootstrap`
2. enable unprivileged user namespaces
   - `echo 'kernel.unprivileged_userns_clone=1' >/etc/sysctl.d/nspawn.conf`
   - `systemctl restart systemd-sysctl.service`
3. you might as well allow debootstrap to user your apt-cacher-ng proxy
   - `export http_proxy=http://<ip address>:3142`

### br0 bridge

describe br0 bridge in `/etc/systemd/nspawn/ftest.nspawn` (optional).

    # /etc/systemd/nspawn/ftest.nspawn
    [Network]
    VirtualEthernet=yes
    Bridge=br0

## ZFS mountpoint

This is optional, obviously; you might not even use zfs.

- `zfs create vm_pool/nspawn/ftest`
- `zfs set mountpoint=/var/lib/machines/ftest vm_pool/nspawn/ftest`
- sanity check `zfs list -r vm_pool/nspawn`

## bootstrap container

    # for apt-cacher-ng proxy
    export http_proxy=http://<ip address>:3142

    debootstrap --include=systemd-container stable /var/list/machines/ftest

## preboot config

1. delete container's package cache
2. copy `/etc/apt/apt.conf` to container
3. copy `/root/.bashrc` to container
4. copy `/root/.inputrc` to container
5. edit `/etc/hostname` in container
6. write nspawn file on host
7. copy `/etc/locale.gen` to `/etc/locale.gen.bak` on container

## first interactive boot

1. `systemd-nspawn -D /var/lib/machines/ftest -U --machine ftest`
2. set passwd: `passwd`
3. stop container: `logout`

## run as service

1. `systemctl start systemd-nspawn@ftest`
2. login: `machinectl login ftest`
3. start/enable network `systemctl enable --now systemd-networkd`
4. add regular user `useradd <username>`

## install applications

### locale

- install locales
- edit `/etc/locale.gen` to taste and then run the command `locale-gen`

### essential apps

    apt-get install openssh-server git unzip wget sudo curl file rsync

### add regular user to sudo group

`usermod -a -G sudo <user>`

### other apps

    apt-get install mosh htop haveged byobu needrestart tree bash-completion

### install openjdk-8 from stretch repo

1. add following to `/etc/apt/sources.list`

       deb http://security.debian.org/debian-security stretch/updates main

2. `apt-get update && apt-get install openjdk-8-jdk-headless`

## user environment

You can now ssh into your container.

scp your favorite environment files over to the container

- ~/.byobu/
- ~/.bashrc
- ~/.bash_aliases
- ~/.inputrc

## install flutter

Pick a location to taste; I prefer `~/.local/`

    cd ; cd .local
    git clone https://github.com/flutter/flutter.git

### downgrade flutter

if needed:

    cd ~/.local/flutter
    git checkout 2.2.3

## install command-line-tools

The schuck and jive here is absurd, but here goes.

Now is the time to decide where ANDROID_HOME and ANDROID_SDK_ROOT are going to be; I prefer `~/.local/share/Android/Sdk/`

    mkdir -p ~/.local/share/Android/Sdk

### temporary installation of cmdline-tools

Command line tools only Scroll half way down

    cd ~/.local/share/Android/Sdk
    wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip
    unzip commandlinetools-linux-7583922_latest.zip
    mkdir 5.0
    mv cmdline-tools/* 5.0/
    mv 5.0 cmdline-tools/

## flutter and sdk environment

add the following to `~/.bashrc`

    function addToPATH {
      case ":$PATH:" in
        *":$1:"*) :;; # already there
        *) PATH="$PATH:$1";; # or PATH="$PATH:$1"
      esac
    }

    addToPATH ~/.local/flutter/bin
    addToPATH ~/.local/share/Android/Sdk/cmdline-tools/latest/bin
    addToPATH ~/.local/share/Android/Sdk/platform-tools

    # temporary path to temporary version of cmdline-tools
    addToPATH ~/.local/share/Android/Sdk/cmdline-tools/5.0/bin

add the following to `~/.bash_aliases`

    alias sdkmanager='sdkmanager --sdk_root=~/.local/share/Android/Sdk'

Confirm by logging out and then back in and:

    which flutter ; which sdkmanager ; alias

### now install cmdline-tools for real

`sdkmanager --install "cmdline-tools;latest"`

and then logout and log back in

#### cleanup

At this point I think you can remove or comment the temporary PATH statement from `~/.bashrc` for the temporary location of cmdline-tools

## install Android SDK

review your options

    sdkmanager --list

and then install them (platform-tools: adb and fastboot will be pulled in automatically)

    sdkmanager --install "platforms;android-30" \
      "build-tools;31.0.0" "build-tools;30.0.3"

## confirm flutter installation

`flutter doctor`

## run tests

At this point you shoud be able to rsync a flutter app over to the container, connect to a device using network adb, and run something like:

    flutter drive --driver integration_test/driver.dart \
      --target integration_test/app_test.dart --profile