Problem: no sources in database
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Solution: add sources in database and tests
This commit is contained in:
parent
974f460f84
commit
caaa069660
15
.drone.yml
15
.drone.yml
|
@ -7,6 +7,17 @@ workspace:
|
|||
base: /go
|
||||
path: src/p83.nl/go/ekster
|
||||
|
||||
services:
|
||||
- name: redis
|
||||
image: redis:5
|
||||
- name: database
|
||||
image: postgres:14
|
||||
environment:
|
||||
POSTGRES_DB: ekster_testing
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: simple
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
|
||||
steps:
|
||||
- name: testing
|
||||
image: golang:1.18-alpine
|
||||
|
@ -18,11 +29,9 @@ steps:
|
|||
- go version
|
||||
- apk --no-cache add git
|
||||
- go get -d -t ./...
|
||||
- go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||
- go build p83.nl/go/ekster/cmd/eksterd
|
||||
- go build -buildvcs=false p83.nl/go/ekster/cmd/eksterd
|
||||
- go vet ./...
|
||||
- go test -v ./...
|
||||
- staticcheck ./...
|
||||
|
||||
- name: publish-personal
|
||||
image: plugins/docker
|
||||
|
|
123
cmd/eksterd/database_test.go
Normal file
123
cmd/eksterd/database_test.go
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Ekster is a microsub server
|
||||
* Copyright (c) 2022 The Ekster authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type DatabaseSuite struct {
|
||||
suite.Suite
|
||||
|
||||
URL string
|
||||
Database *sql.DB
|
||||
|
||||
RedisURL string
|
||||
Redis redis.Conn
|
||||
}
|
||||
|
||||
func (s *DatabaseSuite) SetupSuite() {
|
||||
db, err := sql.Open("postgres", s.URL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
s.Database = db
|
||||
|
||||
conn, err := redis.Dial("tcp", s.RedisURL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
s.Redis = conn
|
||||
_, err = s.Redis.Do("SELECT", "1")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DatabaseSuite) TearDownSuite() {
|
||||
err := s.Database.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = s.Redis.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type databaseSuite struct {
|
||||
DatabaseSuite
|
||||
}
|
||||
|
||||
func (d *databaseSuite) TestGetChannelFromAuthorization() {
|
||||
_, err := d.Database.Exec(`truncate "sources", "channels", "feeds", "subscriptions","items"`)
|
||||
assert.NoError(d.T(), err, "truncate sources, channels, feeds")
|
||||
row := d.Database.QueryRow(`INSERT INTO "channels" (uid, name, created_at, updated_at) VALUES ('abcdef', 'Channel', now(), now()) RETURNING "id"`)
|
||||
var id int
|
||||
err = row.Scan(&id)
|
||||
assert.NoError(d.T(), err, "insert channel")
|
||||
_, err = d.Database.Exec(`INSERT INTO "sources" (channel_id, auth_code, created_at, updated_at) VALUES ($1, '1234', now(), now())`, id)
|
||||
assert.NoError(d.T(), err, "insert sources")
|
||||
|
||||
// source_id found
|
||||
r := httptest.NewRequest("POST", "/micropub?source_id=1234", nil)
|
||||
c, err := getChannelFromAuthorization(r, d.Redis, d.Database)
|
||||
assert.NoError(d.T(), err, "channel from source_id")
|
||||
assert.Equal(d.T(), "abcdef", c, "channel uid found")
|
||||
|
||||
// source_id not found
|
||||
r = httptest.NewRequest("POST", "/micropub?source_id=1111", nil)
|
||||
c, err = getChannelFromAuthorization(r, d.Redis, d.Database)
|
||||
assert.Error(d.T(), err, "channel from authorization header")
|
||||
assert.Equal(d.T(), "", c, "channel uid found")
|
||||
}
|
||||
|
||||
func TestDatabaseSuite(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skip test for database")
|
||||
}
|
||||
|
||||
databaseURL := os.Getenv("DATABASE_TEST_URL")
|
||||
if databaseURL == "" {
|
||||
databaseURL = "host=database user=postgres password=simple dbname=ekster_testing sslmode=disable"
|
||||
}
|
||||
databaseSuite := &databaseSuite{
|
||||
DatabaseSuite{
|
||||
URL: databaseURL,
|
||||
RedisURL: "redis:6379",
|
||||
},
|
||||
}
|
||||
|
||||
databaseURL = "postgres://postgres@database/ekster_testing?sslmode=disable&user=postgres&password=simple"
|
||||
err := runMigrations(databaseURL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
suite.Run(t, databaseSuite)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
DROP TABLE "sources";
|
20
cmd/eksterd/db/migrations/000008_create_table_sources.up.sql
Normal file
20
cmd/eksterd/db/migrations/000008_create_table_sources.up.sql
Normal file
|
@ -0,0 +1,20 @@
|
|||
BEGIN;
|
||||
CREATE OR REPLACE FUNCTION update_timestamp()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
COMMIT;
|
||||
|
||||
CREATE TABLE "sources" (
|
||||
"id" int primary key generated always as identity,
|
||||
"channel_id" int not null,
|
||||
"auth_code" varchar(64) not null,
|
||||
"created_at" timestamp DEFAULT current_timestamp,
|
||||
"updated_at" timestamp DEFAULT current_timestamp
|
||||
);
|
||||
|
||||
CREATE TRIGGER sources_update_timestamp BEFORE INSERT OR UPDATE ON "sources"
|
||||
FOR EACH ROW EXECUTE PROCEDURE update_timestamp();
|
|
@ -167,8 +167,8 @@ func main() {
|
|||
// }
|
||||
|
||||
// TODO(peter): automatically gather this information from login or otherwise
|
||||
|
||||
err := runMigrations()
|
||||
databaseURL := "postgres://postgres@database/ekster?sslmode=disable&user=postgres&password=simple"
|
||||
err := runMigrations(databaseURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Error with migrations: %s", err)
|
||||
}
|
||||
|
@ -205,12 +205,12 @@ func (l Log) Verbose() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func runMigrations() error {
|
||||
func runMigrations(databaseURL string) error {
|
||||
d, err := iofs.New(migrations, "db/migrations")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := migrate.NewWithSourceInstance("iofs", d, "postgres://postgres@database/ekster?sslmode=disable&user=postgres&password=simple")
|
||||
m, err := migrate.NewWithSourceInstance("iofs", d, databaseURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package main
|
|||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
@ -65,7 +66,7 @@ func (h *micropubHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
if r.Method == http.MethodPost {
|
||||
var channel string
|
||||
|
||||
channel, err = getChannelFromAuthorization(r, conn)
|
||||
channel, err = getChannelFromAuthorization(r, conn, h.Backend.database)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
|
@ -165,15 +166,21 @@ func parseIncomingItem(r *http.Request) (*microsub.Item, error) {
|
|||
return nil, fmt.Errorf("content-type %q is not supported", contentType)
|
||||
}
|
||||
|
||||
func getChannelFromAuthorization(r *http.Request, conn redis.Conn) (string, error) {
|
||||
func getChannelFromAuthorization(r *http.Request, conn redis.Conn, database *sql.DB) (string, error) {
|
||||
// backward compatible
|
||||
sourceID := r.URL.Query().Get("source_id")
|
||||
if sourceID != "" {
|
||||
channel, err := redis.String(conn.Do("HGET", "sources", sourceID))
|
||||
if err != nil {
|
||||
row := database.QueryRow(`
|
||||
SELECT c.uid
|
||||
FROM "sources" AS "s"
|
||||
INNER JOIN "channels" AS "c" ON s.channel_id = c.id
|
||||
WHERE "auth_code" = $1
|
||||
`, sourceID)
|
||||
|
||||
var channel string
|
||||
if err := row.Scan(&channel); err == sql.ErrNoRows {
|
||||
return "", errors.Wrapf(err, "could not get channel for sourceID: %s", sourceID)
|
||||
}
|
||||
|
||||
return channel, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user