<commit_before>package norwegiantime

import (
	"errors"
	"time"
	"fmt"
)

// Gauss's algorithm for finding easter day for a given year
func easterDay(year int) (month, day int, err error) {
	// Source: http://no.it.programmering.delphi.narkive.com/oDY0xYOW/algoritme-for-norske-bevegelige-helligdager
	if (year < 1583) || (year > 4199) {
		return 0, 0, errors.New("year out of range")
	}
	g := (year % 19) + 1            // Golden year number
	c := (year / 100) + 1           // Century number
	x := (3 * c >> 2) - 12          // Lost leap years correction
	z := ((8*c + 5) / 25) - 5       // Moon's orbit correction
	d := ((5 * year) >> 2) - x - 10 // Find a Sunday in March
	e := (11*g + 20 + z - x) % 30   // Epact
	if (e == 24) || ((e == 25) && (g > 11)) {
		e++
	}
	n := 44 - e // Full Moon
	if n < 21 {
		n += 30
	}
	day = n + 7 - ((d + n) % 7) // Advance to Sunday
	month = 3
	if day > 31 {
		month++
		day -= 31
	}
	return month, day, nil
}

func EasterDate(year int) (time.Time, error) {
	month, day, err := easterDay(year)
	return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC), err
}

// Checks if the given time is easter day
func IsEaster(t time.Time) bool {
	eastermonth, easterday, err := easterDay(t.Year())
	if err != nil {
		// If the year is out of range, treat it like there isn't an easter day
		return false
	}
	return (t.Month() == time.Month(eastermonth)) && (t.Day() == easterday)
}

// Checks if the given time is at the given month and day
func At(t time.Time, month, day int) bool {
	return (t.Month() == time.Month(month)) && (t.Day() == day)
}

// Checks if the two given times are at the same months and days
func AtDate(t, when time.Time) bool {
	return (t.Month() == when.Month()) && (t.Day() == when.Day())
}

// Checks if a day is at easterday +- a few days
func AtEasterPlus(t time.Time, days int) bool {
	year := t.Year()
	eastermonth, easterday, err := easterDay(year)
	if err != nil {
		// If the year is out of range, treat it like there isn't an easter day
		return false
	}
	easter := time.Date(year, time.Month(eastermonth), easterday, 0, 0, 0, 0, time.UTC)
	when := easter.AddDate(0, 0, days)
	return AtDate(t, when)
}

// Return the number of sundays from day t, +- a few days
func SundaysInPeriod(t time.Time, days int) int {
	sundayCounter := 0
	when := t
	if days < 0 {
		for i := days; i <= 0; i++ {
			when = t.AddDate(0, 0, i)
			if when.Weekday() == time.Sunday {
				sundayCounter++
			}
		}
	} else {
		for i := 0; i <= days; i++ {
			when = t.AddDate(0, 0, i)
			if when.Weekday() == time.Sunday {
				sundayCounter++
			}
		}
	}
	return sundayCounter
}

// Check if a day is at easterday +- a few days, not counting sundays
// TODO: test
func AtEasterPlusNotCountingSundays(t time.Time, days int) bool {
	adjustedDays := days
	if days < 0 {
		adjustedDays += SundaysInPeriod(t, days)
	} else {
		adjustedDays -= SundaysInPeriod(t, days)
	}
	return AtEasterPlus(t, adjustedDays)
}

// Checks if the given year, month and day is a "red" in the Norwegian calendar
// Returns true/false and a description
func RedDay(year int, month time.Month, day int) (bool, string) {
	return RedDate(time.Date(year, month, day, 0, 0, 0, 0, time.UTC))
}

// Find a preceeding sunday
func searchBackwardsForSunday(t time.Time) (time.Time, error) {
	// Start with the day before the given date
	current := t.AddDate(0, 0, -1)

	// Stay within the same year
	for current.Year() == t.Year() {
		// Check if it's a Sunday
		if current.Weekday() == time.Sunday {
			// Found one
			return current, nil
		}

		// Go the previous day
		current = current.AddDate(0, 0, -1)
	}

	// This should never happen, since we will only be searching
	// from easter day and backwards
	return t, errors.New("Could not find an earlier Sunday!")
}

// Checks if the given date is at Palmesøndag
// Palmesøndag is the Sunday before easter (Første Påskedag)
func AtPalmesøndag(t time.Time) bool {
	easter, err := EasterDate(t.Year())
	if err != nil {
		// If the year is out of range, treat it like there isn't an easter day
		return false
	}
	palmesøndag, err := searchBackwardsForSunday(easter)
	return AtDate(t, palmesøndag)
}

// Find the Nth sunday of a given year and month
func nthSundayOfMonth(t time.Time, n int) (time.Time, error) {

	sundaycounter := 0

	// Start at the first day in the given month
	current := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.UTC)

	// As long as we are in the same month
	for current.Month() == t.Month() {

		// Is it a Sunday?
		if current.Weekday() == time.Sunday {
			sundaycounter++
		}

		// Is it the Nth sunday?
		if sundaycounter == n {
			return current, nil
		}

		// Advance to the next day
		current = current.AddDate(0, 0, 1)
	}

	return t, errors.New(fmt.Sprintf("Could not find the %dth Sunday in %s", n, t.Month().String()))

}

// Morsdag, 2nd Sunday in February
func AtMorsdag(t time.Time) bool {
	if t.Month() != time.February {
		return false
	}
	nthSunday, err := nthSundayOfMonth(t, 2)
	if err != nil {
		return false
	}
	if AtDate(t, nthSunday) {
		return true
	}
	return false
}

// Farsdag, 2nd Sunday in November
func AtFarsdag(t time.Time) bool {
	if t.Month() != time.November {
		return false
	}
	nthSunday, err := nthSundayOfMonth(t, 2)
	if err != nil {
		return false
	}
	if AtDate(t, nthSunday) {
		return true
	}
	return false
}

// Dates that are not red, but not completely ordinary either
func NotableDate(date time.Time) (bool, string) {

	// Askeonsdag (fasten begynner)
	if AtEasterPlus(date, -46) {
		return true, "Askeonsdag"
	}

	// Påskeaften (fasten slutter)
	if AtEasterPlus(date, -1) {
		return true, "Påskeaften"
	}

	// Fetetirsdag
	if AtEasterPlus(date, -47) {
		return true, "Fetetirsdag"
	}

	// Fastelavn
	if AtEasterPlus(date, -49) {
		return true, "Fastelavn"
	}

	// Fastelavnsøndag

	// Blåmandag

	// Morsdag
	if AtMorsdag(date) {
		return true, "Morsdag"
	}

	// Farsdag
	if AtFarsdag(date) {
		return true, "Farsdag"
	}

	// Sankthansaften
	if At(date, 6, 23) {
		return true, "Sankthansaften"
	}

	return false, ""
}

// Checks if a given date is a "red day" in the Norwegian calendar
// Returns true/false and a description
func RedDate(date time.Time) (bool, string) {
	// Source: http://www.diskusjon.no/index.php?showtopic=1084239
	// Source: http://no.wikipedia.org/wiki/Helligdager_i_Norge

	// Første nyttårsdag, 1. januar
	if At(date, 1, 1) {
		return true, "Første nyttårsdag"
	}

	// Palmesøndag
	if AtPalmesøndag(date) {
		return true, "Palmesøndag"
	}

	// Skjærtorsdag (easter - 3d)
	if AtEasterPlus(date, -3) {
		return true, "Skjærtorsdag"
	}

	// Langfredag (easter - 2d)
	if AtEasterPlus(date, -2) {
		return true, "Langfredag"
	}

	// Første påskedag
	if AtEasterPlus(date, 0) {
		return true, "Første påskedag"
	}

	// Andre påskedag (easter + 1d)
	if AtEasterPlus(date, 1) {
		return true, "Andre påskedag"
	}

	// Arbeidernes internasjonale kampdag, 1. mai
	if At(date, 5, 1) {
		return true, "Arbeidernes internasjonale kampdag"
	}

	// Grunnlovsdagen, 17. mai
	if At(date, 5, 17) {
		return true, "Grunnlovsdagen"
	}

	// Kristi himmelfartsdag (40. påskedag: easter + 39d)
	if AtEasterPlus(date, 39) {
		return true, "Kristi himmelfartsdag"
	}

	// Første pinsedag (50. påskedag: easter + 49d)
	if AtEasterPlus(date, 49) {
		return true, "Første pinsedag"
	}

	// Andre pinsedag (51. påskedag: easter + 50d)
	if AtEasterPlus(date, 50) {
		return true, "Andre pinsedag"
	}

	// Første juledag (25. desember)
	if At(date, 12, 25) {
		return true, "Første juledag"
	}

	// Andre juledag (26. desember)
	if At(date, 12, 26) {
		return true, "Andre juledag"
	}

	// Sundays
	if date.Weekday() == 0 {
		return true, "Søndag"
	}

	// Normal days
	return false, ""
}

// Finds the norwegian name for a day of the week
// Note that time.Weekday starts at 0 with Sunday, not Monday
func NorwegianName(dayoftheweek time.Weekday) string {
	days := []string{"søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"}
	return days[int(dayoftheweek)]
}
<commit_msg>Minor changes<commit_after>package norwegiantime

import (
	"errors"
	"time"
	"fmt"
)

// Gauss's algorithm for finding easter day for a given year
func easterDay(year int) (month, day int, err error) {
	// Source: http://no.it.programmering.delphi.narkive.com/oDY0xYOW/algoritme-for-norske-bevegelige-helligdager
	if (year < 1583) || (year > 4199) {
		return 0, 0, errors.New("year out of range")
	}
	g := (year % 19) + 1            // Golden year number
	c := (year / 100) + 1           // Century number
	x := (3 * c >> 2) - 12          // Lost leap years correction
	z := ((8*c + 5) / 25) - 5       // Moon's orbit correction
	d := ((5 * year) >> 2) - x - 10 // Find a Sunday in March
	e := (11*g + 20 + z - x) % 30   // Epact
	if (e == 24) || ((e == 25) && (g > 11)) {
		e++
	}
	n := 44 - e // Full Moon
	if n < 21 {
		n += 30
	}
	day = n + 7 - ((d + n) % 7) // Advance to Sunday
	month = 3
	if day > 31 {
		month++
		day -= 31
	}
	return month, day, nil
}

func EasterDate(year int) (time.Time, error) {
	month, day, err := easterDay(year)
	return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC), err
}

// Checks if the given time is easter day
func IsEaster(t time.Time) bool {
	eastermonth, easterday, err := easterDay(t.Year())
	if err != nil {
		// If the year is out of range, treat it like there isn't an easter day
		return false
	}
	return (t.Month() == time.Month(eastermonth)) && (t.Day() == easterday)
}

// Checks if the given time is at the given month and day
func At(t time.Time, month, day int) bool {
	return (t.Month() == time.Month(month)) && (t.Day() == day)
}

// Checks if the two given times are at the same months and days
func AtDate(t, when time.Time) bool {
	return (t.Month() == when.Month()) && (t.Day() == when.Day())
}

// Checks if a day is at easterday +- a few days
func AtEasterPlus(t time.Time, days int) bool {
	year := t.Year()
	eastermonth, easterday, err := easterDay(year)
	if err != nil {
		// If the year is out of range, treat it like there isn't an easter day
		return false
	}
	easter := time.Date(year, time.Month(eastermonth), easterday, 0, 0, 0, 0, time.UTC)
	when := easter.AddDate(0, 0, days)
	return AtDate(t, when)
}

// Return the number of sundays from day t, +- a few days
func sundaysInPeriod(t time.Time, days int) int {
	sundayCounter := 0
	when := t
	if days < 0 {
		for i := days; i <= 0; i++ {
			when = t.AddDate(0, 0, i)
			if when.Weekday() == time.Sunday {
				sundayCounter++
			}
		}
	} else {
		for i := 0; i <= days; i++ {
			when = t.AddDate(0, 0, i)
			if when.Weekday() == time.Sunday {
				sundayCounter++
			}
		}
	}
	return sundayCounter
}

// Checks if the given year, month and day is a "red" in the Norwegian calendar
// Returns true/false and a description
func RedDay(year int, month time.Month, day int) (bool, string) {
	return RedDate(time.Date(year, month, day, 0, 0, 0, 0, time.UTC))
}

// Find a preceeding sunday
func searchBackwardsForSunday(t time.Time) (time.Time, error) {
	// Start with the day before the given date
	current := t.AddDate(0, 0, -1)

	// Stay within the same year
	for current.Year() == t.Year() {
		// Check if it's a Sunday
		if current.Weekday() == time.Sunday {
			// Found one
			return current, nil
		}

		// Go the previous day
		current = current.AddDate(0, 0, -1)
	}

	// This should never happen, since we will only be searching
	// from easter day and backwards
	return t, errors.New("Could not find an earlier Sunday!")
}

// Checks if the given date is at Palmesøndag
// Palmesøndag is the Sunday before easter (Første Påskedag)
func AtPalmesøndag(t time.Time) bool {
	easter, err := EasterDate(t.Year())
	if err != nil {
		// If the year is out of range, treat it like there isn't an easter day
		return false
	}
	palmesøndag, err := searchBackwardsForSunday(easter)
	return AtDate(t, palmesøndag)
}

