thar we GO
parent
031d5f545d
commit
0c5bb025bb
|
|
@ -3,6 +3,7 @@ package main_test
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
main "show-rss"
|
main "show-rss"
|
||||||
|
"show-rss/src/db"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -11,7 +12,7 @@ func TestMain(t *testing.T) {
|
||||||
ctx, can := context.WithTimeout(context.Background(), 2*time.Second)
|
ctx, can := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
defer can()
|
defer can()
|
||||||
|
|
||||||
if err := main.Main(ctx); err != nil && ctx.Err() == nil {
|
if err := main.Main(db.Test(t, ctx)); err != nil && ctx.Err() == nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,17 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"show-rss/src/cleanup"
|
||||||
"show-rss/src/db"
|
"show-rss/src/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Config(ctx context.Context) (context.Context, error) {
|
func Config(ctx context.Context) (context.Context, func(), error) {
|
||||||
ctx, err := db.Inject(ctx, "/tmp/f.db")
|
ctx, err := db.Inject(ctx, "/tmp/f.db")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx, err
|
return ctx, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx, nil
|
return ctx, func() {
|
||||||
|
cleanup.Extract(ctx)()
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ package cron
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"fmt"
|
||||||
"show-rss/src/db"
|
"show-rss/src/db"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -11,7 +12,7 @@ func Main(ctx context.Context) error {
|
||||||
c := time.NewTicker(time.Minute)
|
c := time.NewTicker(time.Minute)
|
||||||
defer c.Stop()
|
defer c.Stop()
|
||||||
for {
|
for {
|
||||||
if err := one(ctx); err != nil {
|
if err := One(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,19 +24,49 @@ func Main(ctx context.Context) error {
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func one(ctx context.Context) error {
|
func One(ctx context.Context) error {
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return fmt.Errorf("failed init db: %w", err)
|
||||||
}
|
}
|
||||||
return io.EOF
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDB(ctx context.Context) error {
|
func initDB(ctx context.Context) error {
|
||||||
return db.Exec(ctx, `
|
if err := db.Exec(ctx, `CREATE TABLE IF NOT EXISTS database_version (v NUMBER, t TIMESTAMP)`); err != nil {
|
||||||
CREATE TABLE IF NOT EXISTS feeds (
|
return fmt.Errorf("failed to create database_version table: %w", err)
|
||||||
id SERIAL
|
}
|
||||||
);
|
|
||||||
ALTER TABLE feeds ADD COLUMN IF NOT EXISTS b TEXT;
|
type DatabaseVersion struct {
|
||||||
ALTER TABLE feeds ADD COLUMN IF NOT EXISTS b TEXT;
|
V int `json:"v"`
|
||||||
`)
|
T time.Time `json:"t"`
|
||||||
|
}
|
||||||
|
vs, err := db.Query[DatabaseVersion](ctx, `SELECT v, t FROM database_version ORDER BY v DESC LIMIT 1`)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var v DatabaseVersion
|
||||||
|
if len(vs) > 0 {
|
||||||
|
v = vs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
mods := []string{
|
||||||
|
`CREATE TABLE feeds (
|
||||||
|
id SERIAL PRIMARY KEY NOT NULL,
|
||||||
|
created_at TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP,
|
||||||
|
deleted_at TIMESTAMP
|
||||||
|
)`,
|
||||||
|
}
|
||||||
|
mods = append([]string{""}, mods...)
|
||||||
|
for i := v.V + 1; i < len(mods); i++ {
|
||||||
|
q := mods[i]
|
||||||
|
q = strings.TrimSpace(q)
|
||||||
|
q = strings.TrimSuffix(q, ";")
|
||||||
|
q = fmt.Sprintf("BEGIN; %s; INSERT INTO database_version (v, t) VALUES (?, ?); COMMIT;", q)
|
||||||
|
if err := db.Exec(ctx, q, i, time.Now()); err != nil {
|
||||||
|
return fmt.Errorf("[%d] failed mod %s: %w", i, mods[i], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package cron_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"show-rss/src/cmd/cron"
|
||||||
|
"show-rss/src/db"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOne(t *testing.T) {
|
||||||
|
ctx, can := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
|
defer can()
|
||||||
|
|
||||||
|
t.Run("same ctx", func(t *testing.T) {
|
||||||
|
ctx := db.Test(t, ctx)
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
if err := cron.One(ctx); err != nil && ctx.Err() == nil {
|
||||||
|
t.Fatalf("failed %d: %v", i, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("new ctx", func(t *testing.T) {
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
if err := cron.One(db.Test(t, ctx)); err != nil && ctx.Err() == nil {
|
||||||
|
t.Fatalf("failed %d: %v", i, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -14,10 +14,11 @@ func Main(ctx context.Context) error {
|
||||||
ctx, can := context.WithCancel(ctx)
|
ctx, can := context.WithCancel(ctx)
|
||||||
defer can()
|
defer can()
|
||||||
|
|
||||||
ctx, err := Config(ctx)
|
ctx, can, err := Config(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to inject: %w", err)
|
return fmt.Errorf("failed to inject: %w", err)
|
||||||
}
|
}
|
||||||
|
defer can()
|
||||||
|
|
||||||
foos := map[string]func(context.Context) error{
|
foos := map[string]func(context.Context) error{
|
||||||
"server": server.Main,
|
"server": server.Main,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ package db
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
@ -14,7 +17,27 @@ import (
|
||||||
|
|
||||||
const ctxKey = "__db"
|
const ctxKey = "__db"
|
||||||
|
|
||||||
|
func Test(t *testing.T, ctx context.Context) context.Context {
|
||||||
|
p := path.Join(t.TempDir(), strings.ReplaceAll(t.Name()+".db", "/", "_"))
|
||||||
|
ctx, err := Inject(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to inject db %s: %v", p, err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
db, err := extract(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
db.Close()
|
||||||
|
})
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
func Inject(ctx context.Context, conn string) (context.Context, error) {
|
func Inject(ctx context.Context, conn string) (context.Context, error) {
|
||||||
|
if _, err := extract(ctx); err == nil {
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
connctx, can := context.WithTimeout(ctx, 15*time.Second)
|
connctx, can := context.WithTimeout(ctx, 15*time.Second)
|
||||||
defer can()
|
defer can()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue