test.yml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. name: test
  2. on: [push, pull_request]
  3. env:
  4. CFLAGS: -Werror
  5. MAKEFLAGS: -j
  6. jobs:
  7. # run tests
  8. test:
  9. runs-on: ubuntu-latest
  10. strategy:
  11. fail-fast: false
  12. matrix:
  13. arch: [x86_64, thumb, mips, powerpc]
  14. steps:
  15. - uses: actions/checkout@v2
  16. - name: install
  17. run: |
  18. # need toml, also pip3 isn't installed by default?
  19. sudo apt-get update -qq
  20. sudo apt-get install -qq python3 python3-pip lcov
  21. sudo pip3 install toml
  22. gcc --version
  23. # setup a ram-backed disk to speed up reentrant tests
  24. mkdir disks
  25. sudo mount -t tmpfs -o size=100m tmpfs disks
  26. TESTFLAGS="$TESTFLAGS --disk=disks/disk"
  27. # collect coverage
  28. mkdir -p coverage
  29. TESTFLAGS="$TESTFLAGS --coverage=`
  30. `coverage/${{github.job}}-${{matrix.arch}}.info"
  31. echo "TESTFLAGS=$TESTFLAGS" >> $GITHUB_ENV
  32. # cross-compile with ARM Thumb (32-bit, little-endian)
  33. - name: install-thumb
  34. if: matrix.arch == 'thumb'
  35. run: |
  36. sudo apt-get install -qq \
  37. gcc-arm-linux-gnueabi \
  38. libc6-dev-armel-cross \
  39. qemu-user
  40. echo "CC=arm-linux-gnueabi-gcc -mthumb --static" >> $GITHUB_ENV
  41. echo "EXEC=qemu-arm" >> $GITHUB_ENV
  42. arm-linux-gnueabi-gcc --version
  43. qemu-arm -version
  44. # cross-compile with MIPS (32-bit, big-endian)
  45. - name: install-mips
  46. if: matrix.arch == 'mips'
  47. run: |
  48. sudo apt-get install -qq \
  49. gcc-mips-linux-gnu \
  50. libc6-dev-mips-cross \
  51. qemu-user
  52. echo "CC=mips-linux-gnu-gcc --static" >> $GITHUB_ENV
  53. echo "EXEC=qemu-mips" >> $GITHUB_ENV
  54. mips-linux-gnu-gcc --version
  55. qemu-mips -version
  56. # cross-compile with PowerPC (32-bit, big-endian)
  57. - name: install-powerpc
  58. if: matrix.arch == 'powerpc'
  59. run: |
  60. sudo apt-get install -qq \
  61. gcc-powerpc-linux-gnu \
  62. libc6-dev-powerpc-cross \
  63. qemu-user
  64. echo "CC=powerpc-linux-gnu-gcc --static" >> $GITHUB_ENV
  65. echo "EXEC=qemu-ppc" >> $GITHUB_ENV
  66. powerpc-linux-gnu-gcc --version
  67. qemu-ppc -version
  68. # make sure example can at least compile
  69. - name: test-example
  70. run: |
  71. sed -n '/``` c/,/```/{/```/d; p}' README.md > test.c && \
  72. make all CFLAGS+=" \
  73. -Duser_provided_block_device_read=NULL \
  74. -Duser_provided_block_device_prog=NULL \
  75. -Duser_provided_block_device_erase=NULL \
  76. -Duser_provided_block_device_sync=NULL \
  77. -include stdio.h"
  78. # # test configurations
  79. # # normal+reentrant tests
  80. # - name: test-default
  81. # run: |
  82. # make clean
  83. # make test TESTFLAGS+="-nrk"
  84. # # NOR flash: read/prog = 1 block = 4KiB
  85. # - name: test-nor
  86. # run: |
  87. # make clean
  88. # make test TESTFLAGS+="-nrk \
  89. # -DLFS_READ_SIZE=1 -DLFS_BLOCK_SIZE=4096"
  90. # # SD/eMMC: read/prog = 512 block = 512
  91. # - name: test-emmc
  92. # run: |
  93. # make clean
  94. # make test TESTFLAGS+="-nrk \
  95. # -DLFS_READ_SIZE=512 -DLFS_BLOCK_SIZE=512"
  96. # # NAND flash: read/prog = 4KiB block = 32KiB
  97. # - name: test-nand
  98. # run: |
  99. # make clean
  100. # make test TESTFLAGS+="-nrk \
  101. # -DLFS_READ_SIZE=4096 -DLFS_BLOCK_SIZE=\(32*1024\)"
  102. # # other extreme geometries that are useful for various corner cases
  103. # - name: test-no-intrinsics
  104. # run: |
  105. # make clean
  106. # make test TESTFLAGS+="-nrk \
  107. # -DLFS_NO_INTRINSICS"
  108. # - name: test-byte-writes
  109. # # it just takes too long to test byte-level writes when in qemu,
  110. # # should be plenty covered by the other configurations
  111. # if: matrix.arch == 'x86_64'
  112. # run: |
  113. # make clean
  114. # make test TESTFLAGS+="-nrk \
  115. # -DLFS_READ_SIZE=1 -DLFS_CACHE_SIZE=1"
  116. # - name: test-block-cycles
  117. # run: |
  118. # make clean
  119. # make test TESTFLAGS+="-nrk \
  120. # -DLFS_BLOCK_CYCLES=1"
  121. # - name: test-odd-block-count
  122. # run: |
  123. # make clean
  124. # make test TESTFLAGS+="-nrk \
  125. # -DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD_SIZE=256"
  126. # - name: test-odd-block-size
  127. # run: |
  128. # make clean
  129. # make test TESTFLAGS+="-nrk \
  130. # -DLFS_READ_SIZE=11 -DLFS_BLOCK_SIZE=704"
  131. # collect coverage
  132. - name: collect-coverage
  133. continue-on-error: true
  134. run: |
  135. # we only care about littlefs's actual source
  136. lcov -e coverage/${{github.job}}-${{matrix.arch}}.info \
  137. $(for f in lfs*.c ; do echo "/$f" ; done) \
  138. -o coverage/${{github.job}}-${{matrix.arch}}.info
  139. - name: upload-coverage
  140. continue-on-error: true
  141. uses: actions/upload-artifact@v2
  142. with:
  143. name: coverage
  144. path: coverage
  145. retention-days: 1
  146. # update results
  147. - name: results-code
  148. continue-on-error: true
  149. run: |
  150. mkdir -p results
  151. # TODO remove the need for SRC
  152. make clean
  153. make code \
  154. SRC="$(echo lfs*.c)" \
  155. CFLAGS+=" \
  156. -DLFS_NO_ASSERT \
  157. -DLFS_NO_DEBUG \
  158. -DLFS_NO_WARN \
  159. -DLFS_NO_ERROR" \
  160. CODEFLAGS+="-o results/code-${{matrix.arch}}.csv"
  161. - name: results-code-readonly
  162. continue-on-error: true
  163. run: |
  164. mkdir -p results
  165. make clean
  166. make code \
  167. SRC="$(echo lfs*.c)" \
  168. CFLAGS+=" \
  169. -DLFS_NO_ASSERT \
  170. -DLFS_NO_DEBUG \
  171. -DLFS_NO_WARN \
  172. -DLFS_NO_ERROR \
  173. -DLFS_READONLY" \
  174. CODEFLAGS+="-o results/code-${{matrix.arch}}-readonly.csv"
  175. - name: results-code-threadsafe
  176. continue-on-error: true
  177. run: |
  178. mkdir -p results
  179. make clean
  180. make code \
  181. SRC="$(echo lfs*.c)" \
  182. CFLAGS+=" \
  183. -DLFS_NO_ASSERT \
  184. -DLFS_NO_DEBUG \
  185. -DLFS_NO_WARN \
  186. -DLFS_NO_ERROR \
  187. -DLFS_THREADSAFE" \
  188. CODEFLAGS+="-o results/code-${{matrix.arch}}-threadsafe.csv"
  189. - name: results-code-migrate
  190. continue-on-error: true
  191. run: |
  192. mkdir -p results
  193. make clean
  194. make code \
  195. SRC="$(echo lfs*.c)" \
  196. CFLAGS+=" \
  197. -DLFS_NO_ASSERT \
  198. -DLFS_NO_DEBUG \
  199. -DLFS_NO_WARN \
  200. -DLFS_NO_ERROR \
  201. -DLFS_MIGRATE" \
  202. CODEFLAGS+="-o results/code-${{matrix.arch}}-migrate.csv"
  203. - name: upload-results
  204. continue-on-error: true
  205. uses: actions/upload-artifact@v2
  206. with:
  207. name: results
  208. path: results
  209. # limit reporting to Thumb, otherwise there would be too many numbers
  210. # flying around for the results to be easily readable
  211. - name: collect-status
  212. continue-on-error: true
  213. if: matrix.arch == 'thumb'
  214. run: |
  215. mkdir -p status
  216. for f in results/code*.csv
  217. do
  218. [ -e "$f" ] || continue
  219. export STEP="results-code$(
  220. echo $f | sed -n 's/.*code-.*-\(.*\).csv/-\1/p')"
  221. export CONTEXT="results / code$(
  222. echo $f | sed -n 's/.*code-.*-\(.*\).csv/ (\1)/p')"
  223. export PREV="$(curl -sS \
  224. "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master" \
  225. | jq -re "select(.sha != env.GITHUB_SHA) | .statuses[]
  226. | select(.context == env.CONTEXT).description
  227. | capture(\"Code size is (?<result>[0-9]+)\").result" \
  228. || echo 0)"
  229. echo $PREV
  230. export DESCRIPTION="$(./scripts/code.py -u $f -s | awk '
  231. NR==2 {printf "Code size is %d B",$2}
  232. NR==2 && ENVIRON["PREV"] != 0 {
  233. printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/$2}')"
  234. jq -n '{
  235. state: "success",
  236. context: env.CONTEXT,
  237. description: env.DESCRIPTION,
  238. target_job: "${{github.job}} (${{matrix.arch}})",
  239. target_step: env.STEP}' \
  240. | tee status/code$(
  241. echo $f | sed -n 's/.*code-.*-\(.*\).csv/-\1/p').json
  242. done
  243. - name: upload-status
  244. continue-on-error: true
  245. if: matrix.arch == 'thumb'
  246. uses: actions/upload-artifact@v2
  247. with:
  248. name: status
  249. path: status
  250. retention-days: 1
  251. # run under Valgrind to check for memory errors
  252. valgrind:
  253. runs-on: ubuntu-latest
  254. steps:
  255. - uses: actions/checkout@v2
  256. - name: install
  257. run: |
  258. # need toml, also pip3 isn't installed by default?
  259. sudo apt-get update -qq
  260. sudo apt-get install -qq python3 python3-pip
  261. sudo pip3 install toml
  262. - name: install-valgrind
  263. run: |
  264. sudo apt-get update -qq
  265. sudo apt-get install -qq valgrind
  266. valgrind --version
  267. # # normal tests, we don't need to test all geometries
  268. # - name: test-valgrind
  269. # run: make test TESTFLAGS+="-k --valgrind"
  270. # self-host with littlefs-fuse for a fuzz-like test
  271. fuse:
  272. runs-on: ubuntu-latest
  273. if: "!endsWith(github.ref, '-prefix')"
  274. steps:
  275. - uses: actions/checkout@v2
  276. - name: install
  277. run: |
  278. # need toml, also pip3 isn't installed by default?
  279. sudo apt-get update -qq
  280. sudo apt-get install -qq python3 python3-pip libfuse-dev
  281. sudo pip3 install toml
  282. fusermount -V
  283. gcc --version
  284. - uses: actions/checkout@v2
  285. with:
  286. repository: littlefs-project/littlefs-fuse
  287. ref: v2
  288. path: littlefs-fuse
  289. - name: setup
  290. run: |
  291. # copy our new version into littlefs-fuse
  292. rm -rf littlefs-fuse/littlefs/*
  293. cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs
  294. # setup disk for littlefs-fuse
  295. mkdir mount
  296. sudo chmod a+rw /dev/loop0
  297. dd if=/dev/zero bs=512 count=128K of=disk
  298. losetup /dev/loop0 disk
  299. - name: test
  300. run: |
  301. # self-host test
  302. make -C littlefs-fuse
  303. littlefs-fuse/lfs --format /dev/loop0
  304. littlefs-fuse/lfs /dev/loop0 mount
  305. ls mount
  306. mkdir mount/littlefs
  307. cp -r $(git ls-tree --name-only HEAD) mount/littlefs
  308. cd mount/littlefs
  309. stat .
  310. ls -flh
  311. make -B test
  312. # test migration using littlefs-fuse
  313. migrate:
  314. runs-on: ubuntu-latest
  315. if: "!endsWith(github.ref, '-prefix')"
  316. steps:
  317. - uses: actions/checkout@v2
  318. - name: install
  319. run: |
  320. # need toml, also pip3 isn't installed by default?
  321. sudo apt-get update -qq
  322. sudo apt-get install -qq python3 python3-pip libfuse-dev
  323. sudo pip3 install toml
  324. fusermount -V
  325. gcc --version
  326. - uses: actions/checkout@v2
  327. with:
  328. repository: littlefs-project/littlefs-fuse
  329. ref: v2
  330. path: v2
  331. - uses: actions/checkout@v2
  332. with:
  333. repository: littlefs-project/littlefs-fuse
  334. ref: v1
  335. path: v1
  336. - name: setup
  337. run: |
  338. # copy our new version into littlefs-fuse
  339. rm -rf v2/littlefs/*
  340. cp -r $(git ls-tree --name-only HEAD) v2/littlefs
  341. # setup disk for littlefs-fuse
  342. mkdir mount
  343. sudo chmod a+rw /dev/loop0
  344. dd if=/dev/zero bs=512 count=128K of=disk
  345. losetup /dev/loop0 disk
  346. - name: test
  347. run: |
  348. # compile v1 and v2
  349. make -C v1
  350. make -C v2
  351. # run self-host test with v1
  352. v1/lfs --format /dev/loop0
  353. v1/lfs /dev/loop0 mount
  354. ls mount
  355. mkdir mount/littlefs
  356. cp -r $(git ls-tree --name-only HEAD) mount/littlefs
  357. cd mount/littlefs
  358. stat .
  359. ls -flh
  360. make -B test
  361. # attempt to migrate
  362. cd ../..
  363. fusermount -u mount
  364. v2/lfs --migrate /dev/loop0
  365. v2/lfs /dev/loop0 mount
  366. # run self-host test with v2 right where we left off
  367. ls mount
  368. cd mount/littlefs
  369. stat .
  370. ls -flh
  371. make -B test
  372. # collect coverage info
  373. coverage:
  374. runs-on: ubuntu-latest
  375. needs: [test]
  376. continue-on-error: true
  377. steps:
  378. - uses: actions/checkout@v2
  379. - name: install
  380. run: |
  381. sudo apt-get update -qq
  382. sudo apt-get install -qq python3 python3-pip lcov
  383. sudo pip3 install toml
  384. # yes we continue-on-error on every step, continue-on-error
  385. # at job level apparently still marks a job as failed, which isn't
  386. # what we want
  387. - uses: actions/download-artifact@v2
  388. continue-on-error: true
  389. with:
  390. name: coverage
  391. path: coverage
  392. - name: results-coverage
  393. continue-on-error: true
  394. run: |
  395. mkdir -p results
  396. lcov $(for f in coverage/*.info ; do echo "-a $f" ; done) \
  397. -o results/coverage.info
  398. ./scripts/coverage.py results/coverage.info -o results/coverage.csv
  399. - name: upload-results
  400. uses: actions/upload-artifact@v2
  401. continue-on-error: true
  402. with:
  403. name: results
  404. path: results
  405. - name: collect-status
  406. continue-on-error: true
  407. run: |
  408. mkdir -p status
  409. [ -e results/coverage.csv ] || exit 0
  410. export STEP="results-coverage"
  411. export CONTEXT="results / coverage"
  412. export PREV="$(curl -sS \
  413. "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master" \
  414. | jq -re "select(.sha != env.GITHUB_SHA) | .statuses[]
  415. | select(.context == env.CONTEXT).description
  416. | capture(\"Coverage is (?<result>[0-9\\\\.]+)\").result" \
  417. || echo 0)"
  418. export DESCRIPTION="$(
  419. ./scripts/coverage.py -u results/coverage.csv -s \
  420. | awk -F '[ /%]+' '
  421. NR==2 {printf "Coverage is %.1f%% of %d lines",$4,$3}
  422. NR==2 && ENVIRON["PREV"] != 0 {
  423. printf " (%+.1f%%)",$4-ENVIRON["PREV"]}')"
  424. jq -n '{
  425. state: "success",
  426. context: env.CONTEXT,
  427. description: env.DESCRIPTION,
  428. target_job: "${{github.job}}",
  429. target_step: env.STEP}' \
  430. | tee status/coverage.json
  431. - name: upload-status
  432. uses: actions/upload-artifact@v2
  433. continue-on-error: true
  434. with:
  435. name: status
  436. path: status
  437. retention-days: 1