// Find the Nth sunday of a given year and month
func nthSundayOfMonth(t time.Time, n int) (time.Time, error) {

	sundaycounter := 0

	// Start at the first day in the given month
	current := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.UTC)

	// As long as we are in the same month
	for current.Month() == t.Month() {

		// Is it a Sunday?
		if current.Weekday() == time.Sunday {
			sundaycounter++
		}

		// Is it the Nth sunday?
		if sundaycounter == n {
			return current, nil
		}

		// If it's a sunday, advance one week forward
		if current.Weekday() == time.Sunday {
			current = current.AddDate(0, 0, 7)
			continue
		}

		// Advance to the next day
		current = current.AddDate(0, 0, 1)
	}

	return t, errors.New(fmt.Sprintf("Could not find the %dth Sunday in %s", n, t.Month().String()))

}

// Morsdag, 2nd Sunday in February
func AtMorsdag(t time.Time) bool {
	if t.Month() != time.February {
		return false
	}
	nthSunday, err := nthSundayOfMonth(t, 2)
	if err != nil {
		return false
	}
	if AtDate(t, nthSunday) {
		return true
	}
	return false
}

// Farsdag, 2nd Sunday in November
func AtFarsdag(t time.Time) bool {
	if t.Month() != time.November {
		return false
	}
	nthSunday, err := nthSundayOfMonth(t, 2)
	if err != nil {
		return false
	}
	if AtDate(t, nthSunday) {
		return true
	}
	return false
}

// Finds the norwegian name for a day of the week
// Note that time.Weekday starts at 0 with Sunday, not Monday
func NorwegianName(dayoftheweek time.Weekday) string {
	days := []string{"søndag", "mandag", "tirsdag", "onsdag", "torsdag", "fredag", "lørdag"}
	return days[int(dayoftheweek)]
}

// Dates that are not red, but not completely ordinary either
func NotableDate(date time.Time) (bool, string) {

	// Askeonsdag (fasten begynner)
	if AtEasterPlus(date, -46) {
		return true, "Askeonsdag"
	}

	// Påskeaften (fasten slutter)
	if AtEasterPlus(date, -1) {
		return true, "Påskeaften"
	}

	// Feitetirsdag
	if AtEasterPlus(date, -47) {
		return true, "Feitetirsdag"
	}

	// Fastelavn
	if AtEasterPlus(date, -49) {
		return true, "Fastelavn"
	}

	// Fastelavnsøndag

	// Blåmandag

	// Morsdag
	if AtMorsdag(date) {
		return true, "Morsdag"
	}

	// Farsdag
	if AtFarsdag(date) {
		return true, "Farsdag"
	}

	// Sankthansaften
	if At(date, 6, 23) {
		return true, "Sankthansaften"
	}

	return false, ""
}

// Checks if a given date is a "red day" in the Norwegian calendar
// Returns true/false and a description
func RedDate(date time.Time) (bool, string) {
	// Source: http://www.diskusjon.no/index.php?showtopic=1084239
	// Source: http://no.wikipedia.org/wiki/Helligdager_i_Norge

	// Første nyttårsdag, 1. januar
	if At(date, 1, 1) {
		return true, "Første nyttårsdag"
	}

	// Palmesøndag
	if AtPalmesøndag(date) {
		return true, "Palmesøndag"
	}

	// Skjærtorsdag (easter - 3d)
	if AtEasterPlus(date, -3) {
		return true, "Skjærtorsdag"
	}

	// Langfredag (easter - 2d)
	if AtEasterPlus(date, -2) {
		return true, "Langfredag"
	}

	// Første påskedag
	if AtEasterPlus(date, 0) {
		return true, "Første påskedag"
	}

	// Andre påskedag (easter + 1d)
	if AtEasterPlus(date, 1) {
		return true, "Andre påskedag"
	}

	// Arbeidernes internasjonale kampdag, 1. mai
	if At(date, 5, 1) {
		return true, "Arbeidernes internasjonale kampdag"
	}

	// Grunnlovsdagen, 17. mai
	if At(date, 5, 17) {
		return true, "Grunnlovsdagen"
	}

	// Kristi himmelfartsdag (40. påskedag: easter + 39d)
	if AtEasterPlus(date, 39) {
		return true, "Kristi himmelfartsdag"
	}

	// Første pinsedag (50. påskedag: easter + 49d)
	if AtEasterPlus(date, 49) {
		return true, "Første pinsedag"
	}

	// Andre pinsedag (51. påskedag: easter + 50d)
	if AtEasterPlus(date, 50) {
		return true, "Andre pinsedag"
	}

	// Første juledag (25. desember)
	if At(date, 12, 25) {
		return true, "Første juledag"
	}

	// Andre juledag (26. desember)
	if At(date, 12, 26) {
		return true, "Andre juledag"
	}

	// Sundays
	if date.Weekday() == 0 {
		return true, "Søndag"
	}

	// Normal days
	return false, ""
}

<|endoftext|>


<commit_before>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package store

import (
	"github.com/mattermost/platform/model"
	"testing"
)

func TestSessionStoreSave(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()

	if err := (<-store.Session().Save(&s1)).Err; err != nil {
		t.Fatal(err)
	}
}

func TestSessionGet(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	s2 := model.Session{}
	s2.UserId = s1.UserId
	s2.TeamId = s1.TeamId
	Must(store.Session().Save(&s2))

	s3 := model.Session{}
	s3.UserId = s1.UserId
	s3.TeamId = s1.TeamId
	s3.ExpiresAt = 1
	Must(store.Session().Save(&s3))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	if rs2 := (<-store.Session().GetSessions(s1.UserId)); rs2.Err != nil {
		t.Fatal(rs2.Err)
	} else {
		if len(rs2.Data.([]*model.Session)) != 2 {
			t.Fatal("should match len")
		}
	}

}

func TestSessionRemove(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	Must(store.Session().Remove(s1.Id))

	if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil {
		t.Fatal("should have been removed")
	}
}

func TestSessionRemoveAll(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	Must(store.Session().RemoveAllSessionsForTeam(s1.TeamId))

	if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil {
		t.Fatal("should have been removed")
	}
}

func TestSessionRemoveByUser(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	Must(store.Session().PermanentDeleteSessionsByUser(s1.UserId))

	if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil {
		t.Fatal("should have been removed")
	}
}

func TestSessionRemoveToken(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	Must(store.Session().Remove(s1.Token))

	if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil {
		t.Fatal("should have been removed")
	}

	if rs3 := (<-store.Session().GetSessions(s1.UserId)); rs3.Err != nil {
		t.Fatal(rs3.Err)
	} else {
		if len(rs3.Data.([]*model.Session)) != 0 {
			t.Fatal("should match len")
		}
	}
}

func TestSessionUpdateDeviceId(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs1.Err != nil {
		t.Fatal(rs1.Err)
	}

	s2 := model.Session{}
	s2.UserId = model.NewId()
	s2.TeamId = model.NewId()
	Must(store.Session().Save(&s2))

	if rs2 := (<-store.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs2.Err != nil {
		t.Fatal(rs2.Err)
	}
}

func TestSessionStoreUpdateLastActivityAt(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if err := (<-store.Session().UpdateLastActivityAt(s1.Id, 1234567890)).Err; err != nil {
		t.Fatal(err)
	}

	if r1 := <-store.Session().Get(s1.Id); r1.Err != nil {
		t.Fatal(r1.Err)
	} else {
		if r1.Data.(*model.Session).LastActivityAt != 1234567890 {
			t.Fatal("LastActivityAt not updated correctly")
		}
	}

}

func TestSessionCount(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if r1 := <-store.Session().AnalyticsSessionCount(""); r1.Err != nil {
		t.Fatal(r1.Err)
	} else {
		if r1.Data.(int64) == 0 {
			t.Fatal("should have at least 1 session")
		}
	}

	if r2 := <-store.Session().AnalyticsSessionCount(s1.TeamId); r2.Err != nil {
		t.Fatal(r2.Err)
	} else {
		if r2.Data.(int64) != 1 {
			t.Fatal("should have 1 session")
		}
	}
}
<commit_msg>Fix unit test for session counting<commit_after>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package store

import (
	"github.com/mattermost/platform/model"
	"testing"
)

func TestSessionStoreSave(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()

	if err := (<-store.Session().Save(&s1)).Err; err != nil {
		t.Fatal(err)
	}
}

func TestSessionGet(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	s2 := model.Session{}
	s2.UserId = s1.UserId
	s2.TeamId = s1.TeamId
	Must(store.Session().Save(&s2))

	s3 := model.Session{}
	s3.UserId = s1.UserId
	s3.TeamId = s1.TeamId
	s3.ExpiresAt = 1
	Must(store.Session().Save(&s3))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	if rs2 := (<-store.Session().GetSessions(s1.UserId)); rs2.Err != nil {
		t.Fatal(rs2.Err)
	} else {
		if len(rs2.Data.([]*model.Session)) != 2 {
			t.Fatal("should match len")
		}
	}

}

func TestSessionRemove(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	Must(store.Session().Remove(s1.Id))

	if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil {
		t.Fatal("should have been removed")
	}
}

func TestSessionRemoveAll(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	Must(store.Session().RemoveAllSessionsForTeam(s1.TeamId))

	if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil {
		t.Fatal("should have been removed")
	}
}

func TestSessionRemoveByUser(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	Must(store.Session().PermanentDeleteSessionsByUser(s1.UserId))

	if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil {
		t.Fatal("should have been removed")
	}
}

func TestSessionRemoveToken(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().Get(s1.Id)); rs1.Err != nil {
		t.Fatal(rs1.Err)
	} else {
		if rs1.Data.(*model.Session).Id != s1.Id {
			t.Fatal("should match")
		}
	}

	Must(store.Session().Remove(s1.Token))

	if rs2 := (<-store.Session().Get(s1.Id)); rs2.Err == nil {
		t.Fatal("should have been removed")
	}

	if rs3 := (<-store.Session().GetSessions(s1.UserId)); rs3.Err != nil {
		t.Fatal(rs3.Err)
	} else {
		if len(rs3.Data.([]*model.Session)) != 0 {
			t.Fatal("should match len")
		}
	}
}

func TestSessionUpdateDeviceId(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if rs1 := (<-store.Session().UpdateDeviceId(s1.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs1.Err != nil {
		t.Fatal(rs1.Err)
	}

	s2 := model.Session{}
	s2.UserId = model.NewId()
	s2.TeamId = model.NewId()
	Must(store.Session().Save(&s2))

	if rs2 := (<-store.Session().UpdateDeviceId(s2.Id, model.PUSH_NOTIFY_APPLE+":1234567890")); rs2.Err != nil {
		t.Fatal(rs2.Err)
	}
}

func TestSessionStoreUpdateLastActivityAt(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	Must(store.Session().Save(&s1))

	if err := (<-store.Session().UpdateLastActivityAt(s1.Id, 1234567890)).Err; err != nil {
		t.Fatal(err)
	}

	if r1 := <-store.Session().Get(s1.Id); r1.Err != nil {
		t.Fatal(r1.Err)
	} else {
		if r1.Data.(*model.Session).LastActivityAt != 1234567890 {
			t.Fatal("LastActivityAt not updated correctly")
		}
	}

}

func TestSessionCount(t *testing.T) {
	Setup()

	s1 := model.Session{}
	s1.UserId = model.NewId()
	s1.TeamId = model.NewId()
	s1.ExpiresAt = model.GetMillis() + 100000
	Must(store.Session().Save(&s1))

	if r1 := <-store.Session().AnalyticsSessionCount(""); r1.Err != nil {
		t.Fatal(r1.Err)
	} else {
		if r1.Data.(int64) == 0 {
			t.Fatal("should have at least 1 session")
		}
	}

	if r2 := <-store.Session().AnalyticsSessionCount(s1.TeamId); r2.Err != nil {
		t.Fatal(r2.Err)
	} else {
		if r2.Data.(int64) != 1 {
			t.Fatal("should have 1 session")
		}
	}
}
<|endoftext|>


<commit_before>package acceptance_test

import (
	"crypto/tls"
	"fmt"
	"lib/models"
	"lib/policy_client"
	"math/rand"
	"net/http"
	"strings"

	"code.cloudfoundry.org/lager/lagertest"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/pivotal-cf-experimental/warrant"
)

var _ = Describe("space developer policy configuration", func() {
	var (
		appA       string
		appB       string
		orgName    string
		spaceNameA string
		spaceNameB string
		prefix     string
		w          warrant.Warrant

		policyClient *policy_client.ExternalClient
	)

	BeforeEach(func() {
		policyClient = policy_client.NewExternal(lagertest.NewTestLogger("test"),
			&http.Client{
				Transport: &http.Transport{
					TLSClientConfig: &tls.Config{
						InsecureSkipVerify: true,
					},
				},
			},
			fmt.Sprintf("https://%s", config.ApiEndpoint),
		)

		prefix = testConfig.Prefix
		appA = fmt.Sprintf("appA-%d", rand.Int31())
		appB = fmt.Sprintf("appB-%d", rand.Int31())

		AuthAsAdmin()

		orgName = prefix + "org"
		Expect(cf.Cf("create-org", orgName).Wait(Timeout_Push)).To(gexec.Exit(0))
		Expect(cf.Cf("target", "-o", orgName).Wait(Timeout_Push)).To(gexec.Exit(0))

		spaceNameA = prefix + "space-A"
		Expect(cf.Cf("create-space", spaceNameA).Wait(Timeout_Push)).To(gexec.Exit(0))
		Expect(cf.Cf("target", "-o", orgName, "-s", spaceNameA).Wait(Timeout_Push)).To(gexec.Exit(0))

		pushProxy(appA)

		spaceNameB = prefix + "space-B"
		Expect(cf.Cf("create-space", spaceNameB).Wait(Timeout_Push)).To(gexec.Exit(0))
		Expect(cf.Cf("target", "-o", orgName, "-s", spaceNameB).Wait(Timeout_Push)).To(gexec.Exit(0))

		pushProxy(appB)
		w = warrant.New(warrant.Config{
			Host:          fmt.Sprintf("https://uaa.%s", config.AppsDomain),
			SkipVerifySSL: true,
		})

		uaaAdminClientToken, err := w.Clients.GetToken("admin", testConfig.AdminSecret)
		Expect(err).NotTo(HaveOccurred())

		user := ensureUserExists(w, "space-developer", "password", uaaAdminClientToken)
		group := ensureGroupExists(w, "network.write", uaaAdminClientToken)

		err = w.Groups.AddMember(group.ID, user.ID, uaaAdminClientToken)
		Expect(err).To(Or(BeNil(), BeAssignableToTypeOf(warrant.DuplicateResourceError{})))
	})

	AfterEach(func() {
		By("logging in as admin and deleting the org", func() {
			Expect(cf.Cf("auth", config.AdminUser, config.AdminPassword).Wait(Timeout_Push)).To(gexec.Exit(0))
			Expect(cf.Cf("delete-org", orgName, "-f").Wait(Timeout_Push)).To(gexec.Exit(0))
		})
	})

	Describe("space developer with network.write scope", func() {
		It("can create, list, and delete network policies in spaces they have access to", func(done Done) {
			By("setting space roles", func() {
				Expect(cf.Cf("set-space-role", "space-developer", orgName, spaceNameA, "SpaceDeveloper").Wait(Timeout_Push)).To(gexec.Exit(0))
				Expect(cf.Cf("set-space-role", "space-developer", orgName, spaceNameB, "SpaceDeveloper").Wait(Timeout_Push)).To(gexec.Exit(0))
			})

			var spaceDevUserToken string
			By("logging in and getting the space developer user token", func() {
				Expect(cf.Cf("auth", "space-developer", "password").Wait(Timeout_Push)).To(gexec.Exit(0))
				session := cf.Cf("oauth-token")
				Expect(session.Wait(Timeout_Push)).To(gexec.Exit(0))
				spaceDevUserToken = strings.TrimSpace(string(session.Out.Contents()))
			})

			var appAGUID, appBGUID string
			By("getting the app guids", func() {
				Expect(cf.Cf("target", "-o", orgName, "-s", spaceNameA).Wait(Timeout_Push)).To(gexec.Exit(0))
				session := cf.Cf("app", appA, "--guid")
				Expect(session.Wait(Timeout_Push)).To(gexec.Exit(0))
				appAGUID = strings.TrimSpace(string(session.Out.Contents()))

				Expect(cf.Cf("target", "-o", orgName, "-s", spaceNameB).Wait(Timeout_Push)).To(gexec.Exit(0))
				session = cf.Cf("app", appB, "--guid")
				Expect(session.Wait(Timeout_Push)).To(gexec.Exit(0))
				appBGUID = strings.TrimSpace(string(session.Out.Contents()))
			})

			By("creating a policy", func() {
				err := policyClient.AddPolicies(spaceDevUserToken, []models.Policy{
					models.Policy{
						Source: models.Source{
							ID: appAGUID,
						},
						Destination: models.Destination{
							ID:       appBGUID,
							Port:     1234,
							Protocol: "tcp",
						},
					},
				})
				Expect(err).NotTo(HaveOccurred())
			})

			By("listing policies", func() {
				expectedPolicies := []models.Policy{
					models.Policy{
						Source: models.Source{
							ID: appAGUID,
						},
						Destination: models.Destination{
							ID:       appBGUID,
							Port:     1234,
							Protocol: "tcp",
						},
					},
				}
				policies, err := policyClient.GetPolicies(spaceDevUserToken)
				Expect(err).NotTo(HaveOccurred())
				Expect(policies).To(Equal(expectedPolicies))
			})

			By("deleting the policy", func() {
				err := policyClient.DeletePolicies(spaceDevUserToken, []models.Policy{
					models.Policy{
						Source: models.Source{
							ID: appAGUID,
						},
						Destination: models.Destination{
							ID:       appBGUID,
							Port:     1234,
							Protocol: "tcp",
						},
					},
				})
				Expect(err).NotTo(HaveOccurred())
			})

			close(done)
		}, 60 /* <-- overall spec timeout in seconds */)
	})
})

func ensureGroupExists(client warrant.Warrant, name, token string) warrant.Group {
	_, err := client.Groups.Create(name, token)
	Expect(err).To(Or(BeNil(), BeAssignableToTypeOf(warrant.DuplicateResourceError{})))

	groups, err := client.Groups.List(warrant.Query{Filter: fmt.Sprintf(`displayName eq %q`, name)}, token)
	Expect(err).NotTo(HaveOccurred())

	return groups[0]
}

func ensureUserExists(warrantClient warrant.Warrant, username, password, token string) warrant.User {
	createUserSession := cf.Cf("create-user", username, password)
	Expect(createUserSession.Wait(Timeout_Push)).To(gexec.Exit(0))

	users, err := warrantClient.Users.List(warrant.Query{Filter: fmt.Sprintf(`userName eq %q`, username)}, token)
	Expect(err).NotTo(HaveOccurred())

	return users[0]
}
<commit_msg>Fix space developer acceptance test to have unique org<commit_after>package acceptance_test

import (
	"crypto/tls"
	"fmt"
	"lib/models"
	"lib/policy_client"
	"math/rand"
	"net/http"
	"strings"

	"code.cloudfoundry.org/lager/lagertest"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/pivotal-cf-experimental/warrant"
)

var _ = Describe("space developer policy configuration", func() {
	var (
		appA       string
		appB       string
		orgName    string
		spaceNameA string
		spaceNameB string
		prefix     string
		w          warrant.Warrant

		policyClient *policy_client.ExternalClient
	)

	BeforeEach(func() {
		policyClient = policy_client.NewExternal(lagertest.NewTestLogger("test"),
			&http.Client{
				Transport: &http.Transport{
					TLSClientConfig: &tls.Config{
						InsecureSkipVerify: true,
					},
				},
			},
			fmt.Sprintf("https://%s", config.ApiEndpoint),
		)

		prefix = testConfig.Prefix
		appA = fmt.Sprintf("appA-%d", rand.Int31())
		appB = fmt.Sprintf("appB-%d", rand.Int31())

		AuthAsAdmin()

		orgName = prefix + "space-developer-org"
		Expect(cf.Cf("create-org", orgName).Wait(Timeout_Push)).To(gexec.Exit(0))
		Expect(cf.Cf("target", "-o", orgName).Wait(Timeout_Push)).To(gexec.Exit(0))

		spaceNameA = prefix + "space-A"
		Expect(cf.Cf("create-space", spaceNameA).Wait(Timeout_Push)).To(gexec.Exit(0))
		Expect(cf.Cf("target", "-o", orgName, "-s", spaceNameA).Wait(Timeout_Push)).To(gexec.Exit(0))

		pushProxy(appA)

		spaceNameB = prefix + "space-B"
		Expect(cf.Cf("create-space", spaceNameB).Wait(Timeout_Push)).To(gexec.Exit(0))
		Expect(cf.Cf("target", "-o", orgName, "-s", spaceNameB).Wait(Timeout_Push)).To(gexec.Exit(0))

		pushProxy(appB)
		w = warrant.New(warrant.Config{
			Host:          fmt.Sprintf("https://uaa.%s", config.AppsDomain),
			SkipVerifySSL: true,
		})

		uaaAdminClientToken, err := w.Clients.GetToken("admin", testConfig.AdminSecret)
		Expect(err).NotTo(HaveOccurred())

		user := ensureUserExists(w, "space-developer", "password", uaaAdminClientToken)
		group := ensureGroupExists(w, "network.write", uaaAdminClientToken)

		err = w.Groups.AddMember(group.ID, user.ID, uaaAdminClientToken)
		Expect(err).To(Or(BeNil(), BeAssignableToTypeOf(warrant.DuplicateResourceError{})))
	})

	AfterEach(func() {
		By("logging in as admin and deleting the org", func() {
			Expect(cf.Cf("auth", config.AdminUser, config.AdminPassword).Wait(Timeout_Push)).To(gexec.Exit(0))
			Expect(cf.Cf("delete-org", orgName, "-f").Wait(Timeout_Push)).To(gexec.Exit(0))
		})
	})

	Describe("space developer with network.write scope", func() {
		It("can create, list, and delete network policies in spaces they have access to", func(done Done) {
			By("setting space roles", func() {
				Expect(cf.Cf("set-space-role", "space-developer", orgName, spaceNameA, "SpaceDeveloper").Wait(Timeout_Push)).To(gexec.Exit(0))
				Expect(cf.Cf("set-space-role", "space-developer", orgName, spaceNameB, "SpaceDeveloper").Wait(Timeout_Push)).To(gexec.Exit(0))
			})

			var spaceDevUserToken string
			By("logging in and getting the space developer user token", func() {
				Expect(cf.Cf("auth", "space-developer", "password").Wait(Timeout_Push)).To(gexec.Exit(0))
				session := cf.Cf("oauth-token")
				Expect(session.Wait(Timeout_Push)).To(gexec.Exit(0))
				spaceDevUserToken = strings.TrimSpace(string(session.Out.Contents()))
			})

			var appAGUID, appBGUID string
			By("getting the app guids", func() {
				Expect(cf.Cf("target", "-o", orgName, "-s", spaceNameA).Wait(Timeout_Push)).To(gexec.Exit(0))
				session := cf.Cf("app", appA, "--guid")
				Expect(session.Wait(Timeout_Push)).To(gexec.Exit(0))
				appAGUID = strings.TrimSpace(string(session.Out.Contents()))

				Expect(cf.Cf("target", "-o", orgName, "-s", spaceNameB).Wait(Timeout_Push)).To(gexec.Exit(0))
				session = cf.Cf("app", appB, "--guid")
				Expect(session.Wait(Timeout_Push)).To(gexec.Exit(0))
				appBGUID = strings.TrimSpace(string(session.Out.Contents()))
			})

			By("creating a policy", func() {
				err := policyClient.AddPolicies(spaceDevUserToken, []models.Policy{
					models.Policy{
						Source: models.Source{
							ID: appAGUID,
						},
						Destination: models.Destination{
							ID:       appBGUID,
							Port:     1234,
							Protocol: "tcp",
						},
					},
				})
				Expect(err).NotTo(HaveOccurred())
			})

			By("listing policies", func() {
				expectedPolicies := []models.Policy{
					models.Policy{
						Source: models.Source{
							ID: appAGUID,
						},
						Destination: models.Destination{
							ID:       appBGUID,
							Port:     1234,
							Protocol: "tcp",
						},
					},
				}
				policies, err := policyClient.GetPolicies(spaceDevUserToken)
				Expect(err).NotTo(HaveOccurred())
				Expect(policies).To(Equal(expectedPolicies))
			})

			By("deleting the policy", func() {
				err := policyClient.DeletePolicies(spaceDevUserToken, []models.Policy{
					models.Policy{
						Source: models.Source{
							ID: appAGUID,
						},
						Destination: models.Destination{
							ID:       appBGUID,
							Port:     1234,
							Protocol: "tcp",
						},
					},
				})
				Expect(err).NotTo(HaveOccurred())
			})

			close(done)
		}, 60 /* <-- overall spec timeout in seconds */)
	})
})

func ensureGroupExists(client warrant.Warrant, name, token string) warrant.Group {
	_, err := client.Groups.Create(name, token)
	Expect(err).To(Or(BeNil(), BeAssignableToTypeOf(warrant.DuplicateResourceError{})))

	groups, err := client.Groups.List(warrant.Query{Filter: fmt.Sprintf(`displayName eq %q`, name)}, token)
	Expect(err).NotTo(HaveOccurred())

	return groups[0]
}

func ensureUserExists(warrantClient warrant.Warrant, username, password, token string) warrant.User {
	createUserSession := cf.Cf("create-user", username, password)
	Expect(createUserSession.Wait(Timeout_Push)).To(gexec.Exit(0))

	users, err := warrantClient.Users.List(warrant.Query{Filter: fmt.Sprintf(`userName eq %q`, username)}, token)
	Expect(err).NotTo(HaveOccurred())

	return users[0]
}
<|endoftext|>


<commit_before>// API version number check
package main

import (
	"fmt"

	"github.com/bmizerany/assert"
	"github.com/xyproto/algernon/engine"
	"github.com/xyproto/permissionbolt"
	"github.com/xyproto/permissions2"
	//"github.com/xyproto/permissionsql"
	"github.com/xyproto/pinterface"
	//"github.com/xyproto/pstore"
	"github.com/xyproto/simplebolt"
	//"github.com/xyproto/simplehstore"
	//"github.com/xyproto/simplemaria"
	"testing"

	"github.com/xyproto/simpleredis"
)

// VersionInfo helps to keep track of package names and versions
type VersionInfo struct {
	name    string
	current float64
	target  float64
}

// New takes the name of the go package, the current and the desired version
func New(name string, current, target float64) *VersionInfo {
	return &VersionInfo{name, current, target}
}

// Check compares the current and target version
func (v *VersionInfo) Check() error {
	if v.current != v.target {
		return fmt.Errorf("is %.1f, needs version %.1f", v.current, v.target)
	}
	return nil
}

func TestAPI(t *testing.T) {
	assert.Equal(t, New("simplebolt", simplebolt.Version, 4.0).Check(), nil)
	assert.Equal(t, New("permissionbolt", permissionbolt.Version, 2.5).Check(), nil)
	assert.Equal(t, New("simpleredis", simpleredis.Version, 2.6).Check(), nil)
	assert.Equal(t, New("permissions2", permissions.Version, 2.6).Check(), nil)
	assert.Equal(t, New("pinterface", pinterface.Version, 5.0).Check(), nil)
	assert.Equal(t, New("engine", engine.Version, 2.0).Check(), nil)

	// These adds many dependencies when testing
	//assert.Equal(t, New("simplemaria", simplemaria.Version, 3.0).Check(), nil)
	//assert.Equal(t, New("permissionsql", permissionsql.Version, 2.0).Check(), nil)
	//assert.Equal(t, New("simplehstore", simplehstore.Version, 2.3).Check(), nil)
	//assert.Equal(t, New("pstore", pstore.Version, 3.0).Check(), nil)
}
<commit_msg>Update tests<commit_after>// API version number check
package main

import (
	"fmt"

	"github.com/bmizerany/assert"
	"github.com/xyproto/algernon/engine"
	"github.com/xyproto/permissionbolt"
	"github.com/xyproto/permissions2"
	//"github.com/xyproto/permissionsql"
	"github.com/xyproto/pinterface"
	//"github.com/xyproto/pstore"
	"github.com/xyproto/simplebolt"
	//"github.com/xyproto/simplehstore"
	//"github.com/xyproto/simplemaria"
	"testing"

	"github.com/xyproto/simpleredis"
)

// VersionInfo helps to keep track of package names and versions
type VersionInfo struct {
	name    string
	current float64
	target  float64
}

// New takes the name of the go package, the current and the desired version
func New(name string, current, target float64) *VersionInfo {
	return &VersionInfo{name, current, target}
}

// Check compares the current and target version
func (v *VersionInfo) Check() error {
	if v.current != v.target {
		return fmt.Errorf("is %.1f, needs version %.1f", v.current, v.target)
	}
	return nil
}

func TestAPI(t *testing.T) {
	assert.Equal(t, New("simplebolt", simplebolt.Version, 5.1).Check(), nil)
	assert.Equal(t, New("permissionbolt", permissionbolt.Version, 2.6).Check(), nil)
	assert.Equal(t, New("simpleredis", simpleredis.Version, 2.6).Check(), nil)
	assert.Equal(t, New("permissions2", permissions.Version, 2.6).Check(), nil)
	assert.Equal(t, New("pinterface", pinterface.Version, 5.0).Check(), nil)
	assert.Equal(t, New("engine", engine.Version, 2.0).Check(), nil)

	// These adds many dependencies when testing
	//assert.Equal(t, New("simplemaria", simplemaria.Version, 3.0).Check(), nil)
	//assert.Equal(t, New("permissionsql", permissionsql.Version, 2.0).Check(), nil)
	//assert.Equal(t, New("simplehstore", simplehstore.Version, 2.3).Check(), nil)
	//assert.Equal(t, New("pstore", pstore.Version, 3.0).Check(), nil)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
    "bytes"
	"testing"
    "time"
	"net/http"
    "encoding/json"
	"net/http/httptest"
)

func get(ts *httptest.Server, path string) (string, int, error) {
	res, err := http.Get(ts.URL + path)
	if err != nil {
        return "", 0, err
	}
	data, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
        return "", 0, err
	}
    return string(data), res.StatusCode, nil
}

func post(ts *httptest.Server, path string, jsonStr []byte) (string, int, error) {
    req, err := http.NewRequest("POST", ts.URL + path, bytes.NewBuffer(jsonStr))
    client := &http.Client{}
    res, err := client.Do(req)
    if err != nil {
        return "", 0, err
    }
	data, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
        return "", 0, err
	}
    return string(data), res.StatusCode, nil
}

func TestApiServeHTTP_get(t *testing.T) {
    frontend := &frontend{
        Addr:   "127.0.0.1",
        Path:   "/gxproxy",
        APIKey: "supersecret",
    }
	var tsh = &apiHandler{
		Transport: &http.Transport{
			DisableKeepAlives:  false,
			DisableCompression: false,
		},
		RouteMapping: &RouteMapping{
			AuthCookieName: "sid",
			Routes:         make([]Route, 0),
			Storage:        "/dev/null",
		},
		Frontend: frontend,
	}
	ts := httptest.NewServer(tsh)
    defer ts.Close()

    type testcase struct {
        Path string
        ExpectedCode int
        ExpectedMsg string
        ExpectedErr error
    }

    tests := []testcase{
        {"/api", 401, "Invalid API key\n", nil},
        {"/api?api_key=", 401, "Invalid API key\n", nil},
        {"/api?api_key=supersecret", 200, "[]", nil},
    }

    for _, tc := range tests {
        data, code, err := get(ts, tc.Path)
        if err != tc.ExpectedErr {
            t.Error("Request to", tc.Path, "had error", err, "expected error", tc.ExpectedErr)
        }

        if code != tc.ExpectedCode {
            t.Error("Request to", tc.Path, "had code", code, "expected code", tc.ExpectedCode)
        }

        if data != tc.ExpectedMsg {
            t.Error("Request to", tc.Path, "had body", data, "expected body", tc.ExpectedMsg)
        }
    }

    now := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
    route := &Route{
        FrontendPath: "/some/path",
        BackendAddr: "1.1.1.1",
        AuthorizedCookie: "gxsesh",
        LastSeen: now,
        ContainerIds: []string{"deadbeef", "cafebabe" },
    }
    routes := []Route{*route}
    tc_data_route, err := json.MarshalIndent(route, "", "    ")
    if err != nil {
        t.Error("Could not serialize test case route", err)
    }
    tc_data_routes, err := json.MarshalIndent(routes, "", "    ")
    if err != nil {
        t.Error("Could not serialize test case route", err)
    }

    type testcase2 struct {
        Path string
        Body []byte
        ExpectedCode int
        ExpectedMsg string
        ExpectedErr error
    }

    tests2 := []testcase2{
        {"/api?api_key=supersecret", nil, 400, "Invalid Route Data\n", nil},
        {"/api?api_key=supersecret", []byte("asdf"), 400, "Invalid Route Data\n", nil},
        {"/api?api_key=supersecret", []byte("{\"FrontendPath\": \"\"}"), 400, "Invalid Route Data\n", nil},
    }

    for _, tc := range tests2 {
        data, code, err := post(ts, tc.Path, tc.Body)
        if err != tc.ExpectedErr {
            t.Error("Request to", tc.Path, "had error", err, "expected error", tc.ExpectedErr)
        }

        if code != tc.ExpectedCode {
            t.Error("Request to", tc.Path, "had code", code, "expected code", tc.ExpectedCode)
        }

        if data != tc.ExpectedMsg {
            t.Error("Request to", tc.Path, "had body", data, "expected body", tc.ExpectedMsg)
        }
    }

    tests3 := []testcase2{
        {"/api?api_key=supersecret", tc_data_route, 200, string(tc_data_routes), nil},
    }
    for _, tc := range tests3 {
        _, code, err := post(ts, tc.Path, tc.Body)
        if len(tsh.RouteMapping.Routes) > 0 {
            for idx := range tsh.RouteMapping.Routes {
                tsh.RouteMapping.Routes[idx].LastSeen = now
            }
        }
        data, code, err := get(ts, tc.Path)
        if err != tc.ExpectedErr {
            t.Error("Request to", tc.Path, "had error", err, "expected error", tc.ExpectedErr)
        }

        if code != tc.ExpectedCode {
            t.Error("Request to", tc.Path, "had code", code, "expected code", tc.ExpectedCode)
        }

        if data != tc.ExpectedMsg {
            t.Error("Request to", tc.Path, "had body", data, "expected body", tc.ExpectedMsg)
        }
    }
}
<commit_msg>Reduce copy pasta, complexity<commit_after>package main

import (
	"io/ioutil"
    "bytes"
	"testing"
    "time"
	"net/http"
    "encoding/json"
	"net/http/httptest"
)

func get(ts *httptest.Server, path string) (string, int, error) {
	res, err := http.Get(ts.URL + path)
	if err != nil {
        return "", 0, err
	}
	data, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
        return "", 0, err
	}
    return string(data), res.StatusCode, nil
}
type testcase struct {
    Path string
    Body []byte
    ExpectedCode int
    ExpectedMsg string
    ExpectedErr error
}

func post(ts *httptest.Server, path string, jsonStr []byte) (string, int, error) {
    req, err := http.NewRequest("POST", ts.URL + path, bytes.NewBuffer(jsonStr))
    client := &http.Client{}
    res, err := client.Do(req)
    if err != nil {
        return "", 0, err
    }
	data, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
        return "", 0, err
	}
    return string(data), res.StatusCode, nil
}

func apiTest(data string, code int, err error, tc testcase, t *testing.T) {
    if err != tc.ExpectedErr {
        t.Error("Request to", tc.Path, "had error", err, "expected error", tc.ExpectedErr)
    }

    if code != tc.ExpectedCode {
        t.Error("Request to", tc.Path, "had code", code, "expected code", tc.ExpectedCode)
    }

    if data != tc.ExpectedMsg {
        t.Error("Request to", tc.Path, "had body", data, "expected body", tc.ExpectedMsg)
    }
}

func TestApiServeHTTP_get(t *testing.T) {
    frontend := &frontend{
        Addr:   "127.0.0.1",
        Path:   "/gxproxy",
        APIKey: "supersecret",
    }
	var tsh = &apiHandler{
		Transport: &http.Transport{
			DisableKeepAlives:  false,
			DisableCompression: false,
		},
		RouteMapping: &RouteMapping{
			AuthCookieName: "sid",
			Routes:         make([]Route, 0),
			Storage:        "/dev/null",
		},
		Frontend: frontend,
	}
	ts := httptest.NewServer(tsh)
    defer ts.Close()

    tests := []testcase{
        {"/api", nil, 401, "Invalid API key\n", nil},
        {"/api?api_key=", nil, 401, "Invalid API key\n", nil},
        {"/api?api_key=supersecret", nil, 200, "[]", nil},
    }

    for _, tc := range tests {
        data, code, err := get(ts, tc.Path)

        apiTest(data, code, err, tc, t)
    }

    now := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
    route := &Route{
        FrontendPath: "/some/path",
        BackendAddr: "1.1.1.1",
        AuthorizedCookie: "gxsesh",
        LastSeen: now,
        ContainerIds: []string{"deadbeef", "cafebabe" },
    }
    routes := []Route{*route}
    tcDataRoute, err := json.MarshalIndent(route, "", "    ")
    if err != nil {
        t.Error("Could not serialize test case route", err)
    }
    tcDataRoutes, err := json.MarshalIndent(routes, "", "    ")
    if err != nil {
        t.Error("Could not serialize test case route", err)
    }

    tests2 := []testcase{
        {"/api?api_key=supersecret", nil, 400, "Invalid Route Data\n", nil},
        {"/api?api_key=supersecret", []byte("asdf"), 400, "Invalid Route Data\n", nil},
        {"/api?api_key=supersecret", []byte("{\"FrontendPath\": \"\"}"), 400, "Invalid Route Data\n", nil},
    }

    for _, tc := range tests2 {
        data, code, err := post(ts, tc.Path, tc.Body)
        apiTest(data, code, err, tc, t)
    }

    tests3 := []testcase{
        {"/api?api_key=supersecret", tcDataRoute, 200, string(tcDataRoutes), nil},
    }
    for _, tc := range tests3 {
        _, code, err := post(ts, tc.Path, tc.Body)
        if len(tsh.RouteMapping.Routes) > 0 {
            for idx := range tsh.RouteMapping.Routes {
                tsh.RouteMapping.Routes[idx].LastSeen = now
            }
        }
        data, code, err := get(ts, tc.Path)
        apiTest(data, code, err, tc, t)
    }
}
<|endoftext|>


