Пример #1
0
func TestDataCreateUserHandlesNameUniqueness(t *testing.T) {
	pool := newConnPool(t)

	u := newUser()
	_, err := data.CreateUser(pool, u)
	if err != nil {
		t.Fatal(err)
	}

	u = newUser()
	_, err = data.CreateUser(pool, u)
	if err != (data.DuplicationError{Field: "name"}) {
		t.Fatalf("Expected %v, got %v", data.DuplicationError{Field: "name"}, err)
	}
}
Пример #2
0
func TestDataCreateUserHandlesEmailUniqueness(t *testing.T) {
	pool := newConnPool(t)

	u := newUser()
	u.Email = data.NewString("*****@*****.**")
	_, err := data.CreateUser(pool, u)
	if err != nil {
		t.Fatal(err)
	}

	u.Name = data.NewString("othername")
	_, err = data.CreateUser(pool, u)
	if err != (data.DuplicationError{Field: "email"}) {
		t.Fatalf("Expected %v, got %v", data.DuplicationError{Field: "email"}, err)
	}
}
Пример #3
0
func TestDataSubscriptions(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		t.Fatal(err)
	}

	url := "http://foo"
	err = data.InsertSubscription(pool, userID, url)
	if err != nil {
		t.Fatal(err)
	}

	subscriptions, err := data.SelectSubscriptions(pool, userID)
	if err != nil {
		t.Fatal(err)
	}
	if len(subscriptions) != 1 {
		t.Fatalf("Found %d subscriptions, expected 1", len(subscriptions))
	}
	if subscriptions[0].URL.Value != url {
		t.Fatalf("Expected %v, got %v", url, subscriptions[0].URL)
	}
}
Пример #4
0
func TestDataCopySubscriptionsForUserAsJSON(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		t.Fatal(err)
	}

	buffer := &bytes.Buffer{}
	err = data.CopySubscriptionsForUserAsJSON(pool, buffer, userID)
	if err != nil {
		t.Fatalf("Failed when no subscriptions: %v", err)
	}

	err = data.InsertSubscription(pool, userID, "http://foo")
	if err != nil {
		t.Fatal(err)
	}

	buffer.Reset()
	err = data.CopySubscriptionsForUserAsJSON(pool, buffer, userID)
	if err != nil {
		t.Fatal(err)
	}
	if bytes.Contains(buffer.Bytes(), []byte("foo")) != true {
		t.Errorf("Expected %v, got %v", true, bytes.Contains(buffer.Bytes(), []byte("foo")))
	}
}
Пример #5
0
func TestDataDeleteSubscription(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		t.Fatal(err)
	}

	err = data.InsertSubscription(pool, userID, "http://foo")
	if err != nil {
		t.Fatal(err)
	}

	subscriptions, err := data.SelectSubscriptions(pool, userID)
	if err != nil {
		t.Fatal(err)
	}
	if len(subscriptions) != 1 {
		t.Fatalf("Found %d subscriptions, expected 1", len(subscriptions))
	}
	feedID := subscriptions[0].FeedID.Value

	update := &data.ParsedFeed{Name: "baz", Items: []data.ParsedItem{
		{URL: "http://baz/bar", Title: "Baz", PublicationTime: data.NewTime(time.Now())},
	}}

	nullString := data.String{Status: data.Null}

	err = data.UpdateFeedWithFetchSuccess(pool, feedID, update, nullString, time.Now().Add(-20*time.Minute))
	if err != nil {
		t.Fatal(err)
	}

	err = data.DeleteSubscription(pool, userID, feedID)
	if err != nil {
		t.Fatal(err)
	}

	subscriptions, err = data.SelectSubscriptions(pool, userID)
	if err != nil {
		t.Fatal(err)
	}
	if len(subscriptions) != 0 {
		t.Errorf("Found %d subscriptions, expected 0", len(subscriptions))
	}

	// feed should have been deleted as it was the last user
	staleFeeds, err := data.GetFeedsUncheckedSince(pool, time.Now())
	if err != nil {
		t.Fatal(err)
	}
	if len(staleFeeds) != 0 {
		t.Errorf("Found %d staleFeeds, expected 0", len(staleFeeds))
	}
}
Пример #6
0
func TestGetAccountHandler(t *testing.T) {
	pool := newConnPool(t)
	user := &data.User{
		Name:  data.NewString("test"),
		Email: data.NewString("*****@*****.**"),
	}
	SetPassword(user, "password")

	userID, err := data.CreateUser(pool, user)
	if err != nil {
		t.Fatal(err)
	}

	user, err = data.SelectUserByPK(pool, userID)
	if err != nil {
		t.Fatal(err)
	}

	req, err := http.NewRequest("GET", "http://example.com/", nil)
	if err != nil {
		t.Fatal(err)
	}

	env := &environment{user: user, pool: pool}
	w := httptest.NewRecorder()
	GetAccountHandler(w, req, env)

	if w.Code != 200 {
		t.Fatalf("Expected HTTP status 200, instead received %d", w.Code)
	}

	var resp struct {
		ID    int32  `json:"id"`
		Name  string `json:"name"`
		Email string `json:"email"`
	}

	decoder := json.NewDecoder(w.Body)
	if err := decoder.Decode(&resp); err != nil {
		t.Fatal(err)
	}

	if user.ID.Value != resp.ID {
		t.Errorf("Expected id %d, instead received %d", user.ID.Value, resp.ID)
	}

	if user.Name.Value != resp.Name {
		t.Errorf("Expected name %s, instead received %s", user.Name.Value, resp.Name)
	}

	if user.Email.Value != resp.Email {
		t.Errorf("Expected email %s, instead received %s", user.Email.Value, resp.Email)
	}
}
Пример #7
0
func TestResetPasswordHandlerTokenMatchestUsedPasswordReset(t *testing.T) {
	pool := newConnPool(t)
	user := &data.User{
		Name:  data.NewString("test"),
		Email: data.NewString("*****@*****.**"),
	}
	SetPassword(user, "password")

	userID, err := data.CreateUser(pool, user)
	if err != nil {
		t.Fatalf("repo.CreateUser returned error: %v", err)
	}

	_, localhost, _ := net.ParseCIDR("127.0.0.1/32")
	pwr := &data.PasswordReset{
		Token:          data.NewString("0123456789abcdef"),
		Email:          data.NewString("*****@*****.**"),
		UserID:         data.NewInt32(userID),
		RequestTime:    data.NewTime(time.Now()),
		RequestIP:      data.NewIPNet(*localhost),
		CompletionTime: data.NewTime(time.Now()),
		CompletionIP:   data.NewIPNet(*localhost),
	}

	err = data.InsertPasswordReset(pool, pwr)
	if err != nil {
		t.Fatalf("repo.CreatePasswordReset returned error: %v", err)
	}

	buf := bytes.NewBufferString(`{"token": "0123456789abcdef", "password": "******"}`)

	req, err := http.NewRequest("POST", "http://example.com/", buf)
	if err != nil {
		t.Fatalf("http.NewRequest returned error: %v", err)
	}

	env := &environment{pool: pool}
	w := httptest.NewRecorder()
	ResetPasswordHandler(w, req, env)

	if w.Code != 404 {
		t.Errorf("Expected HTTP status %d, instead received %d", 404, w.Code)
	}

	user, err = data.SelectUserByPK(pool, userID)
	if err != nil {
		t.Fatalf("repo.GetUser returned error: %v", err)
	}

	if IsPassword(user, "bigsecret") {
		t.Error("Expected password not to be changed but it was")
	}
}
Пример #8
0
func BenchmarkDataGetUser(b *testing.B) {
	pool := newConnPool(b)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := data.SelectUserByPK(pool, userID)
		if err != nil {
			b.Fatal(err)
		}
	}
}
Пример #9
0
func BenchmarkDataGetUserByName(b *testing.B) {
	pool := newConnPool(b)

	user := newUser()
	_, err := data.CreateUser(pool, user)
	if err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_, err := data.SelectUserByName(pool, user.Name.Value)
		if err != nil {
			b.Fatal(err)
		}
	}
}
Пример #10
0
func TestDataSessions(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		t.Fatal(err)
	}

	sessionID := []byte("deadbeef")

	err = data.InsertSession(pool,
		&data.Session{
			ID:     data.NewBytes(sessionID),
			UserID: data.NewInt32(userID),
		},
	)
	if err != nil {
		t.Fatal(err)
	}

	user, err := data.SelectUserBySessionID(pool, sessionID)
	if err != nil {
		t.Fatal(err)
	}
	if user.ID.Value != userID {
		t.Errorf("Expected %v, got %v", userID, user.ID)
	}

	err = data.DeleteSession(pool, sessionID)
	if err != nil {
		t.Fatal(err)
	}

	_, err = data.SelectUserBySessionID(pool, sessionID)
	if err != data.ErrNotFound {
		t.Fatalf("Expected %v, got %v", data.ErrNotFound, err)
	}

	err = data.DeleteSession(pool, sessionID)
	if err != data.ErrNotFound {
		t.Fatalf("Expected %v, got %v", notFound, err)
	}
}
Пример #11
0
func TestExportOPML(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, &data.User{
		Name:           data.NewString("test"),
		Email:          data.NewString("*****@*****.**"),
		PasswordDigest: data.NewBytes([]byte("digest")),
		PasswordSalt:   data.NewBytes([]byte("salt")),
	})
	if err != nil {
		t.Fatal(err)
	}

	err = data.InsertSubscription(pool, userID, "http://example.com/feed.rss")
	if err != nil {
		t.Fatal(err)
	}

	req, err := http.NewRequest("GET", "http://example.com/", nil)
	if err != nil {
		t.Fatal(err)
	}

	env := &environment{pool: pool}
	env.user = &data.User{ID: data.NewInt32(userID), Name: data.NewString("test")}

	w := httptest.NewRecorder()

	ExportFeedsHandler(w, req, env)

	if w.Code != 200 {
		t.Fatalf("Expected HTTP status 200, instead received %d", w.Code)
	}

	expected := `<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0"><head><title>The Pithy Reader Export for test</title></head><body><outline text="http://example.com/feed.rss" title="http://example.com/feed.rss" type="rss" xmlUrl="http://example.com/feed.rss"></outline></body></opml>`

	if w.Body.String() != expected {
		t.Fatalf("Expected:\n%s\nGot:\n%s\n", expected, w.Body.String())
	}
}
Пример #12
0
Файл: http.go Проект: jackc/tpr
func RegisterHandler(w http.ResponseWriter, req *http.Request, env *environment) {
	var registration struct {
		Name     string `json:"name"`
		Email    string `json:"email"`
		Password string `json:"password"`
	}

	decoder := json.NewDecoder(req.Body)
	if err := decoder.Decode(&registration); err != nil {
		w.WriteHeader(422)
		fmt.Fprintf(w, "Error decoding request: %v", err)
		return
	}

	if registration.Name == "" {
		w.WriteHeader(422)
		fmt.Fprintln(w, `Request must include the attribute "name"`)
		return
	}

	if len(registration.Name) > 30 {
		w.WriteHeader(422)
		fmt.Fprintln(w, `"name" must be less than 30 characters`)
		return
	}

	err := validatePassword(registration.Password)
	if err != nil {
		w.WriteHeader(422)
		fmt.Fprintln(w, err)
		return
	}

	user := &data.User{}
	user.Name = data.NewString(registration.Name)
	user.Email = newStringFallback(registration.Email, data.Undefined)
	SetPassword(user, registration.Password)

	userID, err := data.CreateUser(env.pool, user)
	if err != nil {
		if err, ok := err.(data.DuplicationError); ok {
			w.WriteHeader(422)
			fmt.Fprintf(w, `"%s" is already taken`, err.Field)
			return
		} else {
			http.Error(w, "Internal server error", http.StatusInternalServerError)
			return
		}
	}

	sessionID, err := genSessionID()
	if err != nil {
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	err = data.InsertSession(env.pool,
		&data.Session{
			ID:     data.NewBytes(sessionID),
			UserID: data.NewInt32(userID),
		},
	)
	if err != nil {
		http.Error(w, "Internal server error", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusCreated)

	var response struct {
		Name      string `json:"name"`
		SessionID string `json:"sessionID"`
	}

	response.Name = registration.Name
	response.SessionID = hex.EncodeToString(sessionID)

	encoder := json.NewEncoder(w)
	encoder.Encode(response)
}
Пример #13
0
func TestUpdateAccountHandler(t *testing.T) {
	origEmail := "*****@*****.**"
	origPassword := "******"

	var tests = []struct {
		descr               string
		reqEmail            string
		reqExistingPassword string
		reqNewPassword      string
		respCode            int
		actualEmail         string
		actualPassword      string
	}{
		{
			descr:               "Update email and password",
			reqEmail:            "*****@*****.**",
			reqExistingPassword: origPassword,
			reqNewPassword:      "******",
			respCode:            200,
			actualEmail:         "*****@*****.**",
			actualPassword:      "******",
		},
		{
			descr:               "Update email",
			reqEmail:            "*****@*****.**",
			reqExistingPassword: origPassword,
			reqNewPassword:      "",
			respCode:            200,
			actualEmail:         "*****@*****.**",
			actualPassword:      origPassword,
		},
		{
			descr:               "Deny update of email and password",
			reqEmail:            "*****@*****.**",
			reqExistingPassword: "******",
			reqNewPassword:      "******",
			respCode:            422,
			actualEmail:         origEmail,
			actualPassword:      origPassword,
		},
		{
			descr:               "Deny update of email",
			reqEmail:            "*****@*****.**",
			reqExistingPassword: "******",
			reqNewPassword:      "",
			respCode:            422,
			actualEmail:         origEmail,
			actualPassword:      origPassword,
		},
	}

	for _, tt := range tests {
		pool := newConnPool(t)
		user := &data.User{
			Name:  data.NewString("test"),
			Email: data.NewString(origEmail),
		}
		SetPassword(user, origPassword)

		userID, err := data.CreateUser(pool, user)
		if err != nil {
			t.Errorf("%s: repo.CreateUser returned error: %v", tt.descr, err)
			continue
		}

		user, err = data.SelectUserByPK(pool, userID)
		if err != nil {
			t.Errorf("%s: repo.GetUser returned error: %v", tt.descr, err)
			continue
		}

		buf := bytes.NewBufferString(`{
			"email": "` + tt.reqEmail + `",
			"existingPassword": "******",
			"newPassword": "******"
		}`)

		req, err := http.NewRequest("PATCH", "http://example.com/", buf)
		if err != nil {
			t.Errorf("%s: http.NewRequest returned error: %v", tt.descr, err)
			continue
		}

		env := &environment{user: user, pool: pool}
		w := httptest.NewRecorder()
		UpdateAccountHandler(w, req, env)

		if w.Code != tt.respCode {
			t.Errorf("%s: Expected HTTP status %d, instead received %d", tt.descr, tt.respCode, w.Code)
			continue
		}

		user, err = data.SelectUserByPK(pool, userID)
		if err != nil {
			t.Errorf("%s: repo.GetUser returned error: %v", tt.descr, err)
			continue
		}

		if user.Email.Value != tt.actualEmail {
			t.Errorf("%s: Expected email %s, instead received %s", tt.descr, tt.actualEmail, user.Email.Value)
		}

		if !IsPassword(user, tt.actualPassword) {
			t.Errorf("%s: Expected password to be %s, but it wasn't", tt.descr, tt.actualPassword)
		}
	}
}
Пример #14
0
func TestRequestPasswordResetHandler(t *testing.T) {

	var tests = []struct {
		descr      string
		mailer     *testMailer
		userEmail  string
		reqEmail   string
		remoteAddr string
		remoteHost string
		sentMailTo string
	}{
		{
			descr:      "Email does not match user",
			mailer:     &testMailer{},
			userEmail:  "*****@*****.**",
			reqEmail:   "*****@*****.**",
			remoteAddr: "192.168.0.1:54678",
			remoteHost: "192.168.0.1/32",
		},
		{
			descr:      "Email matches user",
			mailer:     &testMailer{},
			userEmail:  "*****@*****.**",
			reqEmail:   "*****@*****.**",
			remoteAddr: "192.168.0.1:54678",
			remoteHost: "192.168.0.1/32",
			sentMailTo: "*****@*****.**",
		},
	}

	for _, tt := range tests {
		pool := newConnPool(t)
		user := &data.User{
			Name:  data.NewString("test"),
			Email: data.NewString(tt.userEmail),
		}
		SetPassword(user, "password")

		userID, err := data.CreateUser(pool, user)
		if err != nil {
			t.Errorf("%s: repo.CreateUser returned error: %v", tt.descr, err)
			continue
		}

		buf := bytes.NewBufferString(`{"email": "` + tt.reqEmail + `"}`)

		req, err := http.NewRequest("POST", "http://example.com/", buf)
		if err != nil {
			t.Errorf("%s: http.NewRequest returned error: %v", tt.descr, err)
			continue
		}
		req.RemoteAddr = tt.remoteAddr

		env := &environment{user: user, pool: pool, logger: getLogger(t), mailer: tt.mailer}
		w := httptest.NewRecorder()
		RequestPasswordResetHandler(w, req, env)

		if w.Code != 200 {
			t.Errorf("%s: Expected HTTP status %d, instead received %d", tt.descr, 200, w.Code)
			continue
		}

		// Need to reach down pgx because repo interface doesn't need any get
		// interface besides by token, but for this test we need to know the token
		var token string
		err = pool.QueryRow("select token from password_resets").Scan(&token)
		if err != nil {
			t.Errorf("%s: pool.QueryRow Scan returned error: %v", tt.descr, err)
			continue
		}
		pwr, err := data.SelectPasswordResetByPK(env.pool, token)
		if err != nil {
			t.Errorf("%s: repo.GetPasswordReset returned error: %v", tt.descr, err)
			continue
		}

		if pwr.Email.Value != tt.reqEmail {
			t.Errorf("%s: PasswordReset.Email should be %s, but instead is %v", tt.descr, tt.reqEmail, pwr.Email)
		}
		if pwr.RequestIP.Value.String() != tt.remoteHost {
			t.Errorf("%s: PasswordReset.RequestIP should be %s, but instead is %v", tt.descr, tt.remoteHost, pwr.RequestIP)
		}
		if tt.reqEmail == tt.userEmail && userID != pwr.UserID.Value {
			t.Errorf("%s: PasswordReset.UserID should be %d, but instead is %v", tt.descr, userID, pwr.UserID)
		}
		if tt.reqEmail != tt.userEmail && pwr.UserID.Status != data.Null {
			t.Errorf("%s: PasswordReset.UserID should be nil, but instead is %v", tt.descr, pwr.UserID)
		}

		sentMails := tt.mailer.sentPasswordResetMails
		if tt.sentMailTo == "" {
			if len(sentMails) != 0 {
				t.Errorf("%s: Expected to not send any reset mails, instead sent %d", tt.descr, len(sentMails))
			}
			continue
		}

		if len(sentMails) != 1 {
			t.Errorf("%s: Expected to send 1 reset mail, instead sent %d", tt.descr, len(sentMails))
			continue
		}

		if sentMails[0].to != tt.sentMailTo {
			t.Errorf("%s: Expected to send reset mail to %s, instead sent it to %d", tt.descr, tt.sentMailTo, sentMails[0].to)
		}
		if sentMails[0].token != pwr.Token.Value {
			t.Errorf("%s: Reset mail (%v) and password reset (%v) do not have the same token", tt.descr, sentMails[0].token, pwr.Token)
		}
	}
}
Пример #15
0
func TestResetPasswordHandlerTokenMatchestValidPasswordReset(t *testing.T) {
	pool := newConnPool(t)
	user := &data.User{
		Name:  data.NewString("test"),
		Email: data.NewString("*****@*****.**"),
	}
	SetPassword(user, "password")

	userID, err := data.CreateUser(pool, user)
	if err != nil {
		t.Fatalf("repo.CreateUser returned error: %v", err)
	}

	_, requestIP, _ := net.ParseCIDR("127.0.0.1/32")
	pwr := &data.PasswordReset{
		Token:       data.NewString("0123456789abcdef"),
		Email:       data.NewString("*****@*****.**"),
		UserID:      data.NewInt32(userID),
		RequestTime: data.NewTime(time.Now()),
		RequestIP:   data.NewIPNet(*requestIP),
	}

	err = data.InsertPasswordReset(pool, pwr)
	if err != nil {
		t.Fatalf("repo.CreatePasswordReset returned error: %v", err)
	}

	buf := bytes.NewBufferString(`{"token": "0123456789abcdef", "password": "******"}`)

	req, err := http.NewRequest("POST", "http://example.com/", buf)
	if err != nil {
		t.Fatalf("http.NewRequest returned error: %v", err)
	}

	env := &environment{pool: pool}
	w := httptest.NewRecorder()
	ResetPasswordHandler(w, req, env)

	if w.Code != 200 {
		t.Errorf("Expected HTTP status %d, instead received %d", 200, w.Code)
	}

	user, err = data.SelectUserByPK(pool, userID)
	if err != nil {
		t.Fatalf("repo.GetUser returned error: %v", err)
	}

	if !IsPassword(user, "bigsecret") {
		t.Error("Expected password to be changed but it was not")
	}

	var response struct {
		Name      string `json:"name"`
		SessionID string `json:"sessionID"`
	}

	decoder := json.NewDecoder(w.Body)
	if err := decoder.Decode(&response); err != nil {
		t.Errorf("Unable to decode response: %v", err)
	}
}
Пример #16
0
// This function is a nasty copy and paste of testRepositoryUpdateFeedWithFetchSuccess
// Fix me when refactoring tests
func TestDataUpdateFeedWithFetchSuccessWithoutPublicationTime(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		t.Fatal(err)
	}

	now := time.Now()

	url := "http://bar"
	err = data.InsertSubscription(pool, userID, url)
	if err != nil {
		t.Fatal(err)
	}

	subscriptions, err := data.SelectSubscriptions(pool, userID)
	if err != nil {
		t.Fatal(err)
	}
	if len(subscriptions) != 1 {
		t.Fatalf("Found %d subscriptions, expected 1", len(subscriptions))
	}
	feedID := subscriptions[0].FeedID.Value

	update := &data.ParsedFeed{Name: "baz", Items: []data.ParsedItem{
		{URL: "http://baz/bar", Title: "Baz"},
	}}

	nullString := data.String{Status: data.Null}

	err = data.UpdateFeedWithFetchSuccess(pool, feedID, update, nullString, now)
	if err != nil {
		t.Fatal(err)
	}

	buffer := &bytes.Buffer{}
	err = data.CopyUnreadItemsAsJSONByUserID(pool, buffer, userID)
	if err != nil {
		t.Fatal(err)
	}

	type UnreadItemsFromJSON struct {
		ID int32 `json:id`
	}

	var unreadItems []UnreadItemsFromJSON
	err = json.Unmarshal(buffer.Bytes(), &unreadItems)
	if err != nil {
		t.Fatal(err)
	}
	if len(unreadItems) != 1 {
		t.Fatalf("Found %d unreadItems, expected 1", len(unreadItems))
	}

	// Update again and ensure item does not get created again
	err = data.UpdateFeedWithFetchSuccess(pool, feedID, update, nullString, now)
	if err != nil {
		t.Fatal(err)
	}

	buffer.Reset()
	err = data.CopyUnreadItemsAsJSONByUserID(pool, buffer, userID)
	if err != nil {
		t.Fatal(err)
	}

	err = json.Unmarshal(buffer.Bytes(), &unreadItems)
	if err != nil {
		t.Fatal(err)
	}
	if len(unreadItems) != 1 {
		t.Fatalf("Found %d unreadItems, expected 1", len(unreadItems))
	}
}
Пример #17
0
func TestDataUsersLifeCycle(t *testing.T) {
	pool := newConnPool(t)

	input := &data.User{
		Name:           data.NewString("test"),
		Email:          data.NewString("*****@*****.**"),
		PasswordDigest: data.NewBytes([]byte("digest")),
		PasswordSalt:   data.NewBytes([]byte("salt")),
	}
	userID, err := data.CreateUser(pool, input)
	if err != nil {
		t.Fatal(err)
	}

	user, err := data.SelectUserByName(pool, input.Name.Value)
	if err != nil {
		t.Fatal(err)
	}
	if user.ID.Value != userID {
		t.Errorf("Expected %v, got %v", userID, user.ID)
	}
	if user.Name != input.Name {
		t.Errorf("Expected %v, got %v", input.Name, user.Name)
	}
	if user.Email != input.Email {
		t.Errorf("Expected %v, got %v", input.Email, user.Email)
	}
	if bytes.Compare(user.PasswordDigest.Value, input.PasswordDigest.Value) != 0 {
		t.Errorf("Expected user (%v) and input (%v) PasswordDigest to match, but they did not", user.PasswordDigest, input.PasswordDigest)
	}
	if bytes.Compare(user.PasswordSalt.Value, input.PasswordSalt.Value) != 0 {
		t.Errorf("Expected user (%v), and input (%v) PasswordSalt to match, but they did not", user.PasswordSalt, input.PasswordSalt)
	}

	user, err = data.SelectUserByEmail(pool, input.Email.Value)
	if err != nil {
		t.Fatal(err)
	}
	if user.ID.Value != userID {
		t.Errorf("Expected %v, got %v", userID, user.ID)
	}
	if user.Name != input.Name {
		t.Errorf("Expected %v, got %v", input.Name, user.Name)
	}
	if user.Email != input.Email {
		t.Errorf("Expected %v, got %v", input.Email, user.Email)
	}
	if bytes.Compare(user.PasswordDigest.Value, input.PasswordDigest.Value) != 0 {
		t.Errorf("Expected user (%v) and input (%v) PasswordDigest to match, but they did not", user.PasswordDigest, input.PasswordDigest)
	}
	if bytes.Compare(user.PasswordSalt.Value, input.PasswordSalt.Value) != 0 {
		t.Errorf("Expected user (%v), and input (%v) PasswordSalt to match, but they did not", user.PasswordSalt, input.PasswordSalt)
	}

	user, err = data.SelectUserByPK(pool, userID)
	if err != nil {
		t.Fatal(err)
	}
	if user.ID.Value != userID {
		t.Errorf("Expected %v, got %v", userID, user.ID)
	}
	if user.Name != input.Name {
		t.Errorf("Expected %v, got %v", input.Name, user.Name)
	}
	if user.Email != input.Email {
		t.Errorf("Expected %v, got %v", input.Email, user.Email)
	}
	if bytes.Compare(user.PasswordDigest.Value, input.PasswordDigest.Value) != 0 {
		t.Errorf("Expected user (%v) and input (%v) PasswordDigest to match, but they did not", user.PasswordDigest, input.PasswordDigest)
	}
	if bytes.Compare(user.PasswordSalt.Value, input.PasswordSalt.Value) != 0 {
		t.Errorf("Expected user (%v), and input (%v) PasswordSalt to match, but they did not", user.PasswordSalt, input.PasswordSalt)
	}
}
Пример #18
0
func TestDataFeeds(t *testing.T) {
	pool := newConnPool(t)

	userID, err := data.CreateUser(pool, newUser())
	if err != nil {
		t.Fatal(err)
	}

	now := time.Now()
	fiveMinutesAgo := now.Add(-5 * time.Minute)
	tenMinutesAgo := now.Add(-10 * time.Minute)
	fifteenMinutesAgo := now.Add(-15 * time.Minute)
	update := &data.ParsedFeed{Name: "baz", Items: make([]data.ParsedItem, 0)}

	// Create a feed
	url := "http://bar"
	err = data.InsertSubscription(pool, userID, url)
	if err != nil {
		t.Fatal(err)
	}

	// A new feed has never been fetched -- it should need fetching
	staleFeeds, err := data.GetFeedsUncheckedSince(pool, tenMinutesAgo)
	if err != nil {
		t.Fatal(err)
	}
	if len(staleFeeds) != 1 {
		t.Fatalf("Found %d stale feed, expected 1", len(staleFeeds))
	}

	if staleFeeds[0].URL.Value != url {
		t.Errorf("Expected %v, got %v", url, staleFeeds[0].URL)
	}

	feedID := staleFeeds[0].ID.Value

	nullString := data.String{Status: data.Null}

	// Update feed as of now
	err = data.UpdateFeedWithFetchSuccess(pool, feedID, update, nullString, now)
	if err != nil {
		t.Fatal(err)
	}

	// feed should no longer be stale
	staleFeeds, err = data.GetFeedsUncheckedSince(pool, tenMinutesAgo)
	if err != nil {
		t.Fatal(err)
	}
	if len(staleFeeds) != 0 {
		t.Fatalf("Found %d stale feed, expected 0", len(staleFeeds))
	}

	// Update feed to be old enough to need refresh
	err = data.UpdateFeedWithFetchSuccess(pool, feedID, update, nullString, fifteenMinutesAgo)
	if err != nil {
		t.Fatal(err)
	}

	// It should now need fetching
	staleFeeds, err = data.GetFeedsUncheckedSince(pool, tenMinutesAgo)
	if err != nil {
		t.Fatal(err)
	}
	if len(staleFeeds) != 1 {
		t.Fatalf("Found %d stale feed, expected 1", len(staleFeeds))
	}
	if staleFeeds[0].ID.Value != feedID {
		t.Errorf("Expected %v, got %v", feedID, staleFeeds[0].ID)
	}

	// But update feed with a recent failed fetch
	err = data.UpdateFeedWithFetchFailure(pool, feedID, "something went wrong", fiveMinutesAgo)
	if err != nil {
		t.Fatal(err)
	}

	// feed should no longer be stale
	staleFeeds, err = data.GetFeedsUncheckedSince(pool, tenMinutesAgo)
	if err != nil {
		t.Fatal(err)
	}
	if len(staleFeeds) != 0 {
		t.Fatalf("Found %d stale feed, expected 0", len(staleFeeds))
	}
}