From b9c1d18fa655d4a741f7706df69c2d58b971402c Mon Sep 17 00:00:00 2001 From: Oleg Jukovec Date: Thu, 8 Jun 2023 15:30:30 +0300 Subject: [PATCH 1/2] ci: add GitHub Actions CI The patch adds CI for GitHub Actions and updates flaky tests. Part of #53 Closes #18 --- .github/workflows/tests.yml | 55 ++++++++++++++++++++++++++++++++ .gitlab-ci.yml | 57 --------------------------------- Makefile | 63 +++++++++++++++++++++++++++++-------- README.md | 4 +-- deps.sh | 8 ----- 5 files changed, 107 insertions(+), 80 deletions(-) create mode 100644 .github/workflows/tests.yml delete mode 100644 .gitlab-ci.yml delete mode 100755 deps.sh diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..08799d1 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,55 @@ +name: tests + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + linux: + # We want to run on external PRs, but not on our own internal + # PRs as they'll be run by the push to the branch. + # + # The main trick is described here: + # https://github.com/Dart-Code/Dart-Code/pull/2375 + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + + strategy: + fail-fast: false + matrix: + tarantool: + - '1.10' + - '2.8' + coveralls: [false] + include: + - tarantool: '2.11' + coveralls: true + + runs-on: ubuntu-20.04 + steps: + - name: Install tarantool ${{ matrix.tarantool }} + uses: tarantool/setup-tarantool@v2 + with: + tarantool-version: ${{ matrix.tarantool }} + + - name: Clone the module + uses: actions/checkout@v3 + + - name: Install requirements + run: make deps + + - name: Run linter + run: make lint + + - name: Run tests + run: make test + + - name: Run tests with coverage + run: make coverage + if: ${{ matrix.coveralls }} + + - name: Send code coverage to coveralls.io + run: .rocks/bin/luacov-coveralls -i sharded_queue + if: ${{ matrix.coveralls }} + env: + COVERALLS_REPO_TOKEN: ${{ github.token }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 808dfec..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,57 +0,0 @@ -stages: - - build - - publish - -variables: - DOWNLOAD_ENDPOINT: download.tarantool.io/enterprise - BUNDLE_VERSION: 1.10.4-24-ge72123b - ROCK_NAME: sharded-queue - -build: - stage: build - artifacts: - name: "$CI_COMMIT_REF_NAME" - paths: - - ./release/*all.rock - tags: - - docker - image: centos:7 - before_script: - - yum -y install epel-release && yum -y update && yum -y install wget git cmake make unzip gcc - - wget https://tarantool:${DOWNLOAD_TOKEN}@download.tarantool.io/enterprise/tarantool-enterprise-bundle-${BUNDLE_VERSION}.tar.gz - - tar -zxf tarantool-enterprise-bundle-${BUNDLE_VERSION}.tar.gz --strip 1 - - source env.sh - script: - - make build - - make bootstrap - - make test - - ./release.sh - -### -### Publish rocks -### -publish-scm-1: - stage: publish - tags: - - docker - image: centos:7 - only: - - master - script: - - curl --fail -X PUT -F "rockspec=@${ROCK_NAME}-scm-1.rockspec" - https://${ROCKS_USERNAME}:${ROCKS_PASSWORD}@rocks.tarantool.org - -publish-release: - stage: publish - tags: - - docker - image: centos:7 - only: - - tags - script: - - cd release/ - - curl --fail -X PUT -F "rockspec=@${ROCK_NAME}-${CI_COMMIT_TAG}-1.rockspec" - https://${ROCKS_USERNAME}:${ROCKS_PASSWORD}@rocks.tarantool.org - - curl --fail -X PUT -F "rockspec=@${ROCK_NAME}-${CI_COMMIT_TAG}-1.all.rock" - https://${ROCKS_USERNAME}:${ROCKS_PASSWORD}@rocks.tarantool.org - diff --git a/Makefile b/Makefile index b58424c..bcbf8b2 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,62 @@ -#! /bin/bash +# This way everything works as expected ever for +# `make -C /path/to/project` or +# `make -f /path/to/project/Makefile`. +MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +PROJECT_DIR := $(patsubst %/,%,$(dir $(MAKEFILE_PATH))) +LUACOV_REPORT := $(PROJECT_DIR)/luacov.report.out -.PHONY: all doc -all: doc - mkdir -p doc +# Look for .rocks/bin directories upward starting from the project +# directory. +# +# It is useful for luacheck, luatest and LDoc. +# +# Note: The PROJECT_DIR holds a real path. +define ENABLE_ROCKS_BIN + $(if $(wildcard $1/.rocks/bin), + $(eval ROCKS_PATH := $(if $(ROCKS_PATH),$(ROCKS_PATH):,)$1/.rocks/bin) + ) + $(if $1, + $(eval $(call ENABLE_ROCKS_BIN,$(patsubst %/,%,$(dir $1)))) + ) +endef +$(eval $(call ENABLE_ROCKS_BIN,$(PROJECT_DIR))) -.PHONY: bootstrap -bootstrap: - tarantoolctl rocks install luacheck 0.25.0 - tarantoolctl rocks install luatest 0.5.0 - tarantoolctl rocks install luacov 0.13.0 +# Add found .rocks/bin to PATH. +PATH := $(if $(ROCKS_PATH),$(ROCKS_PATH):$(PATH),$(PATH)) + +TTCTL := tt +ifeq (,$(shell which tt 2>/dev/null)) + TTCTL := tarantoolctl +endif + +.PHONY: default +default: + false .PHONY: build build: cartridge build +.PHONY: deps +deps: + $(TTCTL) rocks install luacheck 0.26.0 + $(TTCTL) rocks install luacov 0.13.0 + $(TTCTL) rocks install luacov-coveralls 0.2.3-1 --server=http://luarocks.org + $(TTCTL) rocks install luatest 0.5.7 + $(TTCTL) rocks install cartridge 2.7.9 + .PHONY: lint lint: - .rocks/bin/luacheck . + luacheck . .PHONY: test -test: lint +test: + luatest -v --shuffle all + +.PHONY: coverage +coverage: rm -f luacov* - .rocks/bin/luatest -v --shuffle all --coverage - .rocks/bin/luacov . && grep -A999 '^Summary' luacov.report.out + luatest -v --shuffle all --coverage + sed "s|$(PROJECT_DIR)/||" -i luacov.stats.out + luacov sharded_queue + grep -A999 '^Summary' $(LUACOV_REPORT) diff --git a/README.md b/README.md index 79f8db0..578c9c8 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ rm -rf ./tmp Say: ``` -make bootstrap +make deps make test ``` @@ -116,7 +116,7 @@ make test Examples: ```lua - conn:call('queue.create_tube', { mytube, { + conn:call('queue.create_tube', { mytube, { log_request = true, -- log all operations }}) diff --git a/deps.sh b/deps.sh deleted file mode 100755 index 51e1a89..0000000 --- a/deps.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -set -e - -tarantoolctl rocks install ldecnumber 1.1.3-1 -tarantoolctl rocks install metrics 0.1.3-1 -tarantoolctl rocks install cluster 0.9.2-1 -tarantoolctl rocks install space-explorer 1.0.2-1 From 6bd16f827461aa55de1ea081ad80f8d3d6ac8731 Mon Sep 17 00:00:00 2001 From: Oleg Jukovec Date: Thu, 8 Jun 2023 15:32:59 +0300 Subject: [PATCH 2/2] test: fix flaky tests Closes #53 --- test/entrypoint/init.lua | 14 ++++ test/helper/config.lua | 20 +++-- test/statistics_test.lua | 2 +- test/take_exp_backoff_test.lua | 130 +++++++++++++++++---------------- 4 files changed, 94 insertions(+), 72 deletions(-) create mode 100755 test/entrypoint/init.lua diff --git a/test/entrypoint/init.lua b/test/entrypoint/init.lua new file mode 100755 index 0000000..accc453 --- /dev/null +++ b/test/entrypoint/init.lua @@ -0,0 +1,14 @@ +#!/usr/bin/env tarantool + +local cartridge = require('cartridge') + +local ok, err = cartridge.cfg({ + bucket_count = 3000, + roles = { + 'sharded_queue.storage', + 'sharded_queue.api' + }, +}, { +}) + +assert(ok, tostring(err)) diff --git a/test/helper/config.lua b/test/helper/config.lua index 5707e6e..fec4c82 100644 --- a/test/helper/config.lua +++ b/test/helper/config.lua @@ -12,7 +12,7 @@ config.unitdir = fio.pathjoin(config.datadir, 'unit') config.cluster = cartridge_helpers.Cluster:new({ datadir = config.datadir, - server_command = fio.pathjoin(config.root, 'init.lua'), + server_command = fio.pathjoin(config.root, 'test', 'entrypoint', 'init.lua'), use_vshard = true, replicasets = { { @@ -24,13 +24,15 @@ config.cluster = cartridge_helpers.Cluster:new({ { instance_uuid = 'aaaaaaaa-aaaa-4000-b000-000000000001', alias = 'queue-router', - advertise_port = 3301, + advertise_port = 3311, + http_port = 9081, cluster_cookie = 'sharded-queue-cookie', }, { instance_uuid = 'aaaaaaaa-aaaa-4000-b000-000000000002', alias = 'queue-router-1', - advertise_port = 3302, + advertise_port = 3312, + http_port = 9082, cluster_cookie = 'sharded-queue-cookie', } }, @@ -44,13 +46,15 @@ config.cluster = cartridge_helpers.Cluster:new({ { instance_uuid = 'bbbbbbbb-bbbb-4000-b000-000000000001', alias = 'queue-storage-1-0', - advertise_port = 3303, + advertise_port = 3313, + http_port = 9083, cluster_cookie = 'sharded-queue-cookie', }, { instance_uuid = 'bbbbbbbb-bbbb-4000-b000-000000000002', alias = 'queue-storage-1-1', - advertise_port = 3304, + advertise_port = 3314, + http_port = 9084, cluster_cookie = 'sharded-queue-cookie', }, } @@ -62,13 +66,15 @@ config.cluster = cartridge_helpers.Cluster:new({ { instance_uuid = 'cccccccc-cccc-4000-b000-000000000001', alias = 'queue-storage-2-0', - advertise_port = 3305, + advertise_port = 3315, + http_port = 9085, cluster_cookie = 'sharded-queue-cookie', }, { instance_uuid = 'cccccccc-cccc-4000-b000-000000000002', alias = 'queue-storage-2-1', - advertise_port = 3306, + advertise_port = 3316, + http_port = 9086, cluster_cookie = 'sharded-queue-cookie', }, }, diff --git a/test/statistics_test.lua b/test/statistics_test.lua index ed027ec..30d81f8 100644 --- a/test/statistics_test.lua +++ b/test/statistics_test.lua @@ -40,7 +40,7 @@ function g.test_statistics() t.assert_equals(cur_stat.tasks.delayed, task_count) t.assert_equals(cur_stat.calls.put, task_count) - fiber.sleep(3.01) + fiber.sleep(3.5) -- after delay cur_stat = g.queue_conn:call('queue.statistics', { tube_name }) diff --git a/test/take_exp_backoff_test.lua b/test/take_exp_backoff_test.lua index 6312ccf..b910171 100644 --- a/test/take_exp_backoff_test.lua +++ b/test/take_exp_backoff_test.lua @@ -16,15 +16,12 @@ g.before_all(function() end) local function task_take(tube_name, timeout, channel, options) - -- fiber function for take task with timeout and calc duration time - local start = fiber.time64() + -- fiber function for take task with timeout and finish time local task = g.queue_conn:call(utils.shape_cmd(tube_name, 'take'), { timeout, options }) - local duration = fiber.time64() - start - channel:put(duration) + channel:put(fiber.time64()) channel:put(task) end --- function g.test_default_wait_factor() local tube_name = 'test_default_wait_factor' @@ -32,27 +29,27 @@ function g.test_default_wait_factor() tube_name }) - local timeout = 3 -- second - local attemts = 7 -- attempts count - local put_wait = 0.01*(math.pow(2, attemts) - 1) -- 1.27 - local take_time_expected = 0.01*(math.pow(2, attemts+1) - 1) -- 2.55 + local timeout = 10 -- second + local attemts = 8 -- attempts count + local put_wait = 0.01*(math.pow(2, attemts) - 1) -- 2.55 + local take_time_expected = 0.01*(math.pow(2, attemts+1) - 1) -- 5.12 local channel = fiber.channel(2) + local start = fiber.time64() fiber.create(task_take, tube_name, timeout, channel) - fiber.sleep(put_wait + 0.2) + fiber.sleep(put_wait + 1) - t.assert(g.queue_conn:call(utils.shape_cmd(tube_name, 'put'), { 'simple_task' }, {timeout=0.5})) + t.assert(g.queue_conn:call(utils.shape_cmd(tube_name, 'put'), { 'simple_task' }, {timeout=5})) - local waiting_time = tonumber(channel:get()) / 1e6 + local waiting_time = tonumber(channel:get() - start) / 1e6 local task = channel:get() - t.assert_almost_equals(waiting_time, take_time_expected, 0.1) + t.assert_almost_equals(waiting_time, take_time_expected, 0.75) t.assert_equals(task[utils.index.data], 'simple_task') channel:close() end --- function g.test_success() -- start taking @@ -60,7 +57,7 @@ function g.test_success() -- 0.01 : take fail => wait 0.05 -- 0.06 : take fail => wait 0.25 -- 0.31 : take fail => wait 1.25 - -- 0.35 : put task + -- 1 : put task -- 1.56 : take success -- expected time is 1.56 in case wait_factor = 5 @@ -72,18 +69,19 @@ function g.test_success() } }) - local timeout = 7 + local timeout = 10 local channel = fiber.channel(2) + local start = fiber.time64() fiber.create(task_take, tube_name, timeout, channel) fiber.sleep(1) - t.assert(g.queue_conn:call(utils.shape_cmd(tube_name, 'put'), { 'simple_task' }, {timeout=1})) + t.assert(g.queue_conn:call(utils.shape_cmd(tube_name, 'put'), { 'simple_task' }, {timeout=5})) - local waiting_time = tonumber(channel:get()) / 1e6 + local waiting_time = tonumber(channel:get() - start) / 1e6 local task = channel:get() - t.assert_almost_equals(waiting_time, 1.56, 0.1) + t.assert_almost_equals(waiting_time, 1.56, 0.75) t.assert_equals(task[utils.index.data], 'simple_task') channel:close() @@ -139,50 +137,50 @@ function g.test_invalid_wait_max() }) end - function g.test_invalid_wait_max_on_take() - -- wait_max = 0.3 + -- wait_max = 1 -- start taking -- 0.00 : take fail => wait 0.01 (see wait_part in api.lua) -- 0.01 : take fail => wait 0.05 -- 0.06 : take fail => wait 0.25 - -- 0.31 : take fail => wait min(1.25, 0.3) = 0.3 - -- 0.61 : take fail => wait 0.3 - -- 0.91 : take fail => wait 0.3 - -- 1.00 : put task - -- 1.21 : take success - -- expected time is 1.56 in case wait_factor = 5 + -- 0.31 : take fail => wait min(1.25, 1) = 1 + -- 1.31 : take fail => wait 1 + -- 2.31 : take fail => wait 1 + -- 2.8 : put task + -- 3.31 : take success + -- expected time is 3.31 in case wait_factor = 5 local tube_name = 'test_invalid_wait_max_on_take' g.queue_conn:call('queue.create_tube', { tube_name, { wait_factor = 5, - wait_max = 0.3, + wait_max = 1, } }) - local timeout = 7 + local timeout = 10 local channel = fiber.channel(2) + local start = fiber.time64() fiber.create(task_take, tube_name, timeout, channel, { wait_max = -10, -- invalid wait_factor, using 0.3 }) - fiber.sleep(1) - t.assert(g.queue_conn:call(utils.shape_cmd(tube_name, 'put'), { 'simple_task' }, {timeout=1})) + fiber.sleep(2.8) + t.assert(g.queue_conn:call(utils.shape_cmd(tube_name, 'put'), { 'simple_task' }, {timeout=5})) - local waiting_time = tonumber(channel:get()) / 1e6 + local waiting_time = tonumber(channel:get() - start) / 1e6 local task = channel:get() - t.assert_almost_equals(waiting_time, 1.21, 0.1) + t.assert_almost_equals(waiting_time, 3.31, 0.75) t.assert_equals(task[utils.index.data], 'simple_task') channel:close() end function g.test_wait_max_on_tube() - -- wait_max = 0.3 + -- wait_max = 1 -- wait_factor = 2 (default value) -- start taking -- 0.00 : take fail => wait 0.01 (see wait_part in api.lua) @@ -190,41 +188,42 @@ function g.test_wait_max_on_tube() -- 0.03 : take fail => wait 0.04 -- 0.07 : take fail => wait 0.08 -- 0.15 : take fail => wait 0.16 - -- 0.31 : take fail => wait 0.30 (because 0.32 > 0.30) - -- 0.61 : take fail => wait 0.30 - -- ~ 0.80 : put task with ttl = 0.30 - -- 0.91 : take successful - -- expected time is 0.91 - - local tube_name = 'test_wait_max_tube' + -- 0.31 : take fail => wait 0.32 + -- 0.63 : take fail => wait 0.64 + -- 1.27 : take fail => wait 1 + -- 2.27 : take fail => wait 1 + -- ~2.8 : put task with ttl = 1 + -- 3.27 : take successful + -- expected time is 3.27 + + local tube_name = 'test_wait_max_on_take_tube' g.queue_conn:call('queue.create_tube', { tube_name, { - wait_factor = 2, - wait_max = 0.3, + wait_max = 1, } }) - local timeout = 2 + local timeout = 10 local channel = fiber.channel(2) + local start = fiber.time64() fiber.create(task_take, tube_name, timeout, channel) - fiber.sleep(0.8) + fiber.sleep(2.8) t.assert(g.queue_conn:call(utils.shape_cmd(tube_name, 'put'), - { 'simple_task' }, {timeout=0.3})) + { 'simple_task' }, {timeout=5})) - local waiting_time = tonumber(channel:get()) / 1e6 + local waiting_time = tonumber(channel:get() - start) / 1e6 local task = channel:get() - t.assert_almost_equals(waiting_time, 0.91, 0.1) + t.assert_almost_equals(waiting_time, 3.27, 0.75) t.assert_equals(task[utils.index.data], 'simple_task') channel:close() end - function g.test_wait_max_in_take() - -- wait_max = 0.3 + -- wait_max = 1 -- wait_factor = 2 (default value) -- start taking -- 0.00 : take fail => wait 0.01 (see wait_part in api.lua) @@ -232,13 +231,15 @@ function g.test_wait_max_in_take() -- 0.03 : take fail => wait 0.04 -- 0.07 : take fail => wait 0.08 -- 0.15 : take fail => wait 0.16 - -- 0.31 : take fail => wait 0.30 (because 0.32 > 0.30) - -- 0.61 : take fail => wait 0.30 - -- ~ 0.80 : put task with ttl = 0.30 - -- 0.91 : take successful - -- expected time is 0.91 - - local tube_name = 'test_wait_max_tube' + -- 0.31 : take fail => wait 0.32 + -- 0.63 : take fail => wait 0.64 + -- 1.27 : take fail => wait 1 + -- 2.27 : take fail => wait 1 + -- ~2.8 : put task with ttl = 1 + -- 3.27 : take successful + -- expected time is 3.27 + + local tube_name = 'test_wait_max_in_take_tube' g.queue_conn:call('queue.create_tube', { tube_name, { @@ -247,19 +248,20 @@ function g.test_wait_max_in_take() } }) - local timeout = 2 + local timeout = 10 local channel = fiber.channel(2) - fiber.create(task_take, tube_name, timeout, channel, {wait_max = 0.3}) + local start = fiber.time64() + fiber.create(task_take, tube_name, timeout, channel, {wait_max = 1.0}) - fiber.sleep(0.8) + fiber.sleep(2.8) t.assert(g.queue_conn:call(utils.shape_cmd(tube_name, 'put'), - { 'simple_task' }, {timeout=0.3})) + { 'simple_task' }, {timeout=5})) - local waiting_time = tonumber(channel:get()) / 1e6 + local waiting_time = tonumber(channel:get() - start) / 1e6 local task = channel:get() - t.assert_almost_equals(waiting_time, 0.91, 0.1) + t.assert_almost_equals(waiting_time, 3.27, 0.75) t.assert_equals(task[utils.index.data], 'simple_task') channel:close() -end \ No newline at end of file +end