<commit_before>package regionagogo

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"

	"gopkg.in/vmihailenco/msgpack.v2"

	"github.com/Workiva/go-datastructures/augmentedtree"
	"github.com/golang/geo/s2"
	"github.com/kpawlik/geojson"
)

// GeoSearch provides in memory storage and query engine for regions lookup
type GeoSearch struct {
	augmentedtree.Tree
	rm    map[int]Region
	Debug bool
}

// Region is region for memory use
type Region struct {
	Code string   `json:"code"`
	Name string   `json:"name"`
	L    *s2.Loop `json:"-"`
}

// GeoData is used to pack the data in a msgpack file
type GeoData struct {
	RS []RegionStorage     `msgpack:"rs"`
	CL []CellIDLoopStorage `msgpack:"cl"`
}

// CellIDLoopStorage is a cell with associated loops used for storage
type CellIDLoopStorage struct {
	C     s2.CellID `msgpack:"c"`
	Loops []int     `msgpack:"l"`
}

// RegionStorage is a region representation for storage use
type RegionStorage struct {
	Name         string   `msgpack:"n"`
	Code         string   `msgpack:"i"`
	Points       []CPoint `msgpack:"p"`
	s2.CellUnion `msgpack:"c"`
}

// CPoint is a []float64 used as coordinates
type CPoint struct {
	Coordinate []float64 `msgpack:"c"`
}

// NewGeoSearch
func NewGeoSearch() *GeoSearch {
	gs := &GeoSearch{
		Tree: augmentedtree.New(1),
		rm:   make(map[int]Region),
	}

	return gs
}

// ImportGeoData loads geodata file into a map loopID->Region
// fills the segment tree for fast lookup
func (gs *GeoSearch) ImportGeoData(b []byte) error {
	var gd GeoData

	err := msgpack.Unmarshal(b, &gd)
	if err != nil {
		return err
	}

	for loopID, r := range gd.RS {
		var points []s2.Point
		for _, c := range r.Points {
			ll := s2.LatLngFromDegrees(c.Coordinate[0], c.Coordinate[1])
			point := s2.PointFromLatLng(ll)
			points = append(points, point)
		}
		// add 1st point as last point to close the shape
		points = append(points, points[0])

		// load the loops into memory
		l := s2.LoopFromPoints(points)
		gs.rm[loopID] = Region{Code: r.Code, Name: r.Name, L: l}
	}

	// load the cell ranges into the tree
	for _, cLoop := range gd.CL {
		gs.Add(&S2Interval{CellID: cLoop.C, LoopIDs: cLoop.Loops})
	}

	log.Println("loaded", len(gs.rm), "regions")

	return nil
}

// Query returns the country for the corresponding lat, lng point
func (gs *GeoSearch) Query(lat, lng float64) *Region {
	q := s2.CellIDFromLatLng(s2.LatLngFromDegrees(lat, lng))
	i := &S2Interval{CellID: q}
	r := gs.Tree.Query(i)
	for _, itv := range r {
		sitv := itv.(*S2Interval)
		if gs.Debug {
			fmt.Println("found", sitv, sitv.LoopIDs)
		}

		for _, loopID := range sitv.LoopIDs {
			if gs.rm[loopID].L.ContainsPoint(q.Point()) {
				region := gs.rm[loopID]
				return &region
			}
		}
	}

	return nil
}

// importGeoJSONFile will load a geo json and save the polygons into
// a msgpack file named geodata
func ImportGeoJSONFile(filename string, debug bool) error {
	var loopID int

	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	var geo geojson.FeatureCollection

	err = json.Unmarshal(b, &geo)
	if err != nil {
		return err
	}

	var geoData GeoData

	cl := make(map[s2.CellID][]int)

	for _, f := range geo.Features {
		geom, err := f.GetGeometry()
		if err != nil {
			return err
		}

		switch geom.GetType() {
		case "MultiPolygon":
			mp := geom.(*geojson.MultiPolygon)
			// multipolygon
			for _, m := range mp.Coordinates {
				// polygon
				var points []s2.Point
				var cpoints []CPoint

				for _, p := range m {
					// coordinates

					// reverse the slice
					for i := len(p)/2 - 1; i >= 0; i-- {
						opp := len(p) - 1 - i
						p[i], p[opp] = p[opp], p[i]
					}

					for i, c := range p {
						ll := s2.LatLngFromDegrees(float64(c[1]), float64(c[0]))
						point := s2.PointFromLatLng(ll)
						points = append(points, point)
						// do not add cpoint on storage (first point is last point)
						if i == len(p)-1 {
							break
						}
						cpoints = append(cpoints, CPoint{Coordinate: []float64{float64(c[1]), float64(c[0])}})
					}
				}
				l := s2.LoopFromPoints(points)

				if l.IsEmpty() || l.IsFull() {
					log.Println("invalid loop")
					continue
				}

				rb := l.RectBound()
				rc := &s2.RegionCoverer{MinLevel: 1, MaxLevel: 30, MaxCells: 8}
				covering := rc.Covering(rb)

				if _, ok := f.Properties["iso_a2"].(string); !ok {
					log.Fatal("can't find country code", f.Properties)
				}
				code := f.Properties["iso_a2"].(string)

				region := ""
				if _, ok := f.Properties["name"].(string); !ok {
					if _, ok := f.Properties["region"].(string); ok {
						region = f.Properties["region"].(string)
					}

				} else {
					region = f.Properties["name"].(string)
				}

				if debug {
					fmt.Println("import", loopID, code, f.Properties["name"])
				}

				r := RegionStorage{
					Name:      region,
					Code:      code,
					Points:    cpoints,
					CellUnion: covering,
				}

				geoData.RS = append(geoData.RS, r)

				for _, cell := range covering {
					cl[cell] = append(cl[cell], loopID)
				}

				loopID = loopID + 1
			}
		default:
			return errors.New("unknown type")
		}

	}

	for k, v := range cl {
		geoData.CL = append(geoData.CL, CellIDLoopStorage{C: k, Loops: v})
	}

	log.Println("imported", filename, len(geoData.RS), "regions")

	b, err = msgpack.Marshal(geoData)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile("geodata", b, 0644)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>only grab 1st polyogon in multi it's the exterior others are interior<commit_after>package regionagogo

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"

	"gopkg.in/vmihailenco/msgpack.v2"

	"github.com/Workiva/go-datastructures/augmentedtree"
	"github.com/golang/geo/s2"
	"github.com/kpawlik/geojson"
)

// GeoSearch provides in memory storage and query engine for regions lookup
type GeoSearch struct {
	augmentedtree.Tree
	rm    map[int]Region
	Debug bool
}

// Region is region for memory use
type Region struct {
	Code string   `json:"code"`
	Name string   `json:"name"`
	L    *s2.Loop `json:"-"`
}

// GeoData is used to pack the data in a msgpack file
type GeoData struct {
	RS []RegionStorage     `msgpack:"rs"`
	CL []CellIDLoopStorage `msgpack:"cl"`
}

// CellIDLoopStorage is a cell with associated loops used for storage
type CellIDLoopStorage struct {
	C     s2.CellID `msgpack:"c"`
	Loops []int     `msgpack:"l"`
}

// RegionStorage is a region representation for storage use
type RegionStorage struct {
	Name         string   `msgpack:"n"`
	Code         string   `msgpack:"i"`
	Points       []CPoint `msgpack:"p"`
	s2.CellUnion `msgpack:"c"`
}

// CPoint is a []float64 used as coordinates
type CPoint struct {
	Coordinate []float64 `msgpack:"c"`
}

// NewGeoSearch
func NewGeoSearch() *GeoSearch {
	gs := &GeoSearch{
		Tree: augmentedtree.New(1),
		rm:   make(map[int]Region),
	}

	return gs
}

// ImportGeoData loads geodata file into a map loopID->Region
// fills the segment tree for fast lookup
func (gs *GeoSearch) ImportGeoData(b []byte) error {
	var gd GeoData

	err := msgpack.Unmarshal(b, &gd)
	if err != nil {
		return err
	}

	for loopID, r := range gd.RS {
		var points []s2.Point
		for _, c := range r.Points {
			ll := s2.LatLngFromDegrees(c.Coordinate[0], c.Coordinate[1])
			point := s2.PointFromLatLng(ll)
			points = append(points, point)
		}
		// add 1st point as last point to close the shape
		points = append(points, points[0])

		// load the loops into memory
		l := s2.LoopFromPoints(points)
		gs.rm[loopID] = Region{Code: r.Code, Name: r.Name, L: l}
	}

	// load the cell ranges into the tree
	for _, cLoop := range gd.CL {
		gs.Add(&S2Interval{CellID: cLoop.C, LoopIDs: cLoop.Loops})
	}

	log.Println("loaded", len(gs.rm), "regions")

	return nil
}

// Query returns the country for the corresponding lat, lng point
func (gs *GeoSearch) Query(lat, lng float64) *Region {
	q := s2.CellIDFromLatLng(s2.LatLngFromDegrees(lat, lng))
	i := &S2Interval{CellID: q}
	r := gs.Tree.Query(i)
	for _, itv := range r {
		sitv := itv.(*S2Interval)
		if gs.Debug {
			fmt.Println("found", sitv, sitv.LoopIDs)
		}

		for _, loopID := range sitv.LoopIDs {
			if gs.rm[loopID].L.ContainsPoint(q.Point()) {
				region := gs.rm[loopID]
				return &region
			}
		}
	}

	return nil
}

// importGeoJSONFile will load a geo json and save the polygons into
// a msgpack file named geodata
func ImportGeoJSONFile(filename string, debug bool) error {
	var loopID int

	b, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	var geo geojson.FeatureCollection

	err = json.Unmarshal(b, &geo)
	if err != nil {
		return err
	}

	var geoData GeoData

	cl := make(map[s2.CellID][]int)

	for _, f := range geo.Features {
		geom, err := f.GetGeometry()
		if err != nil {
			return err
		}

		switch geom.GetType() {
		case "MultiPolygon":
			mp := geom.(*geojson.MultiPolygon)
			// multipolygon
			for _, m := range mp.Coordinates {
				// polygon
				var points []s2.Point
				var cpoints []CPoint
				// For type "MultiPolygon", the "coordinates" member must be an array of Polygon coordinate arrays.
				// "Polygon", the "coordinates" member must be an array of LinearRing coordinate arrays.
				// For Polygons with multiple rings, the first must be the exterior ring and any others must be interior rings or holes.

				if len(m) < 1 {
					continue
				}

				p := m[0]
				// coordinates

				// reverse the slice
				for i := len(p)/2 - 1; i >= 0; i-- {
					opp := len(p) - 1 - i
					p[i], p[opp] = p[opp], p[i]
				}

				for i, c := range p {
					ll := s2.LatLngFromDegrees(float64(c[1]), float64(c[0]))
					point := s2.PointFromLatLng(ll)
					points = append(points, point)
					// do not add cpoint on storage (first point is last point)
					if i == len(p)-1 {
						break
					}
					cpoints = append(cpoints, CPoint{Coordinate: []float64{float64(c[1]), float64(c[0])}})
				}

				l := s2.LoopFromPoints(points)

				if l.IsEmpty() || l.IsFull() {
					log.Println("invalid loop")
					continue
				}

				rb := l.RectBound()
				rc := &s2.RegionCoverer{MinLevel: 1, MaxLevel: 30, MaxCells: 8}
				covering := rc.Covering(rb)

				if _, ok := f.Properties["iso_a2"].(string); !ok {
					log.Fatal("can't find country code", f.Properties)
				}
				code := f.Properties["iso_a2"].(string)

				region := ""
				if _, ok := f.Properties["name"].(string); !ok {
					if _, ok := f.Properties["region"].(string); ok {
						region = f.Properties["region"].(string)
					}

				} else {
					region = f.Properties["name"].(string)
				}

				if debug {
					fmt.Println("import", loopID, code, f.Properties["name"])
				}

				r := RegionStorage{
					Name:      region,
					Code:      code,
					Points:    cpoints,
					CellUnion: covering,
				}

				geoData.RS = append(geoData.RS, r)

				for _, cell := range covering {
					cl[cell] = append(cl[cell], loopID)
				}

				loopID = loopID + 1
			}
		default:
			return errors.New("unknown type")
		}

	}

	for k, v := range cl {
		geoData.CL = append(geoData.CL, CellIDLoopStorage{C: k, Loops: v})
	}

	log.Println("imported", filename, len(geoData.RS), "regions")

	b, err = msgpack.Marshal(geoData)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile("geodata", b, 0644)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package runstats

import "os"
import "fmt"
import "flag"
import "runtime"

import "github.com/bmhatfield/g2s"

var CPU *bool = flag.Bool("cpu", false, "Collect CPU Statistics")
var MEM *bool = flag.Bool("mem", false, "Collect Memory Statistics")
var GC *bool = flag.Bool("gc", false, "Collect GC Statistics")

var prefix string
var s g2s.Statter

var err error

func init() {
    s, err = g2s.Dial("udp", "localhost:8125")

    if err != nil {
        panic("Unable to connect to Statsd")
    }

    flag.Parse()

    prefix, err = os.Hostname()

    if err != nil {
        prefix = "unknown_host.go"
    } else {
        prefix = fmt.Sprintf("%s.go", prefix)
    }

    go collector()
}

func collector() {
    if *CPU {
        // Goroutines
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "cpu.goroutines"), string(runtime.NumGoroutine()))

        // CGo calls
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "cpu.cgo_calls"), string(runtime.NumCgoCall()))
    }

    if *MEM {
        m := new(runtime.MemStats)

        runtime.ReadMemStats(m)

        // s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem."), string(m.))

        // General
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.alloc"), string(m.Alloc))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.total"), string(m.TotalAlloc))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.sys"), string(m.Sys))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.lookups"), string(m.Lookups))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.malloc"), string(m.Mallocs))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.frees"), string(m.Frees))

        // Heap
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.alloc"), string(m.HeapAlloc))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.sys"), string(m.HeapSys))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.idle"), string(m.HeapIdle))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.inuse"), string(m.HeapInuse))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.released"), string(m.HeapReleased))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.objects"), string(m.HeapObjects))

        // Stack
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.inuse"), string(m.StackInuse))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.sys"), string(m.StackSys))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.mspan_inuse"), string(m.MSpanInuse))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.mspan_sys"), string(m.MSpanSys))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.mcache_inuse"), string(m.MCacheInuse))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.mcache_sys"), string(m.MCacheSys))

        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.othersys"), string(m.OtherSys))

        if *GC {
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.sys"), string(m.GCSys))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.next"), string(m.NextGC))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.last"), string(m.LastGC))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.pause_total"), string(m.PauseTotalNs))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.pause"), string(m.PauseNs[(m.NumGC + 255) % 256]))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.count"), string(m.NumGC))
        }
    }
}
<commit_msg>Add collection interval<commit_after>package runstats

