bid: add some tests and tables

This commit is contained in:
Chris Sexton 2019-07-15 13:39:40 -04:00
parent cdff69abdc
commit 04239ec807
2 changed files with 131 additions and 18 deletions

View File

@ -7,13 +7,31 @@ import (
"github.com/PuerkitoBio/goquery" "github.com/PuerkitoBio/goquery"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/mmcdole/gofeed" "github.com/mmcdole/gofeed"
"github.com/rs/zerolog/log"
"net/http"
"net/url" "net/url"
"strings"
) )
type Webshit struct { type Webshit struct {
db *sqlx.DB db *sqlx.DB
} }
type Weekly []string
type Story struct {
Title string
URL string
}
type Bid struct {
ID int
User string
Title string
URL string
Bid int
}
func New(db *sqlx.DB) *Webshit { func New(db *sqlx.DB) *Webshit {
w := &Webshit{db} w := &Webshit{db}
w.setup() w.setup()
@ -22,10 +40,26 @@ func New(db *sqlx.DB) *Webshit {
// setup will create any necessary SQL tables and populate them with minimal data // setup will create any necessary SQL tables and populate them with minimal data
func (w *Webshit) setup() { func (w *Webshit) setup() {
if _, err := w.db.Exec(`create table if not exists webshit_bids (
id integer primary key,
user string,
title string,
url string,
bid integer
)`); err != nil {
log.Fatal().Err(err)
}
if _, err := w.db.Exec(`create table if not exists webshit_balances (
user string primary key,
balance int,
score int
)`); err != nil {
log.Fatal().Err(err)
}
} }
// GetHeadlines will return the current possible news headlines for bidding // GetHeadlines will return the current possible news headlines for bidding
func (w *Webshit) GetHeadlines() ([]hacknews.Post, error) { func (w *Webshit) GetHeadlines() ([]Story, error) {
news := hacknews.Initializer{Story: "topstories", NbPosts: 10} news := hacknews.Initializer{Story: "topstories", NbPosts: 10}
ids, err := news.GetCodesStory() ids, err := news.GetCodesStory()
if err != nil { if err != nil {
@ -35,10 +69,15 @@ func (w *Webshit) GetHeadlines() ([]hacknews.Post, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return posts, nil var stories []Story
for _, p := range posts {
stories = append(stories, Story{
Title: p.Title,
URL: p.Url,
})
}
return stories, nil
} }
type Weekly []string
// GetWeekly will return the headlines in the last webshit weekly report // GetWeekly will return the headlines in the last webshit weekly report
func (w *Webshit) GetWeekly() (Weekly, error) { func (w *Webshit) GetWeekly() (Weekly, error) {
@ -67,10 +106,63 @@ func (w *Webshit) GetWeekly() (Weekly, error) {
// GetBalances returns the current balance for all known users // GetBalances returns the current balance for all known users
// Any unknown user has a default balance on their first bid // Any unknown user has a default balance on their first bid
func (w *Webshit) GetBalances() { func (w *Webshit) GetBalance(user string) int {
q := `select balance from webshit_balances where user=?`
var balance int
err := w.db.Get(&balance, q, user)
if err != nil {
return 100
}
return balance
} }
// Bid allows a user to place a bid on a particular story // Bid allows a user to place a bid on a particular story
func (w *Webshit) Bid(user string, amount int, URL url.URL) error { func (w *Webshit) Bid(user string, amount int, URL string) error {
return nil bal := w.GetBalance(user)
if bal < amount {
return fmt.Errorf("cannot bid more than balance, %d", bal)
}
story, err := w.getStoryByURL(URL)
if err != nil {
return err
}
// Need a transaction here to deduct from the users balance (or create it)
_, err = w.db.Exec(`insert into webshit_bids (user,title,url,bid) values (?,?,?,?)`,
user, story.Title, story.URL, amount)
return err
}
// getStoryByURL scrapes the URL for a title
func (w *Webshit) getStoryByURL(URL string) (Story, error) {
u, err := url.Parse(URL)
if err != nil {
return Story{}, err
}
if u.Host != "news.ycombinator.com" {
return Story{}, fmt.Errorf("expected HN link")
}
res, err := http.Get(URL)
if err != nil {
return Story{}, err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return Story{}, fmt.Errorf("bad response code: %d", res.StatusCode)
}
// Load the HTML document
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
return Story{}, err
}
// Find the review items
title := doc.Find("title").Text()
title = strings.ReplaceAll(title, " | Hacker News", "")
return Story{
Title: title,
URL: URL,
}, nil
} }

View File

@ -2,6 +2,7 @@ package webshit
import ( import (
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/stretchr/testify/assert"
"testing" "testing"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
@ -10,21 +11,41 @@ import (
func make(t *testing.T) *Webshit { func make(t *testing.T) *Webshit {
db := sqlx.MustOpen("sqlite3", "file::memory:?mode=memory&cache=shared") db := sqlx.MustOpen("sqlite3", "file::memory:?mode=memory&cache=shared")
w := New(db) w := New(db)
if w.db != db { assert.Equal(t, w.db, db)
t.Fail()
}
return w return w
} }
func TestWebshit_GetWeekly(t *testing.T) { func TestWebshit_GetWeekly(t *testing.T) {
w := make(t) w := make(t)
weekly, err := w.GetWeekly() weekly, err := w.GetWeekly()
if err != nil { assert.Nil(t, err)
t.Errorf("Could not get weekly: %s", err) assert.NotEmpty(t, weekly)
t.Fail()
} }
if len(weekly) < 5 {
t.Errorf("Weekly content:\n%+v", weekly) func TestWebshit_GetHeadlines(t *testing.T) {
t.Fail() w := make(t)
headlines, err := w.GetHeadlines()
assert.Nil(t, err)
assert.NotEmpty(t, headlines)
} }
func TestWebshit_getStoryByURL(t *testing.T) {
w := make(t)
expected := "Developer Tropes: “Google Does It”"
s, err := w.getStoryByURL("https://news.ycombinator.com/item?id=20432887")
assert.Nil(t, err)
assert.Equal(t, s.Title, expected)
}
func TestWebshit_getStoryByURL_BadURL(t *testing.T) {
w := make(t)
_, err := w.getStoryByURL("https://google.com")
assert.Error(t, err)
}
func TestWebshit_GetBalance(t *testing.T) {
w := make(t)
expected := 100
actual := w.GetBalance("foo")
assert.Equal(t, expected, actual)
} }