diff --git a/api/core/joke/getter_test.go b/api/core/joke/getter_test.go index 68d26a4..0de67ae 100644 --- a/api/core/joke/getter_test.go +++ b/api/core/joke/getter_test.go @@ -2,7 +2,9 @@ package joke_test import ( "context" + "encoding/json" "jokes-bapak2-api/core/joke" + "jokes-bapak2-api/core/schema" "testing" "github.com/jackc/pgx/v4" @@ -10,17 +12,36 @@ import ( func TestGetAllJSONJokes(t *testing.T) { defer Teardown() + conn, err := db.Acquire(context.Background()) if err != nil { t.Error("an error was thrown:", err) } + defer conn.Release() err = conn.BeginFunc(context.Background(), func(t pgx.Tx) error { - _, err := t.Exec(context.Background(), "INSERT INTO \"administrators\" (id, key, token, last_used) VALUES ($1, $2, $3, $4), ($5, $6, $7, $8);", administratorsData...) + _, err := t.Exec( + context.Background(), + `INSERT INTO "administrators" + (id, key, token, last_used) + VALUES + ($1, $2, $3, $4), + ($5, $6, $7, $8);`, + administratorsData..., + ) if err != nil { return err } - _, err = t.Exec(context.Background(), "INSERT INTO \"jokesbapak2\" (id, link, creator) VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9);", jokesData...) + _, err = t.Exec( + context.Background(), + `INSERT INTO "jokesbapak2" + (id, link, creator) + VALUES + ($1, $2, $3), + ($4, $5, $6), + ($7, $8, $9);`, + jokesData..., + ) if err != nil { return err } @@ -39,35 +60,267 @@ func TestGetAllJSONJokes(t *testing.T) { if string(j) == "" { t.Error("j should not be empty") } +} +func TestGetRandomJokeFromDB(t *testing.T) { + defer Teardown() + conn, err := db.Acquire(context.Background()) + if err != nil { + t.Error("an error was thrown:", err) + } + defer conn.Release() + + err = conn.BeginFunc(context.Background(), func(t pgx.Tx) error { + _, err := t.Exec( + context.Background(), + `INSERT INTO "administrators" + (id, key, token, last_used) + VALUES + ($1, $2, $3, $4), + ($5, $6, $7, $8);`, + administratorsData..., + ) + if err != nil { + return err + } + _, err = t.Exec( + context.Background(), + `INSERT INTO "jokesbapak2" + (id, link, creator) + VALUES + ($1, $2, $3), + ($4, $5, $6), + ($7, $8, $9);`, + jokesData..., + ) + if err != nil { + return err + } + + return nil + }) + if err != nil { + t.Error("an error was thrown:", err) + } + + j, err := joke.GetRandomJokeFromDB(db, context.Background()) + if err != nil { + t.Error("an error was thrown:", err) + } + + if j == "" { + t.Error("j should not be empty") + } } func TestGetRandomJokeFromCache(t *testing.T) { defer Teardown() - // + jokes := []schema.Joke{ + {ID: 1, Link: "link1", Creator: 1}, + {ID: 2, Link: "link2", Creator: 1}, + {ID: 3, Link: "link3", Creator: 1}, + } + data, err := json.Marshal(jokes) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = memory.Set("jokes", data) + if err != nil { + t.Error("an error was thrown:", err) + } + + j, err := joke.GetRandomJokeFromCache(memory) + if err != nil { + t.Error("an error was thrown:", err) + } + + if j == "" { + t.Error("j should not be empty") + } } -func TestCheckJokesCache(t *testing.T) { +func TestCheckJokesCache_True(t *testing.T) { defer Teardown() - // + + jokes := []schema.Joke{ + {ID: 1, Link: "link1", Creator: 1}, + {ID: 2, Link: "link2", Creator: 1}, + {ID: 3, Link: "link3", Creator: 1}, + } + data, err := json.Marshal(jokes) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = memory.Set("jokes", data) + if err != nil { + t.Error("an error was thrown:", err) + } + + j, err := joke.CheckJokesCache(memory) + if err != nil { + t.Error("an error was thrown:", err) + } + + if j == false { + t.Error("j should not be false") + } } -func TestCheckTotalJokesCache(t *testing.T) { +func TestCheckJokesCache_False(t *testing.T) { defer Teardown() - // + j, err := joke.CheckJokesCache(memory) + if err != nil { + t.Error("an error was thrown:", err) + } + + if j == true { + t.Error("j should not be true") + } +} + +func TestCheckTotalJokesCache_True(t *testing.T) { + defer Teardown() + + err := memory.Set("total", []byte("10")) + if err != nil { + t.Error("an error was thrown:", err) + } + + j, err := joke.CheckTotalJokesCache(memory) + if err != nil { + t.Error("an error was thrown:", err) + } + + if j == false { + t.Error("j should not be false") + } +} + +func TestCheckTotalJokesCache_False(t *testing.T) { + defer Teardown() + j, err := joke.CheckTotalJokesCache(memory) + if err != nil { + t.Error("an error was thrown:", err) + } + + if j == true { + t.Error("j should not be true") + } } func TestGetCachedJokeByID(t *testing.T) { defer Teardown() - // + + jokes := []schema.Joke{ + {ID: 1, Link: "link1", Creator: 1}, + {ID: 2, Link: "link2", Creator: 1}, + {ID: 3, Link: "link3", Creator: 1}, + } + data, err := json.Marshal(jokes) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = memory.Set("jokes", data) + if err != nil { + t.Error("an error was thrown:", err) + } + + j, err := joke.GetCachedJokeByID(memory, 1) + if err != nil { + t.Error("an error was thrown:", err) + } + + if j != "link1" { + t.Error("j should be link1, got:", j) + } + + k, err := joke.GetCachedJokeByID(memory, 4) + if err == nil { + t.Error("an error was not thrown") + } + + if k != "" { + t.Error("k should be empty, got:", k) + } } func TestGetCachedTotalJokes(t *testing.T) { defer Teardown() - // + + err := memory.Set("total", []byte("10")) + if err != nil { + t.Error("an error was thrown:", err) + } + + j, err := joke.GetCachedTotalJokes(memory) + if err != nil { + t.Error("an error was thrown:", err) + } + + if j != 10 { + t.Error("j should be 10, got:", j) + } } func TestCheckJokeExists(t *testing.T) { defer Teardown() - // + conn, err := db.Acquire(context.Background()) + if err != nil { + t.Error("an error was thrown:", err) + } + defer conn.Release() + + err = conn.BeginFunc(context.Background(), func(t pgx.Tx) error { + _, err := t.Exec( + context.Background(), + `INSERT INTO "administrators" + (id, key, token, last_used) + VALUES + ($1, $2, $3, $4), + ($5, $6, $7, $8);`, + administratorsData..., + ) + if err != nil { + return err + } + _, err = t.Exec( + context.Background(), + `INSERT INTO "jokesbapak2" + (id, link, creator) + VALUES + ($1, $2, $3), + ($4, $5, $6), + ($7, $8, $9);`, + jokesData..., + ) + if err != nil { + return err + } + + return nil + }) + if err != nil { + t.Error("an error was thrown:", err) + } + + j, err := joke.CheckJokeExists(db, context.Background(), "1") + if err != nil { + t.Error("an error was thrown:", err) + } + + if j == false { + t.Error("j should not be false") + } + + k, err := joke.CheckJokeExists(db, context.Background(), "4") + if err != nil { + t.Error("an error was thrown:", err) + } + + if k == true { + t.Error("k should not be true") + } } diff --git a/api/core/joke/init_test.go b/api/core/joke/init_test.go index 20b608d..6796606 100644 --- a/api/core/joke/init_test.go +++ b/api/core/joke/init_test.go @@ -8,7 +8,6 @@ import ( "github.com/allegro/bigcache/v3" "github.com/go-redis/redis/v8" - "github.com/jackc/pgx/v4" "github.com/jackc/pgx/v4/pgxpool" ) @@ -65,42 +64,50 @@ func Setup() { } defer conn.Release() - err = conn.BeginFunc(context.Background(), func(tx pgx.Tx) error { - _, err := tx.Exec( - context.Background(), - `CREATE TABLE IF NOT EXISTS administrators ( - id SERIAL PRIMARY KEY, - key VARCHAR(255) NOT NULL UNIQUE, - token TEXT, - last_used VARCHAR(255) - );`, - ) - if err != nil { - return err - } - _, err = tx.Exec( - context.Background(), - `CREATE TABLE IF NOT EXISTS jokesbapak2 ( - id SERIAL PRIMARY KEY, - link TEXT UNIQUE, - creator INT NOT NULL REFERENCES "administrators" ("id") - );`, - ) - if err != nil { - return err - } - _, err = tx.Exec( - context.Background(), - `CREATE TABLE IF NOT EXISTS submission ( - id SERIAL PRIMARY KEY, - link UNIQUE NOT NULL, - created_at VARCHAR(255), - author VARCHAR(255) NOT NULL, - status SMALLINT DEFAULT 0 - );`, - ) - return err - }) + tx, err := conn.Begin(context.Background()) + if err != nil { + panic(err) + } + defer tx.Rollback(context.Background()) + + _, err = tx.Exec( + context.Background(), + `CREATE TABLE IF NOT EXISTS administrators ( + id SERIAL PRIMARY KEY, + key VARCHAR(255) NOT NULL UNIQUE, + token TEXT, + last_used VARCHAR(255) + );`, + ) + if err != nil { + panic(err) + } + _, err = tx.Exec( + context.Background(), + `CREATE TABLE IF NOT EXISTS jokesbapak2 ( + id SERIAL PRIMARY KEY, + link TEXT UNIQUE, + creator INT NOT NULL REFERENCES "administrators" ("id") + );`, + ) + if err != nil { + panic(err) + } + _, err = tx.Exec( + context.Background(), + `CREATE TABLE IF NOT EXISTS submission ( + id SERIAL PRIMARY KEY, + link UNIQUE NOT NULL, + created_at VARCHAR(255), + author VARCHAR(255) NOT NULL, + status SMALLINT DEFAULT 0 + );`, + ) + if err != nil { + panic(err) + } + + err = tx.Commit(context.Background()) if err != nil { panic(err) } @@ -123,18 +130,26 @@ func TruncateTable(db *pgxpool.Pool, cache *redis.Client, memory *bigcache.BigCa } defer conn.Release() - err = conn.BeginFunc(context.Background(), func(tx pgx.Tx) error { - _, err := tx.Exec(context.Background(), "TRUNCATE TABLE submission;") - if err != nil { - return err - } - _, err = tx.Exec(context.Background(), "TRUNCATE TABLE jokesbapak2;") - if err != nil { - return err - } - _, err = tx.Exec(context.Background(), "TRUNCATE TABLE administrators;") + tx, err := conn.Begin(context.Background()) + if err != nil { return err - }) + } + defer tx.Rollback(context.Background()) + + _, err = tx.Exec(context.Background(), "TRUNCATE TABLE submission;") + if err != nil { + return err + } + _, err = tx.Exec(context.Background(), "TRUNCATE TABLE jokesbapak2;") + if err != nil { + return err + } + _, err = tx.Exec(context.Background(), "TRUNCATE TABLE administrators;") + if err != nil { + return err + } + + err = tx.Commit(context.Background()) if err != nil { return err } diff --git a/api/core/joke/setter.go b/api/core/joke/setter.go index 217a348..c8ef51a 100644 --- a/api/core/joke/setter.go +++ b/api/core/joke/setter.go @@ -106,7 +106,7 @@ func DeleteSingleJoke(db *pgxpool.Pool, ctx context.Context, id int) error { return nil } -func UpdateJoke(db *pgxpool.Pool, ctx context.Context, link, creator string) error { +func UpdateJoke(db *pgxpool.Pool, ctx context.Context, newJoke schema.Joke) error { conn, err := db.Acquire(ctx) if err != nil { return err @@ -116,8 +116,9 @@ func UpdateJoke(db *pgxpool.Pool, ctx context.Context, link, creator string) err var query = squirrel.StatementBuilder.PlaceholderFormat(squirrel.Dollar) sql, args, err := query. Update("jokesbapak2"). - Set("link", link). - Set("creator", creator). + Set("link", newJoke.Link). + Set("creator", newJoke.Creator). + Where(squirrel.Eq{"id": newJoke.ID}). ToSql() if err != nil { return err diff --git a/api/core/joke/setter_test.go b/api/core/joke/setter_test.go new file mode 100644 index 0000000..c4dc887 --- /dev/null +++ b/api/core/joke/setter_test.go @@ -0,0 +1,222 @@ +package joke_test + +import ( + "context" + "jokes-bapak2-api/core/joke" + "jokes-bapak2-api/core/schema" + "testing" + + "github.com/jackc/pgx/v4" +) + +func TestSetAllJSONJoke(t *testing.T) { + defer Teardown() + + conn, err := db.Acquire(context.Background()) + if err != nil { + t.Error("an error was thrown:", err) + } + defer conn.Release() + + err = conn.BeginFunc(context.Background(), func(t pgx.Tx) error { + _, err := t.Exec( + context.Background(), + `INSERT INTO "administrators" + (id, key, token, last_used) + VALUES + ($1, $2, $3, $4), + ($5, $6, $7, $8);`, + administratorsData..., + ) + if err != nil { + return err + } + _, err = t.Exec( + context.Background(), + `INSERT INTO "jokesbapak2" + (id, link, creator) + VALUES + ($1, $2, $3), + ($4, $5, $6), + ($7, $8, $9);`, + jokesData..., + ) + if err != nil { + return err + } + + return nil + }) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = joke.SetAllJSONJoke(db, context.Background(), memory) + if err != nil { + t.Error("an error was thrown:", err) + } +} + +func TestSetTotalJoke(t *testing.T) { + defer Teardown() + + conn, err := db.Acquire(context.Background()) + if err != nil { + t.Error("an error was thrown:", err) + } + defer conn.Release() + + err = conn.BeginFunc(context.Background(), func(t pgx.Tx) error { + _, err := t.Exec( + context.Background(), + `INSERT INTO "administrators" + (id, key, token, last_used) + VALUES + ($1, $2, $3, $4), + ($5, $6, $7, $8);`, + administratorsData..., + ) + if err != nil { + return err + } + _, err = t.Exec( + context.Background(), + `INSERT INTO "jokesbapak2" + (id, link, creator) + VALUES + ($1, $2, $3), + ($4, $5, $6), + ($7, $8, $9);`, + jokesData..., + ) + if err != nil { + return err + } + + return nil + }) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = joke.SetTotalJoke(db, context.Background(), memory) + if err != nil { + t.Error("an error was thrown:", err) + } +} + +func TestInsertJokeIntoDB(t *testing.T) { + defer Teardown() + + data := schema.Joke{ + ID: 1, + Link: "link1", + Creator: 1, + } + err := joke.InsertJokeIntoDB(db, context.Background(), data) + if err != nil { + t.Error("an error was thrown:", err) + } +} + +func TestDeleteSingleJoke(t *testing.T) { + defer Teardown() + + conn, err := db.Acquire(context.Background()) + if err != nil { + t.Error("an error was thrown:", err) + } + defer conn.Release() + + err = conn.BeginFunc(context.Background(), func(t pgx.Tx) error { + _, err := t.Exec( + context.Background(), + `INSERT INTO "administrators" + (id, key, token, last_used) + VALUES + ($1, $2, $3, $4), + ($5, $6, $7, $8);`, + administratorsData..., + ) + if err != nil { + return err + } + _, err = t.Exec( + context.Background(), + `INSERT INTO "jokesbapak2" + (id, link, creator) + VALUES + ($1, $2, $3), + ($4, $5, $6), + ($7, $8, $9);`, + jokesData..., + ) + if err != nil { + return err + } + + return nil + }) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = joke.DeleteSingleJoke(db, context.Background(), 1) + if err != nil { + t.Error("an error was thrown:", err) + } +} + +func TestUpdateJoke(t *testing.T) { + defer Teardown() + + conn, err := db.Acquire(context.Background()) + if err != nil { + t.Error("an error was thrown:", err) + } + defer conn.Release() + + err = conn.BeginFunc(context.Background(), func(t pgx.Tx) error { + _, err := t.Exec( + context.Background(), + `INSERT INTO "administrators" + (id, key, token, last_used) + VALUES + ($1, $2, $3, $4), + ($5, $6, $7, $8);`, + administratorsData..., + ) + if err != nil { + return err + } + _, err = t.Exec( + context.Background(), + `INSERT INTO "jokesbapak2" + (id, link, creator) + VALUES + ($1, $2, $3), + ($4, $5, $6), + ($7, $8, $9);`, + jokesData..., + ) + if err != nil { + return err + } + + return nil + }) + if err != nil { + t.Error("an error was thrown:", err) + } + + newJoke := schema.Joke{ + ID: 1, + Link: "link1", + Creator: 1, + } + + err = joke.UpdateJoke(db, context.Background(), newJoke) + if err != nil { + t.Error("an error was thrown:", err) + } +} diff --git a/api/core/validator/author_test.go b/api/core/validator/author_test.go new file mode 100644 index 0000000..cc1408b --- /dev/null +++ b/api/core/validator/author_test.go @@ -0,0 +1,40 @@ +package validator_test + +import ( + "jokes-bapak2-api/core/validator" + "testing" +) + +func TestValidateAuthor_False(t *testing.T) { + v := validator.ValidateAuthor("Test Author") + if v != false { + t.Error("Expected false, got true") + } + + v = validator.ValidateAuthor("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.") + if v != false { + t.Error("Expected false, got true") + } + + v = validator.ValidateAuthor("") + if v != false { + t.Error("Expected false, got true") + } + + v = validator.ValidateAuthor("Test ") + if v != false { + t.Error("Expected false, got true") + } +} + +func TestValidateAuthor_True(t *testing.T) { + v := validator.ValidateAuthor("Test Author ") + if v != true { + t.Error("Expected true, got false") + } +} diff --git a/api/core/validator/image_test.go b/api/core/validator/image_test.go new file mode 100644 index 0000000..8bf4143 --- /dev/null +++ b/api/core/validator/image_test.go @@ -0,0 +1,50 @@ +package validator_test + +import ( + "jokes-bapak2-api/core/validator" + "testing" + + "github.com/gojek/heimdall/v7/httpclient" +) + +func TestCheckImageValidity_Error(t *testing.T) { + client := httpclient.NewClient() + b, err := validator.CheckImageValidity(client, "http://lorem-ipsum") + if err == nil { + t.Error("Expected error, got nil") + } + + if b { + t.Error("Expected false, got true") + } + + if err.Error() != "URL must use HTTPS protocol" { + t.Error("Expected error to be URL must use HTTPS protocol, got:", err) + } +} + +func TestCheckImageValidity_False(t *testing.T) { + client := httpclient.NewClient() + + b, err := validator.CheckImageValidity(client, "https://www.youtube.com/watch?v=yTJV6T37Reo") + if err != nil { + t.Error("Expected nil, got error") + } + + if b { + t.Error("Expected false, got true") + } +} + +func TestCheckImageValidity_True(t *testing.T) { + client := httpclient.NewClient() + + b, err := validator.CheckImageValidity(client, "https://i.ytimg.com/vi/yTJV6T37Reo/maxresdefault.jpg") + if err != nil { + t.Error("Expected nil, got error") + } + + if !b { + t.Error("Expected true, got false") + } +} diff --git a/api/handler/joke/joke_update.go b/api/handler/joke/joke_update.go index d586553..2562a89 100644 --- a/api/handler/joke/joke_update.go +++ b/api/handler/joke/joke_update.go @@ -4,6 +4,7 @@ import ( core "jokes-bapak2-api/core/joke" "jokes-bapak2-api/core/schema" "jokes-bapak2-api/core/validator" + "strconv" "github.com/gofiber/fiber/v2" ) @@ -45,7 +46,23 @@ func (d *Dependencies) UpdateJoke(c *fiber.Ctx) error { }) } - err = core.UpdateJoke(d.DB, c.Context(), body.Link, c.Locals("userID").(string)) + newID, err := strconv.Atoi(id) + if err != nil { + return err + } + + newCreator, err := strconv.Atoi(c.Locals("userID").(string)) + if err != nil { + return err + } + + updatedJoke := schema.Joke{ + Link: body.Link, + Creator: newCreator, + ID: newID, + } + + err = core.UpdateJoke(d.DB, c.Context(), updatedJoke) if err != nil { return err }