import "os"
import "fmt"
import "flag"
import "time"
import "runtime"

import "github.com/bmhatfield/g2s"

var pause *int = flag.Int("pause", 10, "Collection pause interval")
var CPU *bool = flag.Bool("cpu", true, "Collect CPU Statistics")
var MEM *bool = flag.Bool("mem", true, "Collect Memory Statistics")
var GC *bool = flag.Bool("gc", true, "Collect GC Statistics (requires Memory be enabled)")

var prefix string
var s g2s.Statter

var err error

func init() {
    s, err = g2s.Dial("udp", "localhost:8125")

    if err != nil {
        panic("Unable to connect to Statsd")
    }

    flag.Parse()

    prefix, err = os.Hostname()

    if err != nil {
        prefix = "unknown_host.go"
    } else {
        prefix = fmt.Sprintf("%s.go", prefix)
    }

    go collector()
}

func collector() {
    if *CPU {
        // Goroutines
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "cpu.goroutines"), string(runtime.NumGoroutine()))

        // CGo calls
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "cpu.cgo_calls"), string(runtime.NumCgoCall()))
    }

    if *MEM {
        m := new(runtime.MemStats)
        runtime.ReadMemStats(m)

        // General
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.alloc"), string(m.Alloc))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.total"), string(m.TotalAlloc))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.sys"), string(m.Sys))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.lookups"), string(m.Lookups))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.malloc"), string(m.Mallocs))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.frees"), string(m.Frees))

        // Heap
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.alloc"), string(m.HeapAlloc))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.sys"), string(m.HeapSys))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.idle"), string(m.HeapIdle))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.inuse"), string(m.HeapInuse))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.released"), string(m.HeapReleased))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.heap.objects"), string(m.HeapObjects))

        // Stack
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.inuse"), string(m.StackInuse))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.sys"), string(m.StackSys))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.mspan_inuse"), string(m.MSpanInuse))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.mspan_sys"), string(m.MSpanSys))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.mcache_inuse"), string(m.MCacheInuse))
        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.stack.mcache_sys"), string(m.MCacheSys))

        s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.othersys"), string(m.OtherSys))

        if *GC {
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.sys"), string(m.GCSys))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.next"), string(m.NextGC))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.last"), string(m.LastGC))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.pause_total"), string(m.PauseTotalNs))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.pause"), string(m.PauseNs[(m.NumGC + 255) % 256]))
            s.Gauge(1.0, fmt.Sprintf("%s.%s", prefix, "mem.gc.count"), string(m.NumGC))
        }
    }

    // Don't collect for a time interval
    time.Sleep(*pause * time.Second)
}
<|endoftext|>


<commit_before>package stringer

func LevenshteinDistance(s string, t string) int {
  return levenshteinDistance(s, len(s), t, len(t))
}

func levenshteinDistance(s string, lenS int, t string, lenT int) int {
  if lenS == 0 {
    return lenT
  }
  if lenT == 0 {
    return lenS
  }

  var cost int

  if s[lenS-1] == t[lenT-1] {
    cost = 0
  } else {
    cost = 1
  }

  return min(levenshteinDistance(s, lenS - 1, t, lenT) + 1,
    levenshteinDistance(s, lenS, t, lenT - 1) + 1,
    levenshteinDistance(s, lenS - 1, t, lenT - 1) + cost)
}
<commit_msg>Use iterative with two matrix rows stategy instead of naive recursive strategy for the Levenshtein distance implementation.<commit_after>package stringer

func LevenshteinDistance(s string, t string) int {
  // Degenerate cases
  if s == t {
    return 0
  }
  if len(s) == 0 {
    return len(t)
  }
  if len(t) == 0 {
    return len(s)
  }

  // Create two work vectors of integer distances
  v0 := make([]int, len(t) + 1)
  v1 := make([]int, len(t) + 1)

  // Initialize v0 (previous row of distances)
  // this row is A[0][i] - edit distance
  // the distance is just the number of characters to delete from t
  for i := range v0 {
    v0[i] = i;
  }

  // Calculate v1 (current row distances) from the previous row v0
  for i := range s {
    // First element of v1 is A[i+1][0]
    // Edit distance is delete (i+1) chars from s to match empty t
    v1[0] = i + 1

    // Use formula to fill in the rest of the row
    for j := range t {
      var cost int
      if s[i] == t[j] {
        cost = 0
      } else {
        cost = 1
      }

      v1[j + 1] = min(v1[j] + 1, v0[j + 1] + 1, v0[j] + cost)
    }

    // Copy v1 (current row) to v0 (previous row) for next iteration
    for j := range v0 {
      v0[j] = v1[j]
    }
  }

  return v1[len(t)]
}
<|endoftext|>


<commit_before>package main

import (
	"app/counter"
	"math/rand"
	"sort"
	"strconv"
	"strings"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/search"
)

type DB struct {
	Context context.Context
}

func (db *DB) FetchUser(userId string) {
	//Step 1. Get Vine user's data from the Vine API
	vineApi := VineRequest{db.Context}
	vineUser, err := vineApi.GetUser(userId)

	if err != nil {
		if err.Error() == ErrUserDoesntExist {
			db.UnqueueUser(userId)
		} else {
			log.Errorf(db.Context, "got error getting user %s from vine: %v", userId, err)
		}
		return
	} else if vineUser == nil {
		log.Errorf(db.Context, "failed fetch on user %v. got err %v", userId, err)
		return
	} else if vineUser.Private == 1 {
		return
	}

	recordKey := datastore.NewKey(db.Context, "UserRecord", "", vineUser.UserId, nil)

	//Step 2. Add user to user search index.
	userIndex := &UserIndex{
		Username:    vineUser.Username,
		Location:    vineUser.Location,
		Description: vineUser.Description,
	}

	if len(vineUser.VanityUrls) != 0 {
		userIndex.VanityUrl = strings.ToLower(vineUser.VanityUrls[0])
	}

	index, err := search.Open("users")
	if err != nil {
		log.Errorf(db.Context, "error opening users search index: %v", err)
	} else {
		index.Put(db.Context, vineUser.UserIdStr, userIndex)
	}

	var newLoops, newPosts int64

	//Step 3. Write records (user {meta, record, data}).
	if userRecord, err := db.GetUserRecord(vineUser.UserId); err == nil {
		var userMeta []*UserMeta

		if vineUser.Username != userRecord.Username {
			userMeta = append(userMeta, &UserMeta{vineUser.UserId, "username", userRecord.Username, time.Now()})
		}

		if vineUser.Location != userRecord.Location {
			userMeta = append(userMeta, &UserMeta{vineUser.UserId, "location", userRecord.Location, time.Now()})
		}

		if vineUser.Description != userRecord.Description {
			userMeta = append(userMeta, &UserMeta{vineUser.UserId, "description", userRecord.Description, time.Now()})
		}

		if (vineUser.Verified != 0) != userRecord.Verified {
			userMeta = append(userMeta, &UserMeta{vineUser.UserId, "verified", strconv.FormatBool(userRecord.Verified), time.Now()})
		}

		newLoops = vineUser.LoopCount - userRecord.LoopCount
		newPosts = vineUser.AuthoredPostCount - userRecord.PostCount

		var metaKey *datastore.Key
		for _, m := range userMeta {
			metaKey = datastore.NewIncompleteKey(db.Context, "UserMeta", recordKey)
			if key, err := datastore.Put(db.Context, metaKey, m); err != nil {
				log.Errorf(db.Context, "got error storing user meta %s - %v: %v", userId, key, err)
			}
		}
	} else if err == datastore.ErrNoSuchEntity {

		counter.IncrementBy(db.Context, "TotalUsers", 1)
		counter.IncrementBy(db.Context, "24hUsers", 1)

		if vineUser.Verified == 1 {
			counter.IncrementBy(db.Context, "TotalVerified", 1)
		}
		if vineUser.ExplicitContent == 1 {
			counter.IncrementBy(db.Context, "TotalExplicit", 1)
		}
		newLoops = vineUser.LoopCount
		newPosts = vineUser.AuthoredPostCount
	}

	if newLoops > 0 {
		counter.IncrementBy(db.Context, "TotalLoops", newLoops)
		counter.IncrementBy(db.Context, "24hLoops", newLoops)
	}

	if newPosts > 0 {
		counter.IncrementBy(db.Context, "TotalPosts", newPosts)
		counter.IncrementBy(db.Context, "24hPosts", newPosts)
	}

	userRecord := UserRecord{
		UserId:            vineUser.UserIdStr,
		Username:          vineUser.Username,
		Description:       vineUser.Description,
		Location:          vineUser.Location,
		ProfileBackground: vineUser.ProfileBackground,
		AvatarUrl:         vineUser.AvatarUrl,
		FollowerCount:     vineUser.FollowerCount,
		FollowingCount:    vineUser.FollowingCount,
		LoopCount:         vineUser.LoopCount,
		LoopVelocity:      vineUser.LoopVelocity,
		PostCount:         vineUser.AuthoredPostCount,
		RevineCount:       (vineUser.PostCount - vineUser.AuthoredPostCount),
		LikeCount:         vineUser.LikeCount,
		Private:           (vineUser.Private != 0),
		Verified:          (vineUser.Verified != 0),
		Explicit:          (vineUser.ExplicitContent != 0),
		Discovered:        time.Now(),
	}
	if len(vineUser.VanityUrls) != 0 {
		userRecord.Vanity = strings.ToLower(vineUser.VanityUrls[0])
	}
	if _, err := datastore.Put(db.Context, recordKey, &userRecord); err != nil {
		log.Errorf(db.Context, "got error storing user record %s: %v", userId, err)
	}

	dataKey := datastore.NewIncompleteKey(db.Context, "UserData", recordKey)
	userData := UserData{
		UserId:    vineUser.UserId,
		Recorded:  time.Now(),
		Followers: vineUser.FollowerCount,
		Following: vineUser.FollowingCount,
		Loops:     vineUser.LoopCount,
		Velocity:  vineUser.LoopVelocity,
		Posts:     vineUser.AuthoredPostCount,
		Revines:   (vineUser.PostCount - vineUser.AuthoredPostCount),
		Likes:     vineUser.LikeCount,
	}
	if key, err := datastore.Put(db.Context, dataKey, &userData); err != nil {
		log.Errorf(db.Context, "got error storing user data %s - %v: %v", userId, key, err)
	}
}

func (db *DB) GetRecentUsers(n int, filter ...interface{}) (records []UserRecord, err error) {
	q := datastore.NewQuery("UserRecord").Order("-Discovered")
	if len(filter) > 0 && len(filter)%2 == 0 {
		for i := 0; i < len(filter)/2; i += 2 {
			q = q.Filter(filter[i].(string), filter[i+1])
		}
	}
	q = q.Limit(n)
	_, err = q.GetAll(db.Context, &records)
	return
}

func (db *DB) GetUser(userId int64) (user *UserRecord, err error) {
	user, err = db.GetUserRecord(userId)
	if err != nil {
		log.Infof(db.Context, "error with userRecord")
		return
	}
	user.UserData, err = db.GetUserData(userId)
	if err != nil {
		log.Infof(db.Context, "error with userData")
		return
	}

	user.UserMeta, err = db.GetUserMeta(userId)
	if err != nil {
		log.Infof(db.Context, "error with userMeta")
	}
	return
}

