Преглед на файлове

feat: database pooling, migrations in test

Fela Maslen преди 5 години
родител
ревизия
370f54fb09
променени са 6 файла, в които са добавени 134 реда и са изтрити 40 реда
  1. 1 0
      music-player/go.sum
  2. 41 8
      music-player/pkg/db/main.go
  3. 13 0
      music-player/pkg/db/main_test.go
  4. 7 7
      music-player/pkg/db/scan.go
  5. 50 25
      music-player/pkg/db/scan_test.go
  6. 22 0
      music-player/pkg/db/test_utils.go

+ 1 - 0
music-player/go.sum

@@ -227,6 +227,7 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f
 github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
 github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
 github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.2 h1:mpQEXihFnWGDy6X98EOTh81JYuxn7txby8ilJ3iIPGM=
 github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=

+ 41 - 8
music-player/pkg/db/main.go

@@ -1,21 +1,54 @@
 package db
 
 import (
-  "os"
-  "fmt"
-  "context"
+	"context"
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
 
-  "github.com/jackc/pgx/v4"
+	"github.com/jackc/pgx/v4/pgxpool"
 
-  "github.com/felamaslen/go-music-player/pkg/config"
+	migrate "github.com/golang-migrate/migrate/v4"
+	_ "github.com/golang-migrate/migrate/v4/database/postgres"
+	_ "github.com/golang-migrate/migrate/v4/source/file"
+
+	"github.com/felamaslen/go-music-player/pkg/config"
 )
 
