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
|
base: /go
|
||||||
path: src/p83.nl/go/ekster
|
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:
|
steps:
|
||||||
- name: testing
|
- name: testing
|
||||||
image: golang:1.18-alpine
|
image: golang:1.18-alpine
|
||||||
|
@ -18,11 +29,9 @@ steps:
|
||||||
- go version
|
- go version
|
||||||
- apk --no-cache add git
|
- apk --no-cache add git
|
||||||
- go get -d -t ./...
|
- go get -d -t ./...
|
||||||
- go install honnef.co/go/tools/cmd/staticcheck@latest
|
- go build -buildvcs=false p83.nl/go/ekster/cmd/eksterd
|
||||||
- go build p83.nl/go/ekster/cmd/eksterd
|
|
||||||
- go vet ./...
|
- go vet ./...
|
||||||
- go test -v ./...
|
- go test -v ./...
|
||||||
- staticcheck ./...
|
|
||||||
|
|
||||||
- name: publish-personal
|
- name: publish-personal
|
||||||
image: plugins/docker
|
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
|
// TODO(peter): automatically gather this information from login or otherwise
|
||||||
|
databaseURL := "postgres://postgres@database/ekster?sslmode=disable&user=postgres&password=simple"
|
||||||
err := runMigrations()
|
err := runMigrations(databaseURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error with migrations: %s", err)
|
log.Fatalf("Error with migrations: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -205,12 +205,12 @@ func (l Log) Verbose() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMigrations() error {
|
func runMigrations(databaseURL string) error {
|
||||||
d, err := iofs.New(migrations, "db/migrations")
|
d, err := iofs.New(migrations, "db/migrations")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
@ -65,7 +66,7 @@ func (h *micropubHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method == http.MethodPost {
|
if r.Method == http.MethodPost {
|
||||||
var channel string
|
var channel string
|
||||||
|
|
||||||
channel, err = getChannelFromAuthorization(r, conn)
|
channel, err = getChannelFromAuthorization(r, conn, h.Backend.database)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
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)
|
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
|
// backward compatible
|
||||||
sourceID := r.URL.Query().Get("source_id")
|
sourceID := r.URL.Query().Get("source_id")
|
||||||
if sourceID != "" {
|
if sourceID != "" {
|
||||||
channel, err := redis.String(conn.Do("HGET", "sources", sourceID))
|
row := database.QueryRow(`
|
||||||
if err != nil {
|
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 "", errors.Wrapf(err, "could not get channel for sourceID: %s", sourceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return channel, nil
|
return channel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user