test.yml 14 KB

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