Skip to content

Latest commit

 

History

History
140 lines (102 loc) · 13.4 KB

testing.md

File metadata and controls

140 lines (102 loc) · 13.4 KB

Testing and releases

Branches

Branch Status
v2 Main development branch (default). Modular code in android/. Built as decoder-v2.apk
basic Legacy single-file version (1.0x), kept for reference and older setups. Built as decoder.apk. Its version history is in the basic README

Base pull requests on v2.

CI

.github/workflows/build.yml runs on every push and pull request, and by hand (workflow_dispatch, optionally for a given commit). A newer push to the same branch cancels the older run, so latest always gets the build of the newest commit.

Job Runs on What it does
test every push and pull request, forks included (no secrets) ./gradlew testDebugUnitTest, then ./gradlew lintDebug against app/lint-baseline.xml (only new findings fail). Reports are uploaded when it fails
build pushes and manual runs, not pull requests signed assembleRelease (R8 minify and resource shrinking), the R8 mapping.txt kept as a workflow artifact

What a build run publishes:

Branch Output
v2 decoder-v2.apk and decoder-v2-mapping.txt in the latest release (replaced by every build); the APK with its version and commit to the OpenIPC Telegram channel (new versions only)
basic decoder.apk in latest; nothing to Telegram
any other workflow artifacts decoder-<branch, / → -> (APK) and …-mapping on the run page

Every run, v2 and basic included, also keeps its mapping as the artifact …-mapping. Artifacts expire after 90 days.

A pull request therefore gets tests and lint only; its APK comes from the push run of its branch.

Unit tests

JVM tests under android/app/src/test/java/com/openipc/decoder/ (JUnit 4, Android stubs return defaults). They cover the parts that are pure logic: RTSP responses, URLs, authentication and sessions against a fake server (RtspSession…, RtspAuth…, RtspUrl…), SDP and transports, RTP reordering and udp:// URLs, NAL and JPEG assembly, HTTP MJPEG parsing, audio formats and decoding, the decode planner, the credential store, the debug server (JSON, request parsing, redaction), stream checks, the grid layout, video fit and the buffer pool. No test needs a device; UI and MediaCodec behaviour are tested on the bench (Device tests).

CI is the reference: the project does not depend on local builds.