-func GetConnection() *pgx.Conn {
-  conn, err := pgx.Connect(context.Background(), config.Config.DatabaseUrl)
+var pool *pgxpool.Pool
+
+func GetConnection() *pgxpool.Conn {
+  if pool == nil {
+    var err error
+    pool, err = pgxpool.Connect(context.Background(), config.Config.DatabaseUrl)
+
+    if err != nil {
+      fmt.Fprintf(os.Stderr, "Unable to acquire database connection pool: %v\n", err)
+      os.Exit(1)
+    }
+  }
+
+  conn, err := pool.Acquire(context.Background())
   if err != nil {
-    fmt.Fprintf(os.Stderr, "Unable to acquire database connection: %v\n", err)
+    fmt.Fprintf(os.Stderr, "Unable to acquire connection from pool: %v\n", err)
     os.Exit(1)
   }
 
   return conn
 }
+
+func MigrateDatabase() {
+  databaseUrl := fmt.Sprintf("%s?sslmode=disable", config.Config.DatabaseUrl)
+  cwd, err := os.Getwd()
+  if err != nil {
+    log.Fatal("Error getting working dir: ", err)
+  }
+  directoryUrl := fmt.Sprintf("file://%s", filepath.Join(cwd, "migrations"))
+
+  m, err := migrate.New(directoryUrl, databaseUrl)
+  if err != nil {
+    log.Fatal("Error setting up: ", err)
+  }
+  m.Up()
+}

+ 13 - 0
music-player/pkg/db/main_test.go

@@ -0,0 +1,13 @@
+package db
+
+import (
+  "context"
+  "testing"
+)
+
+func TestDbIntegration(t *testing.T) {
+  conn := PrepareDatabaseForTesting()
+  defer conn.Conn().Close(context.Background())
+
+  t.Run("Scanning and inserting songs", IntegrationTestInsertMusicIntoDatabase)
+}

+ 7 - 7
music-player/pkg/db/scan.go

@@ -8,9 +8,6 @@ import (
 )
 
 func InsertMusicIntoDatabase(songs chan *read.Song) {
-  conn := GetConnection()
-  defer conn.Close(context.Background())
-
   for {
     select {
     case song, more := <- songs:
@@ -18,11 +15,12 @@ func InsertMusicIntoDatabase(songs chan *read.Song) {
         return
       }
 
-      var duration string = fmt.Sprintf("%d", song.Duration)
-      if !song.DurationOk {
-        duration = "NULL"
+      duration := "NULL"
+      if song.DurationOk {
+        duration = fmt.Sprintf("%d", song.Duration)
       }
 
+      conn := GetConnection()
       _, err := conn.Query(
         context.Background(),
         "insert into songs (title, artist, album, duration, base_path, relative_path) values ($1, $2, $3, $4, $5, $6)",
@@ -34,7 +32,9 @@ func InsertMusicIntoDatabase(songs chan *read.Song) {
         song.RelativePath,
       )
 
-      if err != nil {
+      if err == nil {
+        fmt.Printf("Inserted record successfully: %s, %s, %s, %s\n", song.RelativePath, song.Artist, song.Album, song.Title)
+      } else {
         fmt.Printf("Error inserting record: %s\n", err)
       }
     }

+ 50 - 25
music-player/pkg/db/scan_test.go

@@ -1,25 +1,20 @@
 package db
 
 import (
-  "context"
-  "testing"
-  "github.com/stretchr/testify/assert"
+	"context"
+	"testing"
 
-  "github.com/felamaslen/go-music-player/pkg/read"
-)
+	"github.com/stretchr/testify/assert"
 
-func TestInsertMusicIntoDatabase(t *testing.T) {
-  conn := GetConnection()
-  conn.Query(
-    context.Background(),
-    "truncate table songs",
-  )
-  defer conn.Close(context.Background())
+	"github.com/felamaslen/go-music-player/pkg/read"
+)
 
+func IntegrationTestInsertMusicIntoDatabase(t *testing.T) {
   songs := make(chan *read.Song)
 
   go func() {
     defer close(songs)
+
     songs <- &read.Song{
       Title: "Hey Jude",
       Artist: "The Beatles",
@@ -29,14 +24,23 @@ func TestInsertMusicIntoDatabase(t *testing.T) {
       BasePath: "/path/to",
       RelativePath: "file.ogg",
     }
+
+    songs <- &read.Song{
+      Title: "Starman",
+      Artist: "David Bowie",
+      Album: "The Rise and Fall of Ziggy Stardust and the Spiders from Mars",
+      Duration: 256,
+      DurationOk: true,
+      BasePath: "/different/path",
+      RelativePath: "otherFile.ogg",
+    }
   }()
 
   InsertMusicIntoDatabase(songs)
 
-  conn = GetConnection()
+  conn := GetConnection()
 
   type Row struct {
-    id int
     title string
     artist string
     album string
@@ -45,19 +49,40 @@ func TestInsertMusicIntoDatabase(t *testing.T) {
     relative_path string
   }
 
-  var row Row
-
-  err := conn.QueryRow(
+  rows, err := conn.Query(
     context.Background(),
-    "select * from songs",
-  ).Scan(&row.id, &row.title, &row.artist, &row.album, &row.duration, &row.base_path, &row.relative_path)
+    `
+    select title, artist, album, duration, base_path, relative_path
+    from songs
+    order by title
+    `,
+  )
 
   assert.Nil(t, err)
 
-  assert.Equal(t, row.title, "Hey Jude")
-  assert.Equal(t, row.artist, "The Beatles")
-  assert.Equal(t, row.album, "")
-  assert.Equal(t, row.duration, 431)
-  assert.Equal(t, row.base_path, "/path/to")
-  assert.Equal(t, row.relative_path, "file.ogg")
+  var row Row
+
+  rows.Next()
+  rows.Scan(&row.title, &row.artist, &row.album, &row.duration, &row.base_path, &row.relative_path)
+
+  assert.Equal(t, Row{
+    title: "Hey Jude",
+    artist: "The Beatles",
+    album: "",
+    duration: 431,
+    base_path: "/path/to",
+    relative_path: "file.ogg",
+  }, row)
+
+  rows.Next()
+  rows.Scan(&row.title, &row.artist, &row.album, &row.duration, &row.base_path, &row.relative_path)
+
+  assert.Equal(t, Row{
+    title: "Starman",
+    artist: "David Bowie",
+    album: "The Rise and Fall of Ziggy Stardust and the Spiders from Mars",
+    duration: 256,
+    base_path: "/different/path",
+    relative_path: "otherFile.ogg",
+  }, row)
 }

+ 22 - 0
music-player/pkg/db/test_utils.go

@@ -0,0 +1,22 @@
+package db
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/jackc/pgx/v4/pgxpool"
+)
+
+func PrepareDatabaseForTesting() *pgxpool.Conn {
+  fmt.Println("Preparing database for testing")
+
+  MigrateDatabase()
+  conn := GetConnection()
+
+  conn.Query(
+    context.Background(),
+    "truncate table songs",
+  )
+
+  return conn
+}