func (db *DB) GetUserRecord(userId int64) (*UserRecord, error) {

	user := UserRecord{}

	recordKey := datastore.NewKey(db.Context, "UserRecord", "", userId, nil)
	err := datastore.Get(db.Context, recordKey, &user)

	if err != nil {
		return nil, err
	} else {
		return &user, nil
	}
}

func (db *DB) GetUserData(userId int64) (userData []*UserData, err error) {

	dataQuery := datastore.NewQuery("UserData").Filter("UserId =", userId).Order("Recorded")

	_, err = dataQuery.GetAll(db.Context, &userData)
	return
}

func (db *DB) GetUserMeta(userId int64) (userMeta []*UserMeta, err error) {

	dataQuery := datastore.NewQuery("UserMeta").Filter("UserId =", userId).Order("Updated")

	_, err = dataQuery.GetAll(db.Context, &userMeta)
	return
}

func (db *DB) GetTotalUsers() (int, error) {

	var metaStats MetaStats

	key := datastore.NewKey(db.Context, "__Stat_Kind_IsRootEntity__", "UserMeta", 0, nil)
	err := datastore.Get(db.Context, key, &metaStats)

	return metaStats.Count, err
}

func (db *DB) GetTop() (data map[string]interface{}) {

	var topOverall, topFollowed, topLooped, topPosts, topRevines []UserRecord

	//top overall
	q := datastore.NewQuery("UserRecord").Order("-FollowerCount").Limit(10)
	q.GetAll(db.Context, &topOverall)

	sort.Sort(ByOverall(topOverall))

	//top followed
	q = datastore.NewQuery("UserRecord").Order("-FollowerCount").Limit(10)
	q.GetAll(db.Context, &topFollowed)

	//top looped
	q = datastore.NewQuery("UserRecord").Order("-LoopCount").Limit(10)
	q.GetAll(db.Context, &topLooped)

	//top posts
	q = datastore.NewQuery("UserRecord").Order("-PostCount").Limit(5)
	q.GetAll(db.Context, &topPosts)

	//top Revines
	q = datastore.NewQuery("UserRecord").Order("-RevineCount").Limit(5)
	q.GetAll(db.Context, &topRevines)

	data = map[string]interface{}{
		"topOverall":  topOverall,
		"topFollowed": topFollowed,
		"topLooped":   topLooped,
		"topPosts":    topPosts,
		"topRevines":  topRevines,
	}
	return
}

func (a ByOverall) Len() int      { return len(a) }
func (a ByOverall) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByOverall) Less(i, j int) bool {
	return a[i].FollowerCount > a[j].FollowerCount && a[i].LoopCount > a[j].LoopCount && a[i].FollowingCount < a[j].FollowingCount
}

func (a ByFollowers) Len() int      { return len(a) }
func (a ByFollowers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByFollowers) Less(i, j int) bool {
	return a[i].FollowerCount > a[j].FollowerCount
}

func (a ByLoops) Len() int      { return len(a) }
func (a ByLoops) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByLoops) Less(i, j int) bool {
	return a[i].LoopCount > a[j].LoopCount
}

func (a ByPosts) Len() int      { return len(a) }
func (a ByPosts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByPosts) Less(i, j int) bool {
	return a[i].PostCount > a[j].PostCount
}

func (a ByRevines) Len() int      { return len(a) }
func (a ByRevines) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByRevines) Less(i, j int) bool {
	return a[i].RevineCount > a[j].RevineCount
}

func (db *DB) UnqueueUser(user string) {
	var key *datastore.Key
	vineApi := VineRequest{db.Context}
	if vineApi.IsVanity(user) {
		q := datastore.NewQuery("Queue").Filter("UserID =", user).KeysOnly()
		keys, err := q.GetAll(db.Context, nil)
		if err == nil {
			key = keys[0]
		} else {
			log.Errorf(db.Context, "error removing %v from queue: %v", user, err)
		}
	} else {
		userId, _ := strconv.ParseInt(user, 10, 64)
		key = datastore.NewKey(db.Context, "Queue", "", userId, nil)
	}

	datastore.Delete(db.Context, key)
	log.Infof(db.Context, "%v removed from queue.", user)
}

func RandomKey(a []*datastore.Key) *datastore.Key {
	rand.Seed(time.Now().UTC().UnixNano())
	return a[rand.Intn(len(a))]
}

func RemoveDuplicates(a []string) []string {
	found := make(map[string]bool)
	j := 0
	for i, x := range a {
		if !found[x] {
			found[x] = true
			a[j] = a[i]
			j++
		}
	}
	return a[:j]
}
<commit_msg>Fixed discovered time.<commit_after>package main

import (
	"app/counter"
	"math/rand"
	"sort"
	"strconv"
	"strings"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/search"
)

type DB struct {
	Context context.Context
}

func (db *DB) FetchUser(userId string) {
	//Step 1. Get Vine user's data from the Vine API
	vineApi := VineRequest{db.Context}
	vineUser, err := vineApi.GetUser(userId)

	if err != nil {
		if err.Error() == ErrUserDoesntExist {
			db.UnqueueUser(userId)
		} else {
			log.Errorf(db.Context, "got error getting user %s from vine: %v", userId, err)
		}
		return
	} else if vineUser == nil {
		log.Errorf(db.Context, "failed fetch on user %v. got err %v", userId, err)
		return
	} else if vineUser.Private == 1 {
		return
	}

	recordKey := datastore.NewKey(db.Context, "UserRecord", "", vineUser.UserId, nil)

	//Step 2. Add user to user search index.
	userIndex := &UserIndex{
		Username:    vineUser.Username,
		Location:    vineUser.Location,
		Description: vineUser.Description,
	}

	if len(vineUser.VanityUrls) != 0 {
		userIndex.VanityUrl = strings.ToLower(vineUser.VanityUrls[0])
	}

	index, err := search.Open("users")
	if err != nil {
		log.Errorf(db.Context, "error opening users search index: %v", err)
	} else {
		index.Put(db.Context, vineUser.UserIdStr, userIndex)
	}

	var newLoops, newPosts int64
	var discoveredTime time.Time

	//Step 3. Write records (user {meta, record, data}).
	if userRecord, err := db.GetUserRecord(vineUser.UserId); err == nil {
		var userMeta []*UserMeta

		discoveredTime = userRecord.Discovered

		if vineUser.Username != userRecord.Username {
			userMeta = append(userMeta, &UserMeta{vineUser.UserId, "username", userRecord.Username, time.Now()})
		}

		if vineUser.Location != userRecord.Location {
			userMeta = append(userMeta, &UserMeta{vineUser.UserId, "location", userRecord.Location, time.Now()})
		}

		if vineUser.Description != userRecord.Description {
			userMeta = append(userMeta, &UserMeta{vineUser.UserId, "description", userRecord.Description, time.Now()})
		}

		if (vineUser.Verified != 0) != userRecord.Verified {
			userMeta = append(userMeta, &UserMeta{vineUser.UserId, "verified", strconv.FormatBool(userRecord.Verified), time.Now()})
		}

		newLoops = vineUser.LoopCount - userRecord.LoopCount
		newPosts = vineUser.AuthoredPostCount - userRecord.PostCount

		var metaKey *datastore.Key
		for _, m := range userMeta {
			metaKey = datastore.NewIncompleteKey(db.Context, "UserMeta", recordKey)
			if key, err := datastore.Put(db.Context, metaKey, m); err != nil {
				log.Errorf(db.Context, "got error storing user meta %s - %v: %v", userId, key, err)
			}
		}
	} else if err == datastore.ErrNoSuchEntity {

		discoveredTime = time.Now()

		counter.IncrementBy(db.Context, "TotalUsers", 1)
		counter.IncrementBy(db.Context, "24hUsers", 1)

		if vineUser.Verified == 1 {
			counter.IncrementBy(db.Context, "TotalVerified", 1)
		}
		if vineUser.ExplicitContent == 1 {
			counter.IncrementBy(db.Context, "TotalExplicit", 1)
		}
		newLoops = vineUser.LoopCount
		newPosts = vineUser.AuthoredPostCount
	}

	if newLoops > 0 {
		counter.IncrementBy(db.Context, "TotalLoops", newLoops)
		counter.IncrementBy(db.Context, "24hLoops", newLoops)
	}

	if newPosts > 0 {
		counter.IncrementBy(db.Context, "TotalPosts", newPosts)
		counter.IncrementBy(db.Context, "24hPosts", newPosts)
	}

	userRecord := UserRecord{
		UserId:            vineUser.UserIdStr,
		Username:          vineUser.Username,
		Description:       vineUser.Description,
		Location:          vineUser.Location,
		ProfileBackground: vineUser.ProfileBackground,
		AvatarUrl:         vineUser.AvatarUrl,
		FollowerCount:     vineUser.FollowerCount,
		FollowingCount:    vineUser.FollowingCount,
		LoopCount:         vineUser.LoopCount,
		LoopVelocity:      vineUser.LoopVelocity,
		PostCount:         vineUser.AuthoredPostCount,
		RevineCount:       (vineUser.PostCount - vineUser.AuthoredPostCount),
		LikeCount:         vineUser.LikeCount,
		Private:           (vineUser.Private != 0),
		Verified:          (vineUser.Verified != 0),
		Explicit:          (vineUser.ExplicitContent != 0),
		Discovered:        discoveredTime,
	}
	if len(vineUser.VanityUrls) != 0 {
		userRecord.Vanity = strings.ToLower(vineUser.VanityUrls[0])
	}
	if _, err := datastore.Put(db.Context, recordKey, &userRecord); err != nil {
		log.Errorf(db.Context, "got error storing user record %s: %v", userId, err)
	}

	dataKey := datastore.NewIncompleteKey(db.Context, "UserData", recordKey)
	userData := UserData{
		UserId:    vineUser.UserId,
		Recorded:  time.Now(),
		Followers: vineUser.FollowerCount,
		Following: vineUser.FollowingCount,
		Loops:     vineUser.LoopCount,
		Velocity:  vineUser.LoopVelocity,
		Posts:     vineUser.AuthoredPostCount,
		Revines:   (vineUser.PostCount - vineUser.AuthoredPostCount),
		Likes:     vineUser.LikeCount,
	}
	if key, err := datastore.Put(db.Context, dataKey, &userData); err != nil {
		log.Errorf(db.Context, "got error storing user data %s - %v: %v", userId, key, err)
	}
}

func (db *DB) GetRecentUsers(n int, filter ...interface{}) (records []UserRecord, err error) {
	q := datastore.NewQuery("UserRecord").Order("-Discovered")
	if len(filter) > 0 && len(filter)%2 == 0 {
		for i := 0; i < len(filter)/2; i += 2 {
			q = q.Filter(filter[i].(string), filter[i+1])
		}
	}
	q = q.Limit(n)
	_, err = q.GetAll(db.Context, &records)
	return
}

func (db *DB) GetUser(userId int64) (user *UserRecord, err error) {
	user, err = db.GetUserRecord(userId)
	if err != nil {
		log.Infof(db.Context, "error with userRecord")
		return
	}
	user.UserData, err = db.GetUserData(userId)
	if err != nil {
		log.Infof(db.Context, "error with userData")
		return
	}

	user.UserMeta, err = db.GetUserMeta(userId)
	if err != nil {
		log.Infof(db.Context, "error with userMeta")
	}
	return
}

func (db *DB) GetUserRecord(userId int64) (*UserRecord, error) {

	user := UserRecord{}

	recordKey := datastore.NewKey(db.Context, "UserRecord", "", userId, nil)
	err := datastore.Get(db.Context, recordKey, &user)

	if err != nil {
		return nil, err
	} else {
		return &user, nil
	}
}

func (db *DB) GetUserData(userId int64) (userData []*UserData, err error) {

	dataQuery := datastore.NewQuery("UserData").Filter("UserId =", userId).Order("Recorded")

	_, err = dataQuery.GetAll(db.Context, &userData)
	return
}

func (db *DB) GetUserMeta(userId int64) (userMeta []*UserMeta, err error) {

	dataQuery := datastore.NewQuery("UserMeta").Filter("UserId =", userId).Order("Updated")

	_, err = dataQuery.GetAll(db.Context, &userMeta)
	return
}

func (db *DB) GetTotalUsers() (int, error) {

	var metaStats MetaStats

	key := datastore.NewKey(db.Context, "__Stat_Kind_IsRootEntity__", "UserMeta", 0, nil)
	err := datastore.Get(db.Context, key, &metaStats)

	return metaStats.Count, err
}

func (db *DB) GetTop() (data map[string]interface{}) {

	var topOverall, topFollowed, topLooped, topPosts, topRevines []UserRecord

	//top overall
	q := datastore.NewQuery("UserRecord").Order("-FollowerCount").Limit(10)
	q.GetAll(db.Context, &topOverall)

	sort.Sort(ByOverall(topOverall))

	//top followed
	q = datastore.NewQuery("UserRecord").Order("-FollowerCount").Limit(10)
	q.GetAll(db.Context, &topFollowed)

	//top looped
	q = datastore.NewQuery("UserRecord").Order("-LoopCount").Limit(10)
	q.GetAll(db.Context, &topLooped)

	//top posts
	q = datastore.NewQuery("UserRecord").Order("-PostCount").Limit(5)
	q.GetAll(db.Context, &topPosts)

	//top Revines
	q = datastore.NewQuery("UserRecord").Order("-RevineCount").Limit(5)
	q.GetAll(db.Context, &topRevines)

	data = map[string]interface{}{
		"topOverall":  topOverall,
		"topFollowed": topFollowed,
		"topLooped":   topLooped,
		"topPosts":    topPosts,
		"topRevines":  topRevines,
	}
	return
}