Versions and releases

  • Versions are MAJOR.MINOR.PATCH (versionName in android/app/build.gradle): PATCH for fixes and small changes, MINOR for a new feature, MAJOR for an incompatible change or a large update, only when the maintainer decides. Every pull request that changes the app or its build (android/, except the unit tests and Markdown files, and .github/workflows/build.yml, which holds build steps) bumps the version as its last commit before the merge: versionName by that rule and versionCode +1. Docs-only and test-only pull requests do not. A pull request that changes the app or the build but not the APKs (a test or publication step in the workflow, a comment) takes the no-release label instead and keeps the version. Numbers are not reserved for open pull requests: each one takes the next number when it is merged. CI checks this on every pull request to v2 (.github/check-version.sh in the version workflow, .github/workflows/version.yml; adding or removing a label re-runs only this check, not the build): a new number must be canonical (no leading zeros), greater than the base one, and come with its own CHANGELOG.md section.

  • Until 2.17 v2 counted 2.xx (+0.01 per pull request); 2.17 is followed by 2.17.1 or 2.18.0. basic keeps its 1.7.x line (1.07.1 is 1.7.1).

  • CHANGELOG.md is the change history: the version bump commit of a pull request that changes the app adds the version's section (## <version> — <date>, newest first) in the same pull request.

  • Development is continuous, so there is no release per version (#194). The one release, latest, holds the newest v2 and basic builds and is updated in place by both (.github/publish-latest.sh, #229): each branch replaces only its own files; a v2 build moves the latest tag to the commit it built and sets the title Decoder <version>; the notes have one line per branch with its version and commit. The APK of every new v2 version (not every build) is posted to the OpenIPC Telegram channel, where the older builds can be found; basic posts nothing there. Builds of other branches are only workflow artifacts of their runs (90 days).

  • Test pre-releases: to let a reporter test a branch, a pre-release named after the issue is made by hand from the branch's CI artifact (never from a local build), e.g. toys-187-test2 for #187. It is deleted when the test is over, or replaced by the next one.

    B=feat/my-branch                       # the branch to test
    RUN=$(gh run list -R OpenIPC/decoder -b "$B" -e push -w Build -L 1 --json databaseId -q '.[0].databaseId')
    gh run download "$RUN" -R OpenIPC/decoder -n "decoder-${B//\//-}"   # gives decoder-feat-my-branch.apk
    cp "decoder-${B//\//-}.apk" decoder-my-test1.apk                    # the asset name the reporter sees
    gh release create my-187-test1 decoder-my-test1.apk --prerelease \
      --target "$(gh run view "$RUN" -R OpenIPC/decoder --json headSha -q .headSha)" \
      --title "… test build 1 (#187)" --notes "…"

    A test build never takes the place of latest or of another test build: always --prerelease (so it is never marked Latest and releases/latest keeps pointing at latest), a tag and an asset name of its own for every build (<device>-<issue>-test<N>, decoder-<device>-test<N>.apk, never decoder-v2.apk or decoder.apk); the artifact is always named after the branch.

  • The change history is CHANGELOG.md; the details are in the merged pull requests.

  • The installed version and build hash show in the menu (under Exit, v2.10, <hash>) and in /stats.json (version, git).

  • Every build is com.openipc.decoder with the release signature, so a branch build installs over a release and keeps the settings.

Testing a branch build

B=feat/my-branch
RUN=$(gh run list -R OpenIPC/decoder -b "$B" -e push -L 1 --json databaseId -q '.[0].databaseId')
gh run download "$RUN" -R OpenIPC/decoder -n "decoder-${B//\//-}"
adb install -r "decoder-${B//\//-}.apk"

The current v2 build: gh release download latest -R OpenIPC/decoder -p decoder-v2.apk. Check the hash under Exit after installing.

Stack traces and mapping.txt

Release builds are shrunk and obfuscated by R8: classes, fields and methods get short names, and line numbers survive only through a map. A crash from a release build reads like this (an example):

java.lang.IllegalStateException: …
    at a.u.a(SourceFile:12)
    at com.openipc.decoder.Decoder.u(SourceFile:48)

R8 writes that map as mapping.txt, one per build:

# compiler: R8
# compiler_version: 8.13.17
# min_api: 21
# pg_map_id: 8df440e8…            ← ties the file to exactly one build
com.openipc.decoder.DecodePlanner -> a.u:
# {"id":"sourceFile","fileName":"DecodePlanner.java"}
    long capacity -> a
    long proven -> c
    long failedLoad -> d
    1:5:void <init>(long,boolean,long,long):147:147 -> <init>

For every class, field and method it gives original -> obfuscated, with the line ranges that map back to the source. It also covers the library classes that went into the APK, which is why it is about 9,000 lines (700 KB). It holds no secrets (the code is open), and devices don't need it: it only matters for reading crashes.

A mapping fits only the build it came from. Use the one whose build matches the hash under Exit or git in /stats.json:

Build Mapping
the current v2 build decoder-v2-mapping.txt in latest
an older v2 build, or any branch build the artifact decoder-v2-mapping (or decoder-<branch>-mapping) of the CI run that built it, kept 90 days. A push run is found by its commit (below). A manual run (Run workflow with commit_hash) is listed under the branch it was started on, not under the commit it built: gh run list -R OpenIPC/decoder -w Build -e workflow_dispatch -b <branch>, then pick the run by its time or ID
builds before 2.08 none: they were made before the mapping was kept (#181)
RUN=$(gh run list -R OpenIPC/decoder -c <full commit hash> -e push -w Build -L 1 --json databaseId -q '.[0].databaseId')
gh run download "$RUN" -R OpenIPC/decoder -n decoder-v2-mapping
retrace decoder-v2-mapping.txt stacktrace.txt     # Android SDK command-line tools

After retrace, the frames read at com.openipc.decoder.DecodePlanner.step(DecodePlanner.java:215).

Building locally

Not needed for contributing (CI builds every push), but possible: JDK 17 and the Android SDK (platform 36), with ANDROID_HOME or android/local.properties.

cd android
./gradlew testDebugUnitTest    # unit tests
./gradlew assembleDebug        # → app/build/outputs/apk/debug/app-debug.apk, no keys needed

A release build needs a keystore at android/key.jks and KEYSTORE_PASS, KEY_ALIAS, KEY_PASS in the environment (./gradlew assembleRelease). Debug and release builds are signed with different keys: to switch, uninstall first, which removes the saved camera URLs.

Device tests

Test rounds run as GitHub issues that follow the structure of #53. Reports from users: devices.md.