From 472f891a044c621437ffaeec1b9119f2f6827679 Mon Sep 17 00:00:00 2001 From: Matt Decker Date: Sun, 26 Jun 2022 09:17:49 -0500 Subject: [PATCH] Delete plpgsql directory --- plpgsql/Dockerfile | 45 ---------- plpgsql/README.md | 63 -------------- plpgsql/docker-compose.yml | 22 ----- plpgsql/initializeDatabase.sh | 13 --- plpgsql/initializeDocker.sh | 26 ------ plpgsql/pgtap/initialize.sh | 6 -- plpgsql/pgtap/test_case_update_quality.sql | 18 ---- plpgsql/pgunit/asserts.sql | 59 -------------- plpgsql/pgunit/asserts_tests.sql | 95 ---------------------- plpgsql/pgunit/initialize.sh | 14 ---- plpgsql/pgunit/run_tests.sql | 95 ---------------------- plpgsql/src/item.sql | 8 -- plpgsql/src/new_item.sql | 12 --- plpgsql/src/update_quality.sql | 72 ---------------- 14 files changed, 548 deletions(-) delete mode 100644 plpgsql/Dockerfile delete mode 100644 plpgsql/README.md delete mode 100644 plpgsql/docker-compose.yml delete mode 100644 plpgsql/initializeDatabase.sh delete mode 100644 plpgsql/initializeDocker.sh delete mode 100644 plpgsql/pgtap/initialize.sh delete mode 100644 plpgsql/pgtap/test_case_update_quality.sql delete mode 100644 plpgsql/pgunit/asserts.sql delete mode 100644 plpgsql/pgunit/asserts_tests.sql delete mode 100644 plpgsql/pgunit/initialize.sh delete mode 100644 plpgsql/pgunit/run_tests.sql delete mode 100644 plpgsql/src/item.sql delete mode 100644 plpgsql/src/new_item.sql delete mode 100644 plpgsql/src/update_quality.sql diff --git a/plpgsql/Dockerfile b/plpgsql/Dockerfile deleted file mode 100644 index d0f42b3b..00000000 --- a/plpgsql/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM postgres:12.1 as base -WORKDIR /app - -ENV PGHOST=localhost -ENV PGDATABASE=kata -ENV PGPASSWORD=admin -ENV PGUSER=postgres -ENV POSTGRES_PASSWORD=admin -ENV PGDATA /var/lib/postgresql/data_local - -RUN mkdir -p "$PGDATA" && chown -R postgres:postgres "$PGDATA" && chmod 777 "$PGDATA" - -ADD ./*.sh /app/ -ADD ./src/item.sql /app/src/ -ADD ./src/new_item.sql /app/src/ - -# PGUNIT -FROM base as pgunit - -RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates wget \ - && rm -rf /var/lib/apt/lists/* - -ADD ./pgunit/initialize.sh /app/ -ADD ./pgunit/*.sql /app/ -RUN chmod +x ./*.sh \ - && ./initializeDocker.sh - -# PGTAP -FROM base as pgtap - -RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates build-essential git-core libv8-dev curl postgresql-server-dev-12 \ - && rm -rf /var/lib/apt/lists/* - -RUN mkdir -p /tmp/pgtap \ - && cd /tmp/pgtap \ - && git clone https://github.com/theory/pgtap.git /tmp/pgtap \ - && make \ - && make install \ - && cpan TAP::Parser::SourceHandler::pgTAP - -ADD ./pgtap/initialize.sh /app/ -RUN chmod +x ./*.sh \ - && ./initializeDocker.sh diff --git a/plpgsql/README.md b/plpgsql/README.md deleted file mode 100644 index 93337289..00000000 --- a/plpgsql/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Requirements -You'll need: -- PostgreSQL database, version >= 11 because PROCEDURE keyword isn't supported before [version 11](https://www.postgresql.org/docs/11/release-11.html) -- OS user with local connection privilege to database on standard 5432 port - -To use remote / local dockerized database, add ``` --host --port --username``` parameters to plsql invocation. - -# Setup -## With docker -Run `docker-compose up -d ` to start, and `docker-compose exec bash` to enter in container. -`` is the testing framework name. Two values are possible: `pgunit` or `pgtap` - -## Without docker -In shell: -- create database: ```createdb kata``` -- create item table (structure): ```psql -d kata -f ./src/item.sql``` -- create procedure to help to add item: ```psql -d kata -f ./src/new_item.sql``` -- load code into database: ```psql -d kata -f ./src/update_quality.sql ``` - -If you get this message```LINE 1: CREATE OR REPLACE PROCEDURE public.update_quality()```, your PostgreSQL version may under 11, consider upgrading. - -# Run -In shell: -- connect to CLI: ```psql -d kata``` -- add item: ```CALL new_item('+5 Dexterity Vest', 10, 20);``` -- check item state: ```SELECT * FROM item;``` -- execute item update: ```CALL update_quality();``` -- check item state: ```SELECT * FROM item;``` -- empty table : ```TRUNCATE TABLE item;``` - -# Kata -`src/update_quality.sql` contains code to refactor. - -# Test - -## Using pgTAP -### Requirements -Install pgTAP [instructions here](https://pgtap.org/documentation.html#installation) -It's already installed with docker - -```item``` table is supposed to be empty. -If not, it would cause a (false positive)[https://en.wikipedia.org/wiki/False_positives_and_false_negatives] - -### Execute -Run `docker-compose up -d pgtap` to start, and `docker-compose exec pgtap bash` to enter in container. -In shell, execute ```psql -d kata -f src/update_quality.sql && pg_prove pgtap/test_*.sql```. -You should get ```pgtap/test_case_update_quality.sql .. ok All tests successful.``` - -If you get this message ```ERROR: function plan(integer) does not exist LINE 1: SELECT PLAN(1);```, pgTAP is not working => check your pgTAP installation. -If you get this message ```Failed test: 2 Parse errors: Bad plan. You planned 1 tests but ran 2.```, the item table contains data, interfering with the test => empty it, then run test again. - -`pgtap/test_case_update_quality.sql` contains test examples. - -## Using pgunit -### Requirement -Unit test framework used : pgunit (https://github.com/adrianandrei-ca/pgunit) -It's already installed with docker - -### Execute -Run `docker-compose up -d pgunit` to start, and `docker-compose exec pgunit bash` to enter in container. -You can run `cat src/update_quality.sql pgunit/run_tests.sql | psql -d kata -f -` - -`pgunit/run_tests.sql` contains test examples. diff --git a/plpgsql/docker-compose.yml b/plpgsql/docker-compose.yml deleted file mode 100644 index b753b164..00000000 --- a/plpgsql/docker-compose.yml +++ /dev/null @@ -1,22 +0,0 @@ -version: '3.4' - -services: - pgunit: - # image: fpellet/gildedrose-refactoring-kata:pgunit - build: - context: . - target: pgunit - ports: - - "5432:5432" - volumes: - - .:/app/:z - - pgtap: - # image: fpellet/gildedrose-refactoring-kata:pgtap - build: - context: . - target: pgtap - ports: - - "5432:5432" - volumes: - - .:/app/:z diff --git a/plpgsql/initializeDatabase.sh b/plpgsql/initializeDatabase.sh deleted file mode 100644 index 09b6202a..00000000 --- a/plpgsql/initializeDatabase.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -echo "Create database" -psql -d postgres -c 'DROP DATABASE IF EXISTS kata;' -psql -d postgres -c 'CREATE DATABASE kata;' - -./initialize.sh - -echo "Add current code" -psql -d kata -f src/item.sql -psql -d kata -f src/new_item.sql diff --git a/plpgsql/initializeDocker.sh b/plpgsql/initializeDocker.sh deleted file mode 100644 index e962623a..00000000 --- a/plpgsql/initializeDocker.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -wait_database() -{ - while : - do - (echo > /dev/tcp/127.0.0.1/5432) >/dev/null 2>&1 - result=$? - - if [[ $result -eq 0 ]]; then - break - fi - sleep 1 - done - return $result -} - -nohup docker-entrypoint.sh postgres > /dev/null 2>&1 & -wait_database - -set -ex - -./initializeDatabase.sh - -echo "Stop database" -disown %1 diff --git a/plpgsql/pgtap/initialize.sh b/plpgsql/pgtap/initialize.sh deleted file mode 100644 index 7646180d..00000000 --- a/plpgsql/pgtap/initialize.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -echo "Enable extension" -psql -d kata -c 'CREATE EXTENSION IF NOT EXISTS pgtap;' diff --git a/plpgsql/pgtap/test_case_update_quality.sql b/plpgsql/pgtap/test_case_update_quality.sql deleted file mode 100644 index 5d06a167..00000000 --- a/plpgsql/pgtap/test_case_update_quality.sql +++ /dev/null @@ -1,18 +0,0 @@ -BEGIN; --- Plan count should match the number of tests. If it does not then pg_prove will fail the test -SELECT plan(1); - --- Run the tests. --- Given -TRUNCATE TABLE item; -CALL new_item('foo', 0, 0); - --- When -CALL update_quality(); - --- Then -SELECT is( name, 'fixme', 'name did change' ) FROM item; - --- Finish the tests and clean up. -SELECT * FROM finish(); -ROLLBACK; diff --git a/plpgsql/pgunit/asserts.sql b/plpgsql/pgunit/asserts.sql deleted file mode 100644 index d51b5b6a..00000000 --- a/plpgsql/pgunit/asserts.sql +++ /dev/null @@ -1,59 +0,0 @@ -CREATE OR REPLACE FUNCTION test_assertEquals(message TEXT, expected ANYELEMENT, result ANYELEMENT) RETURNS VOID AS $$ -BEGIN - IF expected = result THEN - null; - ELSE - raise exception '%: expect ''%'' instead of ''%''', message, expected, result using errcode = 'triggered_action_exception'; - END IF; -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_assertEquals(expected ANYELEMENT, result ANYELEMENT) RETURNS VOID AS $$ -BEGIN - perform test_assertEquals('assertEquals failure', expected, result); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_assertEqualsArray(expected VARCHAR[], result VARCHAR[]) RETURNS VOID AS $$ -DECLARE - line RECORD; - error_message text; -BEGIN - IF expected = result THEN - null; - ELSE - error_message := 'assertEqualsArray failure:'; - FOR line IN SELECT expected_item, result_item FROM (SELECT unnest(expected) AS expected_item, unnest(result) AS result_item) x - LOOP - IF line.expected_item = line.result_item THEN - error_message := CONCAT(error_message, E'\n', '= ', line.expected_item); - ELSE - error_message := CONCAT(error_message, E'\n', '- ', line.expected_item); - error_message := CONCAT(error_message, E'\n', '+ ', line.result_item); - END IF; - END LOOP; - - raise exception '%', error_message using errcode = 'triggered_action_exception'; - END IF; -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_assertEquals_golden_master(expected VARCHAR[], result VARCHAR[]) RETURNS VOID as $$ -DECLARE - golden TEXT; - line VARCHAR; -BEGIN - perform test_assertEqualsArray(expected, result); -EXCEPTION - WHEN triggered_action_exception THEN - golden := CONCAT(SQLERRM, E'\n\n', E'For update, copy:\n'); - golden := CONCAT(golden, E'expected := ARRAY['); - FOREACH line IN ARRAY result - LOOP - golden := CONCAT(golden, E'\n', '''', line, ''','); - END LOOP; - golden := CONCAT(golden, E'\n', '];'); - - raise exception '%', golden using errcode = 'triggered_action_exception'; -END; -$$ LANGUAGE plpgsql; diff --git a/plpgsql/pgunit/asserts_tests.sql b/plpgsql/pgunit/asserts_tests.sql deleted file mode 100644 index 05cd77f1..00000000 --- a/plpgsql/pgunit/asserts_tests.sql +++ /dev/null @@ -1,95 +0,0 @@ -CREATE OR REPLACE FUNCTION test_case_assertEquals_numeric_should_fail_if_not_equals() RETURNS VOID AS $$ -DECLARE - expected_message VARCHAR; - error_message VARCHAR; - is_equals BOOLEAN; -BEGIN - BEGIN - perform test_assertEquals(7, 5); - EXCEPTION - WHEN triggered_action_exception THEN - expected_message := 'assertEquals failure: expect ''7'' instead of ''5'''; - error_message := SQLERRM; - perform test_assertTrue(format('Expect message ''%s'' instead of ''%s'' ', expected_message, error_message), error_message = expected_message); - END; -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_case_assertEquals_numeric_should_success_if_equals() RETURNS VOID AS $$ -BEGIN - perform test_assertEquals(7, 7); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_case_assertEquals_text_should_fail_if_not_equals() RETURNS VOID AS $$ -DECLARE - expected_message VARCHAR; - error_message VARCHAR; - is_equals BOOLEAN; -BEGIN - BEGIN - perform test_assertEquals('hello'::VARCHAR, 'olleh'); - EXCEPTION - WHEN triggered_action_exception THEN - expected_message := 'assertEquals failure: expect ''hello'' instead of ''olleh'''; - error_message := SQLERRM; - perform test_assertTrue(format('Expect message ''%s'' instead of ''%s'' ', expected_message, error_message), error_message = expected_message); - END; -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_case_assertEquals_text_should_success_if_equals() RETURNS VOID AS $$ -BEGIN - perform test_assertEquals('hello'::VARCHAR, 'hello'); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_case_assertEquals_should_display_custom_message_if_defined() RETURNS VOID AS $$ -DECLARE - expected_message VARCHAR; - error_message VARCHAR; - is_equals BOOLEAN; -BEGIN - BEGIN - perform test_assertEquals('Test with custom message', 'hello'::VARCHAR, 'olleh'); - EXCEPTION - WHEN triggered_action_exception THEN - expected_message := 'Test with custom message: expect ''hello'' instead of ''olleh'''; - error_message := SQLERRM; - perform test_assertTrue(format('Expect message ''%s'' instead of ''%s'' ', expected_message, error_message), error_message = expected_message); - END; -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_case_assertEqualsArray_should_success_if_equals() RETURNS VOID AS $$ -BEGIN - perform test_assertEqualsArray(ARRAY['1','2'], ARRAY['1','2']); - perform test_assertEqualsArray(ARRAY['a','b'], ARRAY['a','b']); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_case_assertEqualsArray_should_display_diff_if_failed() RETURNS VOID AS $$ -DECLARE - expected_message VARCHAR; - error_message VARCHAR; - is_equals BOOLEAN; -BEGIN - BEGIN - perform test_assertEqualsArray(ARRAY['1','2','3','4'], ARRAY['1','2','4','4']); - EXCEPTION - WHEN triggered_action_exception THEN - expected_message := CONCAT( - 'assertEqualsArray failure:', E'\n', - '= 1', E'\n', - '= 2', E'\n', - '- 3', E'\n', - '+ 4', E'\n', - '= 4' - ); - error_message := SQLERRM; - perform test_assertTrue(format('Expect message ''%s'' instead of ''%s'' ', expected_message, error_message), error_message = expected_message); - END; -END; -$$ LANGUAGE plpgsql; - -SELECT * FROM test_run_all(); diff --git a/plpgsql/pgunit/initialize.sh b/plpgsql/pgunit/initialize.sh deleted file mode 100644 index 60557019..00000000 --- a/plpgsql/pgunit/initialize.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -set -ex - -echo "Enable DBLINK" -psql -d kata -c 'CREATE EXTENSION DBLINK;' - -echo "Initialize test framework" -wget https://raw.githubusercontent.com/adrianandrei-ca/pgunit/bc69dfc526ec3db55ff72af5d78eab55661502af/PGUnit.sql \ - && psql -d kata -f PGUnit.sql \ - && rm PGUnit.sql - -echo "Initialize custom asserts" -psql -d kata -f asserts.sql diff --git a/plpgsql/pgunit/run_tests.sql b/plpgsql/pgunit/run_tests.sql deleted file mode 100644 index 3c4e3c68..00000000 --- a/plpgsql/pgunit/run_tests.sql +++ /dev/null @@ -1,95 +0,0 @@ -CREATE OR REPLACE FUNCTION test_case_update_quality() RETURNS void AS $$ -DECLARE - name_result item.name%TYPE; -BEGIN - TRUNCATE TABLE item; - CALL new_item('foo', 0, 0); - - CALL update_quality(); - - SELECT name FROM item INTO name_result; - perform test_assertEquals('name did change', 'fixme', name_result); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION format_day(day INTEGER) RETURNS TEXT[] AS $$ -DECLARE - result TEXT[]; - item_result RECORD; -BEGIN - result := ARRAY[CONCAT('-------- day ', day, ' --------')]; - result := result || 'name, sellIn, quality'::TEXT; - - FOR item_result IN (SELECT name, sell_in, quality FROM item ORDER BY name ASC, sell_in ASC, quality ASC) - LOOP - result := result || format('%s, %s, %s', item_result.name, item_result.sell_in, item_result.quality); - END LOOP; - - RETURN result; -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION test_case_update_quality_golden_master() RETURNS VOID AS $$ -DECLARE - sell_in_result item.sell_in%TYPE; - quality_result item.quality%TYPE; - days INTEGER; - result TEXT[]; - expected TEXT[]; - item_result RECORD; -BEGIN - -- given - TRUNCATE TABLE item; - CALL new_item('+5 Dexterity Vest', 10, 20); - CALL new_item('Aged Brie', 2, 0); - CALL new_item('Elixir of the Mongoose', 5, 7); - CALL new_item('Sulfuras, Hand of Ragnaros', 0, 80); - CALL new_item('Sulfuras, Hand of Ragnaros', -1, 80); - CALL new_item('Backstage passes to a TAFKAL80ETC concert', 15, 20); - CALL new_item('Backstage passes to a TAFKAL80ETC concert', 10, 49); - CALL new_item('Backstage passes to a TAFKAL80ETC concert', 5, 49); - -- this conjured item does not work properly yet ; - CALL new_item('Conjured Mana Cake', 3, 6); - days := 1; - - -- when - result := format_day(0); - FOR current_day IN 1 .. days - LOOP - CALL update_quality(); - - result := result || format_day(current_day); - END LOOP; - - -- then - expected := ARRAY[ - '-------- day 0 --------', - 'name, sellIn, quality', - '+5 Dexterity Vest, 10, 20', - 'Aged Brie, 2, 0', - 'Backstage passes to a TAFKAL80ETC concert, 5, 49', - 'Backstage passes to a TAFKAL80ETC concert, 10, 49', - 'Backstage passes to a TAFKAL80ETC concert, 15, 20', - 'Conjured Mana Cake, 3, 6', - 'Elixir of the Mongoose, 5, 7', - 'Sulfuras, Hand of Ragnaros, -1, 80', - 'Sulfuras, Hand of Ragnaros, 0, 80', - '-------- day 1 --------', - 'name, sellIn, quality', - '+5 Dexterity Vest, 9, 19', - 'Aged Brie, 1, 1', - 'Backstage passes to a TAFKAL80ETC concert, 4, 50', - 'Backstage passes to a TAFKAL80ETC concert, 9, 50', - 'Backstage passes to a TAFKAL80ETC concert, 14, 21', - 'Conjured Mana Cake, 2, 5', - 'Elixir of the Mongoose, 4, 6', - 'Sulfuras, Hand of Ragnaros, -1, 80', - 'Sulfuras, Hand of Ragnaros, 0, 80' - ]; - - perform test_assertEquals_golden_master(expected, result); -END; -$$ LANGUAGE plpgsql; - - -SELECT * FROM test_run_all(); \ No newline at end of file diff --git a/plpgsql/src/item.sql b/plpgsql/src/item.sql deleted file mode 100644 index 1b59331e..00000000 --- a/plpgsql/src/item.sql +++ /dev/null @@ -1,8 +0,0 @@ -DROP TABLE IF EXISTS item; -CREATE TABLE item - ( - name character varying(100) NOT NULL, - sell_in numeric(6) NOT NULL, - quality numeric(6) NOT NULL - ); - diff --git a/plpgsql/src/new_item.sql b/plpgsql/src/new_item.sql deleted file mode 100644 index e78d712f..00000000 --- a/plpgsql/src/new_item.sql +++ /dev/null @@ -1,12 +0,0 @@ -DROP PROCEDURE IF EXISTS new_item; -CREATE PROCEDURE new_item( - name item.name%TYPE, - sell_in item.sell_in%TYPE, - quality item.quality%TYPE - ) -LANGUAGE plpgsql -AS $$ -BEGIN - INSERT INTO item (name, sell_in, quality) VALUES (name, sell_in, quality); -END; -$$; diff --git a/plpgsql/src/update_quality.sql b/plpgsql/src/update_quality.sql deleted file mode 100644 index e19d6863..00000000 --- a/plpgsql/src/update_quality.sql +++ /dev/null @@ -1,72 +0,0 @@ -CREATE OR REPLACE PROCEDURE update_quality() -LANGUAGE plpgsql -AS $$ -DECLARE - c_items CURSOR FOR - SELECT name, sell_in, quality FROM item FOR UPDATE; - l_item RECORD; - l_name item.name%TYPE; - l_sell_in item.sell_in%TYPE; - l_quality item.quality%TYPE; -BEGIN - OPEN c_items; - LOOP - FETCH c_items INTO l_item; - EXIT WHEN NOT FOUND; - - l_name := l_item.name; - l_sell_in := l_item.sell_in; - l_quality := l_item.quality; - - IF l_name <> 'Aged Brie' AND l_name <> 'Backstage passes to a TAFKAL80ETC concert' THEN - IF l_quality > 0 THEN - IF l_name <> 'Sulfuras, Hand of Ragnaros' THEN - l_quality := l_quality - 1; - END IF; - END IF; - ELSE - IF (l_quality < 50) THEN - l_quality := l_quality + 1; - IF l_name = 'Backstage passes to a TAFKAL80ETC concert' THEN - IF l_sell_in < 11 THEN - IF l_quality < 50 THEN - l_quality := l_quality + 1; - END IF; - END IF; - IF l_sell_in < 6 THEN - IF l_quality < 50 THEN - l_quality := l_quality + 1; - END IF; - END IF; - END IF; - END IF; - END IF; - - IF l_name <> 'Sulfuras, Hand of Ragnaros' THEN - l_sell_in := l_sell_in - 1; - END IF; - - IF l_sell_in < 0 THEN - IF l_name <> 'Aged Brie' THEN - IF l_name <> 'Backstage passes to a TAFKAL80ETC concert' THEN - IF l_quality > 0 THEN - IF l_name <> 'Sulfuras, Hand of Ragnaros' THEN - l_quality := l_quality - 1; - END IF; - END IF; - ELSE - l_quality := l_quality - l_quality; - END IF; - ELSE - IF l_quality < 50 THEN - l_quality := l_quality + 1; - END IF; - END IF; - END IF; - - UPDATE item - SET name = l_name, sell_in = l_sell_in, quality = l_quality WHERE CURRENT OF c_items; - END LOOP; - CLOSE c_items; -END; -$$;