func (a ByOverall) Len() int      { return len(a) }
func (a ByOverall) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByOverall) Less(i, j int) bool {
	return a[i].FollowerCount > a[j].FollowerCount && a[i].LoopCount > a[j].LoopCount && a[i].FollowingCount < a[j].FollowingCount
}

func (a ByFollowers) Len() int      { return len(a) }
func (a ByFollowers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByFollowers) Less(i, j int) bool {
	return a[i].FollowerCount > a[j].FollowerCount
}

func (a ByLoops) Len() int      { return len(a) }
func (a ByLoops) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByLoops) Less(i, j int) bool {
	return a[i].LoopCount > a[j].LoopCount
}

func (a ByPosts) Len() int      { return len(a) }
func (a ByPosts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByPosts) Less(i, j int) bool {
	return a[i].PostCount > a[j].PostCount
}

func (a ByRevines) Len() int      { return len(a) }
func (a ByRevines) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByRevines) Less(i, j int) bool {
	return a[i].RevineCount > a[j].RevineCount
}

func (db *DB) UnqueueUser(user string) {
	var key *datastore.Key
	vineApi := VineRequest{db.Context}
	if vineApi.IsVanity(user) {
		q := datastore.NewQuery("Queue").Filter("UserID =", user).KeysOnly()
		keys, err := q.GetAll(db.Context, nil)
		if err == nil {
			key = keys[0]
		} else {
			log.Errorf(db.Context, "error removing %v from queue: %v", user, err)
		}
	} else {
		userId, _ := strconv.ParseInt(user, 10, 64)
		key = datastore.NewKey(db.Context, "Queue", "", userId, nil)
	}

	datastore.Delete(db.Context, key)
	log.Infof(db.Context, "%v removed from queue.", user)
}

func RandomKey(a []*datastore.Key) *datastore.Key {
	rand.Seed(time.Now().UTC().UnixNano())
	return a[rand.Intn(len(a))]
}

func RemoveDuplicates(a []string) []string {
	found := make(map[string]bool)
	j := 0
	for i, x := range a {
		if !found[x] {
			found[x] = true
			a[j] = a[i]
			j++
		}
	}
	return a[:j]
}
<|endoftext|>


<commit_before>package service

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os/exec"
	"regexp"
	"time"

	"github.com/Azure/acs-engine/test/e2e/kubernetes/util"
)

// Service represents a kubernetes service
type Service struct {
	Metadata Metadata `json:"metadata"`
	Spec     Spec     `json:"spec"`
	Status   Status   `json:"status"`
}

// Metadata holds information like name, namespace, and labels
type Metadata struct {
	CreatedAt time.Time         `json:"creationTimestamp"`
	Labels    map[string]string `json:"labels"`
	Name      string            `json:"name"`
	Namespace string            `json:"namespace"`
}

// Spec holds information like clusterIP and port
type Spec struct {
	ClusterIP string `json:"clusterIP"`
	Ports     []Port `json:"ports"`
	Type      string `json:"type"`
}

// Port represents a service port definition
type Port struct {
	NodePort   int    `json:"nodePort"`
	Port       int    `json:"port"`
	Protocol   string `json:"protocol"`
	TargetPort int    `json:"targetPort"`
}

// Status holds the load balancer definition
type Status struct {
	LoadBalancer LoadBalancer `json:"loadBalancer"`
}

// LoadBalancer holds the ingress definitions
type LoadBalancer struct {
	Ingress []map[string]string `json:"ingress"`
}

// Get returns the service definition specified in a given namespace
func Get(name, namespace string) (*Service, error) {
	cmd := exec.Command("kubectl", "get", "svc", "-o", "json", "-n", namespace, name)
	util.PrintCommand(cmd)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("Error trying to run 'kubectl get svc':%s\n", string(out))
		return nil, err
	}
	s := Service{}
	err = json.Unmarshal(out, &s)
	if err != nil {
		log.Printf("Error unmarshalling service json:%s\n", err)
		return nil, err
	}
	return &s, nil
}

// Delete will delete a service in a given namespace
func (s *Service) Delete() error {
	cmd := exec.Command("kubectl", "delete", "svc", "-n", s.Metadata.Namespace, s.Metadata.Name)
	util.PrintCommand(cmd)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("Error while trying to delete service %s in namespace %s:%s\n", s.Metadata.Namespace, s.Metadata.Name, string(out))
		return err
	}
	return nil
}

// GetNodePort will return the node port for a given pod
func (s *Service) GetNodePort(port int) int {
	for _, p := range s.Spec.Ports {
		if p.Port == port {
			return p.NodePort
		}
	}
	return 0
}

// WaitForExternalIP waits for an external ip to be provisioned
func (s *Service) WaitForExternalIP(wait, sleep time.Duration) (*Service, error) {
	svcCh := make(chan *Service)
	errCh := make(chan error)
	ctx, cancel := context.WithTimeout(context.Background(), wait)
	defer cancel()
	go func() {
		for {
			select {
			case <-ctx.Done():
				errCh <- fmt.Errorf("Timeout exceeded while waiting for External IP to be provisioned")
			default:
				svc, _ := Get(s.Metadata.Name, s.Metadata.Namespace)
				if svc != nil && svc.Status.LoadBalancer.Ingress != nil {
					svcCh <- svc
				}
				time.Sleep(sleep)
			}
		}
	}()
	for {
		select {
		case err := <-errCh:
			return nil, err
		case svc := <-svcCh:
			return svc, nil
		}
	}
}

// Validate will attempt to run an http.Get against the root service url
func (s *Service) Validate(check string, attempts int, sleep, wait time.Duration) bool {
	var err error
	var url string
	var i int
	var resp *http.Response
	svc, waitErr := s.WaitForExternalIP(wait, 5*time.Second)
	if waitErr != nil {
		log.Printf("Unable to verify external IP, cannot validate service:%s\n", waitErr)
		return false
	}
	if svc.Status.LoadBalancer.Ingress == nil || len(svc.Status.LoadBalancer.Ingress) == 0 {
		log.Printf("Service LB ingress is empty or nil: %#v\n", svc.Status.LoadBalancer.Ingress)
		return false
	}
	for i = 1; i <= attempts; i++ {
		url = fmt.Sprintf("http://%s", svc.Status.LoadBalancer.Ingress[0]["ip"])
		resp, err = http.Get(url)
		if err == nil {
			body, _ := ioutil.ReadAll(resp.Body)
			matched, _ := regexp.MatchString(check, string(body))
			if matched {
				defer resp.Body.Close()
				return true
			}
			log.Printf("Got unexpected URL body, expected to find %s, got:\n%s\n", check, string(body))
		}
		time.Sleep(sleep)
	}
	log.Printf("Unable to validate URL %s after %s, err: %#v\n", url, time.Duration(i)*wait, err)
	if resp != nil {
		defer resp.Body.Close()
	}
	return false
}

// CreateServiceFromFile will create a Service from file with a name
func CreateServiceFromFile(filename, name, namespace string) (*Service, error) {
	cmd := exec.Command("kubectl", "create", "-f", filename)
	util.PrintCommand(cmd)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("Error trying to create Service %s:%s\n", name, string(out))
		return nil, err
	}
	svc, err := Get(name, namespace)
	if err != nil {
		log.Printf("Error while trying to fetch Service %s:%s\n", name, err)
		return nil, err
	}
	return svc, nil
}
<commit_msg>E2E ILB test only create service once (#2667)<commit_after>package service

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os/exec"
	"regexp"
	"time"

	"github.com/Azure/acs-engine/test/e2e/kubernetes/util"
)

// Service represents a kubernetes service
type Service struct {
	Metadata Metadata `json:"metadata"`
	Spec     Spec     `json:"spec"`
	Status   Status   `json:"status"`
}

// Metadata holds information like name, namespace, and labels
type Metadata struct {
	CreatedAt time.Time         `json:"creationTimestamp"`
	Labels    map[string]string `json:"labels"`
	Name      string            `json:"name"`
	Namespace string            `json:"namespace"`
}

// Spec holds information like clusterIP and port
type Spec struct {
	ClusterIP string `json:"clusterIP"`
	Ports     []Port `json:"ports"`
	Type      string `json:"type"`
}

// Port represents a service port definition
type Port struct {
	NodePort   int    `json:"nodePort"`
	Port       int    `json:"port"`
	Protocol   string `json:"protocol"`
	TargetPort int    `json:"targetPort"`
}

// Status holds the load balancer definition
type Status struct {
	LoadBalancer LoadBalancer `json:"loadBalancer"`
}

// LoadBalancer holds the ingress definitions
type LoadBalancer struct {
	Ingress []map[string]string `json:"ingress"`
}

// Get returns the service definition specified in a given namespace
func Get(name, namespace string) (*Service, error) {
	cmd := exec.Command("kubectl", "get", "svc", "-o", "json", "-n", namespace, name)
	util.PrintCommand(cmd)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("Error trying to run 'kubectl get svc':%s\n", string(out))
		return nil, err
	}
	s := Service{}
	err = json.Unmarshal(out, &s)
	if err != nil {
		log.Printf("Error unmarshalling service json:%s\n", err)
		return nil, err
	}
	return &s, nil
}

// Delete will delete a service in a given namespace
func (s *Service) Delete() error {
	cmd := exec.Command("kubectl", "delete", "svc", "-n", s.Metadata.Namespace, s.Metadata.Name)
	util.PrintCommand(cmd)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("Error while trying to delete service %s in namespace %s:%s\n", s.Metadata.Namespace, s.Metadata.Name, string(out))
		return err
	}
	return nil
}

// GetNodePort will return the node port for a given pod
func (s *Service) GetNodePort(port int) int {
	for _, p := range s.Spec.Ports {
		if p.Port == port {
			return p.NodePort
		}
	}
	return 0
}

// WaitForExternalIP waits for an external ip to be provisioned
func (s *Service) WaitForExternalIP(wait, sleep time.Duration) (*Service, error) {
	svcCh := make(chan *Service)
	errCh := make(chan error)
	ctx, cancel := context.WithTimeout(context.Background(), wait)
	defer cancel()
	go func() {
		for {
			select {
			case <-ctx.Done():
				errCh <- fmt.Errorf("Timeout exceeded while waiting for External IP to be provisioned")
			default:
				svc, _ := Get(s.Metadata.Name, s.Metadata.Namespace)
				if svc != nil && svc.Status.LoadBalancer.Ingress != nil {
					svcCh <- svc
				}
				time.Sleep(sleep)
			}
		}
	}()
	for {
		select {
		case err := <-errCh:
			return nil, err
		case svc := <-svcCh:
			return svc, nil
		}
	}
}

// Validate will attempt to run an http.Get against the root service url
func (s *Service) Validate(check string, attempts int, sleep, wait time.Duration) bool {
	var err error
	var url string
	var i int
	var resp *http.Response
	svc, waitErr := s.WaitForExternalIP(wait, 5*time.Second)
	if waitErr != nil {
		log.Printf("Unable to verify external IP, cannot validate service:%s\n", waitErr)
		return false
	}
	if svc.Status.LoadBalancer.Ingress == nil || len(svc.Status.LoadBalancer.Ingress) == 0 {
		log.Printf("Service LB ingress is empty or nil: %#v\n", svc.Status.LoadBalancer.Ingress)
		return false
	}
	for i = 1; i <= attempts; i++ {
		url = fmt.Sprintf("http://%s", svc.Status.LoadBalancer.Ingress[0]["ip"])
		resp, err = http.Get(url)
		if err == nil {
			body, _ := ioutil.ReadAll(resp.Body)
			matched, _ := regexp.MatchString(check, string(body))
			if matched {
				defer resp.Body.Close()
				return true
			}
			log.Printf("Got unexpected URL body, expected to find %s, got:\n%s\n", check, string(body))
		}
		time.Sleep(sleep)
	}
	log.Printf("Unable to validate URL %s after %s, err: %#v\n", url, time.Duration(i)*wait, err)
	if resp != nil {
		defer resp.Body.Close()
	}
	return false
}

// CreateServiceFromFile will create a Service from file with a name
func CreateServiceFromFile(filename, name, namespace string) (*Service, error) {
	svc, err := Get(name, namespace)
	if err == nil {
		log.Printf("Service %s already exists\n", name)
		return svc, nil
	}
	cmd := exec.Command("kubectl", "create", "-f", filename)
	util.PrintCommand(cmd)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("Error trying to create Service %s:%s\n", name, string(out))
		return nil, err
	}
	svc, err = Get(name, namespace)
	if err != nil {
		log.Printf("Error while trying to fetch Service %s:%s\n", name, err)
		return nil, err
	}
	return svc, nil
}
<|endoftext|>