3 Commits
v2.5 ... v2.7

Author SHA1 Message Date
a6a68a5320 Add song rank in performance. Use DbMigrate in tests.
* Add the song order in a service using `performances.rank` to indicate the
  relative position of each song within the service. The service page now
  respects this ranking.

* Update the tests to use DB Migrate to manage the database transitions.
2017-02-11 21:23:17 -06:00
200b69b960 Updated build to use git versioning and extract shell utilities. 2016-12-17 23:24:38 -06:00
e02b465ada Update elastic beanstalk config for new environment. 2016-12-17 21:55:24 -06:00
14 changed files with 110 additions and 212 deletions

View File

@ -1,6 +1,6 @@
branch-defaults: branch-defaults:
master: master:
environment: new-life-songs-env environment: new-life-songs-prod
global: global:
application_name: new-life-songs application_name: new-life-songs
branch: null branch: null

View File

@ -1,19 +1,32 @@
import org.apache.tools.ant.filters.ReplaceTokens import org.apache.tools.ant.filters.ReplaceTokens
buildscript {
repositories {
maven { url 'https://mvn.jdb-labs.com/repo' }
}
dependencies {
classpath 'com.jdbernard:gradle-exec-util:0.2.0'
}
}
plugins { id 'com.palantir.git-version' version '0.5.2' }
apply plugin: "groovy" apply plugin: "groovy"
apply plugin: "maven" apply plugin: "maven"
apply plugin: "war" apply plugin: "war"
apply plugin: "jetty"
group = "com.jdbernard" group = "com.jdbernard"
version = new ProjectVersion() import static com.jdbernard.gradle.ExecUtil.*
version = gitVersion()
// webAppDirName = "build/webapp/main" // webAppDirName = "build/webapp/main"
repositories { repositories {
mavenLocal() mavenLocal()
mavenCentral() } mavenCentral()
}
dependencies { dependencies {
compile 'ch.qos.logback:logback-classic:1.1.8' compile 'ch.qos.logback:logback-classic:1.1.8'
@ -32,14 +45,13 @@ dependencies {
providedCompile 'javax.servlet:javax.servlet-api:3.1.0' providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'com.jdblabs:db-migrate.groovy:0.2.5'
testRuntime 'com.h2database:h2:1.4.186' testRuntime 'com.h2database:h2:1.4.186'
} }
war { war {
from "resources/webapp" from "resources/webapp"
from "build/webapp" from "build/webapp"
version = project.version.releaseVersion
filter(ReplaceTokens, tokens: [version: version]) filter(ReplaceTokens, tokens: [version: version])
rename '(.+)(\\..*(css|js))', '$1-' + version + '$2' rename '(.+)(\\..*(css|js))', '$1-' + version + '$2'
webInf { from 'resources/main/WEB-INF' } webInf { from 'resources/main/WEB-INF' }
@ -50,7 +62,6 @@ test { testLogging { events 'failed' } }
task testWar(type: War) { task testWar(type: War) {
from 'resources/webapp' from 'resources/webapp'
version = project.version.releaseVersion
filter(ReplaceTokens, tokens: [version: version]) filter(ReplaceTokens, tokens: [version: version])
rename '(.+)(\\..*(css|js))', '$1-' + version + '$2' rename '(.+)(\\..*(css|js))', '$1-' + version + '$2'
webInf { from 'resources/test/WEB-INF' } webInf { from 'resources/test/WEB-INF' }
@ -68,45 +79,8 @@ task compileScss(
war.dependsOn compileScss war.dependsOn compileScss
testWar.dependsOn compileScss testWar.dependsOn compileScss
// ## Build Versioning task
task incrementBuildNumber(
group: 'versioning',
description: "Increment the project's build number."
) { doLast { ++version.build } }
task incrementMinorNumber(
group: 'versioning',
description: "Increment the project's minor version number."
) { doLast { ++version.minor } }
task incrementMajorNumber(
group: 'versioning',
description: "Increment the project's major version number."
) { doLast { ++version.major } }
task markReleaseBuild(
group: 'versioning',
description: "Mark this version of the project as a release version."
) { doLast { version.release = true } }
war.dependsOn << incrementBuildNumber
testWar.dependsOn << incrementBuildNumber
// ## Custom tasks for local deployment
task deployLocal(dependsOn: ['build']) { doLast {
def warName = "${project.name}-${version.releaseVersion}.war"
def jettyHome = System.getenv("JETTY_HOME")
def deployedWar = new File("$jettyHome/webapps/$warName")
if (deployedWar.exists()) deployedWar.delete();
copy {
from "build/libs"
into "$jettyHome/webapps"
include warName } } }
task deployProd(dependsOn: ['build']) { doLast { task deployProd(dependsOn: ['build']) { doLast {
def warName = "${project.name}-${version.releaseVersion}.war" def warName = "${project.name}-${version}.war"
def artifactName = "ROOT.war" def artifactName = "ROOT.war"
copy { copy {
@ -115,99 +89,5 @@ task deployProd(dependsOn: ['build']) { doLast {
include warName include warName
rename warName, artifactName } rename warName, artifactName }
shell_("eb", "deploy", "-l", "${project.name}-${version}") exec("eb", "deploy", "-l", "${project.name}-${version}")
} } } }
task killJettyLocal() { doLast {
def pidFile = new File(System.properties['user.home'] + "/temp/jetty.pid")
println "Killing old Jetty instance."
shell_("sh", "-c", 'kill $(jps -l | grep start.jar | cut -f 1 -d " ")') } }
task localJetty(dependsOn: ['killJettyLocal', 'deployLocal']) { doLast {
spawn(["java", "-jar", "start.jar"], new File(jettyHome)) } }
// ## Project Version
class ProjectVersion {
private File versionFile
int major
int minor
int build
boolean release
public ProjectVersion() { this(new File('version.properties')) }
public ProjectVersion(File versionFile) {
this.versionFile = versionFile
if (!versionFile.exists()) {
versionFile.createNewFile()
this.major = this.minor = this.build = 0
this.save() }
else this.load() }
@Override String toString() { "$major.$minor${release ? '' : '-build' + build}" }
public String getReleaseVersion() { "$major.$minor" }
public void setRelease(boolean release) { this.release = release; save() }
public void setMajor(int major) {
this.major = major; minor = build = 0; release = false; save() }
public void setMinor(int minor) {
this.minor = minor; build = 0; release = false; save() }
public void setBuild(int build) { this.build = build; save() }
private void save() {
def props = new Properties()
versionFile.withInputStream { props.load(it) }
["major", "minor", "build"].each { props[it] = this[it].toString() }
props["version.release"] = release.toString()
versionFile.withOutputStream { props.store(it, "") } }
private void load() {
def props = new Properties()
versionFile.withInputStream { props.load(it) }
["major", "minor", "build"].each {
this[it] = props[it] ? props[it] as int : 0 }
release = Boolean.parseBoolean(props["version.release"]) }
}
// ## Utility methods for working with processes.
def shell_(List<String> cmd) { shell(cmd, null, false) }
def shell_(String... cmd) { shell(cmd, null, false) }
def shell(String... cmd) { shell(cmd, null, true) }
def shell(List<String> cmd, File workingDir, boolean checkExit) {
shell(cmd as String[], workingDir, checkExit) }
def shell(String[] cmd, File workingDir, boolean checkExit) {
def pb = new ProcessBuilder(cmd)
if (workingDir) pb.directory(workingDir)
def process = pb.start()
process.waitForProcessOutput(System.out, System.err)
if (process.exitValue() != 0)
println "Command $cmd exited with non-zero result code."
if (checkExit) assert process.exitValue() == 0 : "Not ignoring failed command." }
def shell(List<List<String>> cmds, File workingDir) {
cmds.each {
ProcessBuilder pb = new ProcessBuilder(it)
pb.directory(workingDir)
pb.start().waitForProcessOutput(System.out, System.err) } }
def spawn(String... cmd) { spawn(cmd, null) }
def spawn(List<String> cmd, File workingDir) { spawn(cmd as String[], workingDir) }
def spawn(String[] cmd, File workingDir) {
def pb = new ProcessBuilder(cmd)
if (workingDir) pb.directory(workingDir)
def process = pb.start() }

View File

@ -14,20 +14,20 @@ INSERT INTO songs (name, artists) VALUES
('Glorious', 'Martha Munizzi'), ('Glorious', 'Martha Munizzi'),
('Rez Power', 'Israel Houghton'); ('Rez Power', 'Israel Houghton');
INSERT INTO performances (service_id, song_id, pianist, organist, bassist, drummer, guitarist, leader) VALUES INSERT INTO performances (service_id, song_id, rank, pianist, organist, bassist, drummer, guitarist, leader) VALUES
(1, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'), (1, 1, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'),
(1, 2, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'), (1, 2, 2, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'),
(1, 3, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'), (1, 3, 3, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'),
(2, 2, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'), (2, 2, 1, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'),
(2, 3, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'), (2, 3, 2, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'),
(2, 4, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'), (2, 4, 3, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'),
(3, 1, 'Rachel Wood', 'Krista Hatcher', 'Jonathan Bernard', 'Jared Wood', 'Tony Bagliore', 'Rachel Wood'), (3, 1, 0, 'Rachel Wood', 'Krista Hatcher', 'Jonathan Bernard', 'Jared Wood', 'Tony Bagliore', 'Rachel Wood'),
(3, 2, 'Rachel Wood', 'Krista Hatcher', 'Jonathan Bernard', 'Jared Wood', 'Tony Bagliore', 'Rachel Wood'), (3, 2, 0, 'Rachel Wood', 'Krista Hatcher', 'Jonathan Bernard', 'Jared Wood', 'Tony Bagliore', 'Rachel Wood'),
(4, 3, 'Trevor Delano', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'), (4, 3, 0, 'Trevor Delano', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'),
(5, 4, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Tony Bagliore', 'Rachel Wood'), (5, 4, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Tony Bagliore', 'Rachel Wood'),
(6, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'), (6, 1, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'),
(7, 2, 'Trevor Delano', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'), (7, 2, 1, 'Trevor Delano', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'),
(8, 3, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'); (8, 3, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood');
INSERT INTO users (username, pwd, role) VALUES INSERT INTO users (username, pwd, role) VALUES
('admin', '', 'admin'), ('admin', '', 'admin'),

View File

@ -152,10 +152,10 @@ public class NLSongsDB {
public Performance create(Performance perf) { public Performance create(Performance perf) {
// TODO: handle constraint violation (same service and song ids) // TODO: handle constraint violation (same service and song ids)
sql.executeInsert( sql.executeInsert(
"INSERT INTO performances (service_id, song_id, pianist, " + "INSERT INTO performances (service_id, song_id, rank, pianist, " +
"organist, bassist, drummer, guitarist, leader) VALUES " + "organist, bassist, drummer, guitarist, leader) VALUES " +
"(?, ?, ?, ?, ?, ?, ?, ?)", [perf.serviceId, perf.songId, "(?, ?, ?, ?, ?, ?, ?, ?)", [perf.serviceId, perf.songId,
perf.pianist, perf.organist, perf.bassist, perf.drummer, perf.rank, perf.pianist, perf.organist, perf.bassist, perf.drummer,
perf.guitarist, perf.leader]) perf.guitarist, perf.leader])
return perf } return perf }
@ -163,10 +163,11 @@ public class NLSongsDB {
// TODO: handle constraint violation (same service and song ids) // TODO: handle constraint violation (same service and song ids)
return sql.executeUpdate( return sql.executeUpdate(
"UPDATE performances SET pianist = ?, organist = ?, " + "UPDATE performances SET pianist = ?, organist = ?, " +
"bassist = ?, drummer = ?, guitarist = ?, leader = ? " + "bassist = ?, drummer = ?, guitarist = ?, leader = ?, " +
"WHERE service_id = ? AND song_id = ?", "rank = ? WHERE service_id = ? AND song_id = ?",
[perf.pianist, perf.organist, perf.bassist, perf.drummer, [perf.pianist, perf.organist, perf.bassist, perf.drummer,
perf.guitarist, perf.leader, perf.serviceId, perf.songId]) } perf.guitarist, perf.leader, perf.rank, perf.serviceId,
perf.songId]) }
public int delete(Performance perf) { public int delete(Performance perf) {
sql.execute( sql.execute(

View File

@ -4,6 +4,7 @@ public class Performance implements Serializable {
int serviceId int serviceId
int songId int songId
int rank
String pianist String pianist
String organist String organist
String bassist String bassist
@ -19,6 +20,7 @@ public class Performance implements Serializable {
return (this.serviceId == that.serviceId && return (this.serviceId == that.serviceId &&
this.songId == that.songId && this.songId == that.songId &&
this.rank == that.rank &&
this.pianist == that.pianist && this.pianist == that.pianist &&
this.organist == that.organist && this.organist == that.organist &&
this.bassist == that.bassist && this.bassist == that.bassist &&
@ -27,5 +29,5 @@ public class Performance implements Serializable {
this.leader == that.leader) } this.leader == that.leader) }
@Override String toString() { @Override String toString() {
return "($serviceId, $songId): $leader - $pianist" } return "($serviceId, $songId)-$rank: $leader - $pianist" }
} }

View File

@ -0,0 +1,9 @@
-- # New Life Songs DB
-- @author Jonathan Bernard <jdb@jdb-labs.com>
--
-- PostgreSQL database un-creation sript.
DROP TABLE performances;
DROP TABLE services;
DROP TABLE songs;
DROP TABLE tokens;
DROP TABLE users;

View File

@ -4,8 +4,7 @@
-- PostgreSQL database creation sript. -- PostgreSQL database creation sript.
-- Services table -- Services table
DROP TABLE IF EXISTS services; CREATE TABLE services (
CREATE TABLE IF NOT EXISTS services (
id SERIAL, id SERIAL,
date DATE NOT NULL, date DATE NOT NULL,
service_type VARCHAR(16) DEFAULT NULL, service_type VARCHAR(16) DEFAULT NULL,
@ -13,10 +12,8 @@ CREATE TABLE IF NOT EXISTS services (
CONSTRAINT uc_serviceTypeAndDate UNIQUE (date, service_type), CONSTRAINT uc_serviceTypeAndDate UNIQUE (date, service_type),
PRIMARY KEY (id)); PRIMARY KEY (id));
-- Songs table -- Songs table
DROP TABLE IF EXISTS songs; CREATE TABLE songs (
CREATE TABLE IF NOT EXISTS songs (
id SERIAL, id SERIAL,
name VARCHAR(128) NOT NULL, name VARCHAR(128) NOT NULL,
artists VARCHAR(256) DEFAULT NULL, artists VARCHAR(256) DEFAULT NULL,
@ -25,8 +22,7 @@ CREATE TABLE IF NOT EXISTS songs (
-- performances table -- performances table
DROP TABLE IF EXISTS performances; CREATE TABLE performances (
CREATE TABLE IF NOT EXISTS performances (
service_id INTEGER NOT NULL, service_id INTEGER NOT NULL,
song_id INTEGER NOT NULL, song_id INTEGER NOT NULL,
pianist VARCHAR(64) DEFAULT NULL, pianist VARCHAR(64) DEFAULT NULL,
@ -40,16 +36,16 @@ CREATE TABLE IF NOT EXISTS performances (
FOREIGN KEY (song_id) REFERENCES songs (id) ON DELETE CASCADE); FOREIGN KEY (song_id) REFERENCES songs (id) ON DELETE CASCADE);
DROP TABLE IF EXISTS users; -- Users table
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE users (
id SERIAL, id SERIAL,
username VARCHAR(64) UNIQUE NOT NULL, username VARCHAR(64) UNIQUE NOT NULL,
pwd VARCHAR(80), pwd VARCHAR(80),
role VARCHAR(16) NOT NULL, role VARCHAR(16) NOT NULL,
PRIMARY KEY (id)); PRIMARY KEY (id));
DROP TABLE IF EXISTS tokens; -- Tokens table
CREATE TABLE IF NOT EXISTS tokens ( CREATE TABLE tokens (
token VARCHAR(64), token VARCHAR(64),
user_id INTEGER NOT NULL, user_id INTEGER NOT NULL,
expires TIMESTAMP NOT NULL, expires TIMESTAMP NOT NULL,

View File

@ -0,0 +1,5 @@
-- # New Life Songs DB
-- @author Jonathan Bernard <jdb@jdb-labs.com>
--
-- Remove performances.rank
ALTER TABLE performances DROP COLUMN rank;

View File

@ -0,0 +1,6 @@
-- # New Life Songs DB
-- @author Jonathan Bernard <jdb@jdb-labs.com>
--
-- Add performances.rank: the rank of the performance in the service, aka. the
-- "track number" if the service were an album.
ALTER TABLE performances ADD COLUMN rank integer NOT NULL DEFAULT 0;

View File

@ -1,8 +0,0 @@
-- DROP DATABASE IF EXISTS nlsongs;
CREATE DATABASE nlsongs
ENCODING = 'UTF8'
LC_COLLATE = 'en_US.UTF-8'
LC_CTYPE = 'en_US.UTF-8'
CONNECTION LIMIT = 1;
\c nlsongs

View File

@ -1,5 +0,0 @@
DROP TABLE tokens;
DROP TABLE users;
DROP TABLE performances;
DROP TABLE songs;
DROP TABLE services;

View File

@ -64,7 +64,7 @@ if (!service) { response.sendError(response.SC_NOT_FOUND); return }
<tbody> <tbody>
<% songsDB.findPerformancesForServiceId(service.id). <% songsDB.findPerformancesForServiceId(service.id).
collect { [perf: it, song: songsDB.findSong(it.songId)] }. collect { [perf: it, song: songsDB.findSong(it.songId)] }.
sort { it.song.name }.each { row -> %> sort { it.song.name }.sort { it.perf.rank }.each { row -> %>
<tr><td class=actions><a href="<%= NLSongsContext.makeUrl(service, row.song) %>"><i class="fa fa-download"></i></a></td> <tr><td class=actions><a href="<%= NLSongsContext.makeUrl(service, row.song) %>"><i class="fa fa-download"></i></a></td>
<td class=song-name><a href='../song/<%= row.song.id %>'><%= <td class=song-name><a href='../song/<%= row.song.id %>'><%=
row.song.name %></a></td> row.song.name %></a></td>

View File

@ -3,6 +3,7 @@ package com.jdbernard.nlsongs.service
import com.jdbernard.nlsongs.db.NLSongsDB import com.jdbernard.nlsongs.db.NLSongsDB
import com.jdbernard.nlsongs.model.* import com.jdbernard.nlsongs.model.*
import com.jdbernard.nlsongs.servlet.NLSongsContext import com.jdbernard.nlsongs.servlet.NLSongsContext
import com.jdblabs.dbmigrate.DbMigrate
import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.HikariDataSource
@ -24,8 +25,9 @@ import org.slf4j.LoggerFactory
public class NLSongsDBTest { public class NLSongsDBTest {
static NLSongsDB songsDB; static NLSongsDB songsDB
static Sql sql static Sql sql
static DbMigrate dbmigrate
static Logger log = LoggerFactory.getLogger(NLSongsDBTest) static Logger log = LoggerFactory.getLogger(NLSongsDBTest)
def dateFormat def dateFormat
@ -61,23 +63,23 @@ public class NLSongsDBTest {
new Song(id: it[0], name: it[1], artists: it[2]) } new Song(id: it[0], name: it[1], artists: it[2]) }
this.performances = [ this.performances = [
[1, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'], [1, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood', 1],
[1, 2, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'], [1, 2, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood', 2],
[1, 3, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'], [1, 3, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood', 3],
[2, 2, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'], [2, 2, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood', 1],
[2, 3, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'], [2, 3, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood', 2],
[2, 4, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'], [2, 4, 'Trevor Delano', 'Connie Bernard', 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood', 3],
[3, 1, 'Rachel Wood', 'Krista Hatcher', 'Jonathan Bernard', 'Jared Wood', 'Tony Bagliore', 'Rachel Wood'], [3, 1, 'Rachel Wood', 'Krista Hatcher', 'Jonathan Bernard', 'Jared Wood', 'Tony Bagliore', 'Rachel Wood', 0],
[3, 2, 'Rachel Wood', 'Krista Hatcher', 'Jonathan Bernard', 'Jared Wood', 'Tony Bagliore', 'Rachel Wood'], [3, 2, 'Rachel Wood', 'Krista Hatcher', 'Jonathan Bernard', 'Jared Wood', 'Tony Bagliore', 'Rachel Wood', 0],
[4, 3, 'Trevor Delano', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood'], [4, 3, 'Trevor Delano', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser', 'Rachel Wood', 0],
[5, 4, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Tony Bagliore', 'Rachel Wood'], [5, 4, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Tony Bagliore', 'Rachel Wood', 1],
[6, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'], [6, 1, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood', 1],
[7, 2, 'Trevor Delano', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'], [7, 2, 'Trevor Delano', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood', 1],
[8, 3, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood'] ].collect { [8, 3, 'Jared Wood', null, 'Jonathan Bernard', 'Christian Thompson', 'Andrew Fraiser; Tony Bagliore', 'Rachel Wood', 1] ].collect {
new Performance(serviceId: it[0], songId: it[1], pianist: it[2], new Performance(serviceId: it[0], songId: it[1], pianist: it[2],
organist: it[3], bassist: it[4], drummer: it[5], organist: it[3], bassist: it[4], drummer: it[5],
guitarist: it[6], leader: it[7]) } guitarist: it[6], leader: it[7], rank: it[8]) }
} }
@BeforeClass @BeforeClass
@ -90,8 +92,13 @@ public class NLSongsDBTest {
HikariDataSource dataSource = new HikariDataSource(hcfg) HikariDataSource dataSource = new HikariDataSource(hcfg)
// Create NLSongsDB // Create NLSongsDB
this.songsDB = new NLSongsDB(dataSource) NLSongsDBTest.songsDB = new NLSongsDB(dataSource)
this.sql = new Sql(dataSource) NLSongsDBTest.sql = new Sql(dataSource)
// Setup our DB migration tool
NLSongsDBTest.dbmigrate = new DbMigrate(
migrationsDir: new File('src/main/sql'),
sql: NLSongsDBTest.sql)
// Set NLSongsContext // Set NLSongsContext
NLSongsContext.songsDB = songsDB } NLSongsContext.songsDB = songsDB }
@ -103,18 +110,18 @@ public class NLSongsDBTest {
@Before @Before
public void initData() { public void initData() {
// Get the DB Schema and test data. // Create the DB schema
File createSchemaSql = new File("src/main/sql/create-tables.sql") dbmigrate.up()
File testDataSql = new File("resources/test/testdb.init.sql")
// Create the DB Schema
sql.execute(createSchemaSql.text)
// Populate the DB with test data. // Populate the DB with test data.
File testDataSql = new File("resources/test/testdb.init.sql")
sql.execute(testDataSql.text) } sql.execute(testDataSql.text) }
/// ### Services @After
public void destroyData() {
dbmigrate.down(Integer.MAX_VALUE) }
/// ### Services
@Test public void shouldCreateService() { @Test public void shouldCreateService() {
def service = new Service( def service = new Service(
date: new Date(), serviceType: ServiceType.SUN_AM) date: new Date(), serviceType: ServiceType.SUN_AM)
@ -178,8 +185,8 @@ public class NLSongsDBTest {
assertCollectionsEqual( assertCollectionsEqual(
performances.findAll { it.serviceId != 1 }, performances.findAll { it.serviceId != 1 },
songsDB.findAllPerformances()) } songsDB.findAllPerformances()) }
/// ### Songs
/// ### Songs
@Test public void shoudCreateSong() { @Test public void shoudCreateSong() {
def song = new Song(name: "Test Song", artists: ["Bob Sam"]) def song = new Song(name: "Test Song", artists: ["Bob Sam"])
def newSong = songsDB.create(song) def newSong = songsDB.create(song)
@ -247,5 +254,10 @@ public class NLSongsDBTest {
log.info("C2: $c2") log.info("C2: $c2")
assertEquals(c1.size(), c2.size()) assertEquals(c1.size(), c2.size())
c1.each {
def isPresent = c2.contains(it)
if (!isPresent) log.info("$it is not within $c2.")
assertTrue(isPresent) }
assertTrue(c1.every { c2.contains(it) }) } assertTrue(c1.every { c2.contains(it) }) }
} }

View File

@ -1,6 +1,6 @@
# #
#Sat Dec 17 21:50:15 CST 2016 #Sat Dec 17 21:52:48 CST 2016
major=2 major=2
version.release=true version.release=true
minor=5 minor=5
build=0 build=2