test.yml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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. # upload coveragefor later coverage
  132. - name: upload-coverage
  133. continue-on-error: true
  134. uses: actions/upload-artifact@v2
  135. with:
  136. name: coverage
  137. path: coverage
  138. retention-days: 1
  139. # update results
  140. - name: results-code
  141. continue-on-error: true
  142. run: |
  143. mkdir -p results
  144. make clean
  145. make code \
  146. CFLAGS+=" \
  147. -DLFS_NO_ASSERT \
  148. -DLFS_NO_DEBUG \
  149. -DLFS_NO_WARN \
  150. -DLFS_NO_ERROR" \
  151. CODEFLAGS+="-o results/code-${{matrix.arch}}.csv"
  152. - name: results-code-readonly
  153. continue-on-error: true
  154. run: |
  155. mkdir -p results
  156. make clean
  157. make code \
  158. CFLAGS+=" \
  159. -DLFS_NO_ASSERT \
  160. -DLFS_NO_DEBUG \
  161. -DLFS_NO_WARN \
  162. -DLFS_NO_ERROR \
  163. -DLFS_READONLY" \
  164. CODEFLAGS+="-o results/code-${{matrix.arch}}-readonly.csv"
  165. - name: results-code-threadsafe
  166. continue-on-error: true
  167. run: |
  168. mkdir -p results
  169. make clean
  170. make code \
  171. CFLAGS+=" \
  172. -DLFS_NO_ASSERT \
  173. -DLFS_NO_DEBUG \
  174. -DLFS_NO_WARN \
  175. -DLFS_NO_ERROR \
  176. -DLFS_THREADSAFE" \
  177. CODEFLAGS+="-o results/code-${{matrix.arch}}-threadsafe.csv"
  178. - name: results-code-migrate
  179. continue-on-error: true
  180. run: |
  181. mkdir -p results
  182. make clean
  183. make code \
  184. CFLAGS+=" \
  185. -DLFS_NO_ASSERT \
  186. -DLFS_NO_DEBUG \
  187. -DLFS_NO_WARN \
  188. -DLFS_NO_ERROR \
  189. -DLFS_MIGRATE" \
  190. CODEFLAGS+="-o results/code-${{matrix.arch}}-migrate.csv"
  191. - name: upload-results
  192. continue-on-error: true
  193. uses: actions/upload-artifact@v2
  194. with:
  195. name: results
  196. path: results
  197. # limit reporting to Thumb, otherwise there would be too many numbers
  198. # flying around for the results to be easily readable
  199. - name: collect-status
  200. continue-on-error: true
  201. if: matrix.arch == 'thumb'
  202. run: |
  203. mkdir -p status
  204. for f in results/code*.csv
  205. do
  206. [ -e "$f" ] || continue
  207. export STEP="results-code$(
  208. echo $f | sed -n 's/.*code-.*-\(.*\).csv/-\1/p')"
  209. export CONTEXT="results / code$(
  210. echo $f | sed -n 's/.*code-.*-\(.*\).csv/ (\1)/p')"
  211. export PREV="$(curl -sS \
  212. "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master" \
  213. | jq -re "select(.sha != env.GITHUB_SHA) | .statuses[]
  214. | select(.context == env.CONTEXT).description
  215. | capture(\"Code size is (?<result>[0-9]+)\").result" \
  216. || echo 0)"
  217. echo $PREV
  218. export DESCRIPTION="$(./scripts/code.py -u $f -s | awk '
  219. NR==2 {printf "Code size is %d B",$2}
  220. NR==2 && ENVIRON["PREV"] != 0 {
  221. printf " (%+.1f%%)",100*($2-ENVIRON["PREV"])/$2}')"
  222. jq -n '{
  223. state: "success",
  224. context: env.CONTEXT,
  225. description: env.DESCRIPTION,
  226. target_job: "${{github.job}} (${{matrix.arch}})",
  227. target_step: env.STEP}' \
  228. | tee status/code$(
  229. echo $f | sed -n 's/.*code-.*-\(.*\).csv/-\1/p').json
  230. done
  231. - name: upload-status
  232. continue-on-error: true
  233. if: matrix.arch == 'thumb'
  234. uses: actions/upload-artifact@v2
  235. with:
  236. name: status
  237. path: status
  238. retention-days: 1
  239. # run under Valgrind to check for memory errors
  240. valgrind:
  241. runs-on: ubuntu-latest
  242. steps:
  243. - uses: actions/checkout@v2
  244. - name: install
  245. run: |
  246. # need toml, also pip3 isn't installed by default?
  247. sudo apt-get update -qq
  248. sudo apt-get install -qq python3 python3-pip
  249. sudo pip3 install toml
  250. - name: install-valgrind
  251. run: |
  252. sudo apt-get update -qq
  253. sudo apt-get install -qq valgrind
  254. valgrind --version
  255. # # normal tests, we don't need to test all geometries
  256. # - name: test-valgrind
  257. # run: make test TESTFLAGS+="-k --valgrind"
  258. # self-host with littlefs-fuse for a fuzz-like test
  259. fuse:
  260. runs-on: ubuntu-latest
  261. if: "!endsWith(github.ref, '-prefix')"
  262. steps:
  263. - uses: actions/checkout@v2
  264. - name: install
  265. run: |
  266. # need toml, also pip3 isn't installed by default?
  267. sudo apt-get update -qq
  268. sudo apt-get install -qq python3 python3-pip libfuse-dev
  269. sudo pip3 install toml
  270. fusermount -V
  271. gcc --version
  272. - uses: actions/checkout@v2
  273. with:
  274. repository: littlefs-project/littlefs-fuse
  275. ref: v2
  276. path: littlefs-fuse
  277. - name: setup
  278. run: |
  279. # copy our new version into littlefs-fuse
  280. rm -rf littlefs-fuse/littlefs/*
  281. cp -r $(git ls-tree --name-only HEAD) littlefs-fuse/littlefs
  282. # setup disk for littlefs-fuse
  283. mkdir mount
  284. sudo chmod a+rw /dev/loop0
  285. dd if=/dev/zero bs=512 count=128K of=disk
  286. losetup /dev/loop0 disk
  287. - name: test
  288. run: |
  289. # self-host test
  290. make -C littlefs-fuse
  291. littlefs-fuse/lfs --format /dev/loop0
  292. littlefs-fuse/lfs /dev/loop0 mount
  293. ls mount
  294. mkdir mount/littlefs
  295. cp -r $(git ls-tree --name-only HEAD) mount/littlefs
  296. cd mount/littlefs
  297. stat .
  298. ls -flh
  299. make -B test
  300. # test migration using littlefs-fuse
  301. migrate:
  302. runs-on: ubuntu-latest
  303. if: "!endsWith(github.ref, '-prefix')"
  304. steps:
  305. - uses: actions/checkout@v2
  306. - name: install
  307. run: |
  308. # need toml, also pip3 isn't installed by default?
  309. sudo apt-get update -qq
  310. sudo apt-get install -qq python3 python3-pip libfuse-dev
  311. sudo pip3 install toml
  312. fusermount -V
  313. gcc --version
  314. - uses: actions/checkout@v2
  315. with:
  316. repository: littlefs-project/littlefs-fuse
  317. ref: v2
  318. path: v2
  319. - uses: actions/checkout@v2
  320. with:
  321. repository: littlefs-project/littlefs-fuse
  322. ref: v1
  323. path: v1
  324. - name: setup
  325. run: |
  326. # copy our new version into littlefs-fuse
  327. rm -rf v2/littlefs/*
  328. cp -r $(git ls-tree --name-only HEAD) v2/littlefs
  329. # setup disk for littlefs-fuse
  330. mkdir mount
  331. sudo chmod a+rw /dev/loop0
  332. dd if=/dev/zero bs=512 count=128K of=disk
  333. losetup /dev/loop0 disk
  334. - name: test
  335. run: |
  336. # compile v1 and v2
  337. make -C v1
  338. make -C v2
  339. # run self-host test with v1
  340. v1/lfs --format /dev/loop0
  341. v1/lfs /dev/loop0 mount
  342. ls mount
  343. mkdir mount/littlefs
  344. cp -r $(git ls-tree --name-only HEAD) mount/littlefs
  345. cd mount/littlefs
  346. stat .
  347. ls -flh
  348. make -B test
  349. # attempt to migrate
  350. cd ../..
  351. fusermount -u mount
  352. v2/lfs --migrate /dev/loop0
  353. v2/lfs /dev/loop0 mount
  354. # run self-host test with v2 right where we left off
  355. ls mount
  356. cd mount/littlefs
  357. stat .
  358. ls -flh
  359. make -B test
  360. # collect coverage info
  361. coverage:
  362. runs-on: ubuntu-latest
  363. needs: [test]
  364. continue-on-error: true
  365. steps:
  366. - uses: actions/checkout@v2
  367. - name: install
  368. run: |
  369. sudo apt-get update -qq
  370. sudo apt-get install -qq python3 python3-pip lcov
  371. sudo pip3 install toml
  372. # yes we continue-on-error on every step, continue-on-error
  373. # at job level apparently still marks a job as failed, which isn't
  374. # what we want
  375. - uses: actions/download-artifact@v2
  376. continue-on-error: true
  377. with:
  378. name: coverage
  379. path: coverage
  380. - name: results-coverage
  381. continue-on-error: true
  382. run: |
  383. mkdir -p results
  384. lcov $(for f in coverage/*.info ; do echo "-a $f" ; done) \
  385. -o results/coverage.info
  386. ./scripts/coverage.py results/coverage.info -o results/coverage.csv
  387. - name: upload-results
  388. uses: actions/upload-artifact@v2
  389. continue-on-error: true
  390. with:
  391. name: results
  392. path: results
  393. - name: collect-status
  394. continue-on-error: true
  395. run: |
  396. mkdir -p status
  397. [ -e results/coverage.csv ] || exit 0
  398. export STEP="results-coverage"
  399. export CONTEXT="results / coverage"
  400. export PREV="$(curl -sS \
  401. "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/status/master" \
  402. | jq -re "select(.sha != env.GITHUB_SHA) | .statuses[]
  403. | select(.context == env.CONTEXT).description
  404. | capture(\"Coverage is (?<result>[0-9\\\\.]+)\").result" \
  405. || echo 0)"
  406. export DESCRIPTION="$(
  407. ./scripts/coverage.py -u results/coverage.csv -s \
  408. | awk -F '[ /%]+' '
  409. NR==2 {printf "Coverage is %.1f%% of %d lines",$4,$3}
  410. NR==2 && ENVIRON["PREV"] != 0 {
  411. printf " (%+.1f%%)",$4-ENVIRON["PREV"]}')"
  412. jq -n '{
  413. state: "success",
  414. context: env.CONTEXT,
  415. description: env.DESCRIPTION,
  416. target_job: "${{github.job}}",
  417. target_step: env.STEP}' \
  418. | tee status/coverage.json
  419. - name: upload-status
  420. uses: actions/upload-artifact@v2
  421. continue-on-error: true
  422. with:
  423. name: status
  424. path: status
  425. retention-days: 1