Пример #1
0
// Ensure that an account can retrieve all associated users.
func TestAccountUsers(t *testing.T) {
	withDB(func(db *DB) {
		// Create two accounts.
		db.Do(func(tx *Tx) error {
			a1 := &Account{}
			assert.NoError(t, tx.CreateAccount(a1))
			a2 := &Account{}
			assert.NoError(t, tx.CreateAccount(a2))
			return nil
		})

		// Add users to first account.
		db.Do(func(tx *Tx) error {
			a1, _ := tx.Account(1)
			assert.NoError(t, a1.CreateUser(&User{Email: "*****@*****.**", Password: "******"}))
			assert.NoError(t, a1.CreateUser(&User{Email: "*****@*****.**", Password: "******"}))
			return nil
		})

		// Add users to second account.
		db.Do(func(tx *Tx) error {
			a2, _ := tx.Account(2)
			assert.NoError(t, a2.CreateUser(&User{Email: "*****@*****.**", Password: "******"}))
			return nil
		})

		// Check first account users.
		db.With(func(tx *Tx) error {
			a1, _ := tx.Account(1)
			users, err := a1.Users()
			if assert.NoError(t, err) && assert.Equal(t, len(users), 2) {
				assert.Equal(t, users[0].Tx, tx)
				assert.Equal(t, users[0].ID(), 2)
				assert.Equal(t, users[0].AccountID, 1)
				assert.Equal(t, users[0].Email, "*****@*****.**")

				assert.Equal(t, users[1].Tx, tx)
				assert.Equal(t, users[1].ID(), 1)
				assert.Equal(t, users[1].AccountID, 1)
				assert.Equal(t, users[1].Email, "*****@*****.**")
			}
			return nil
		})

		// Check second account users.
		db.With(func(tx *Tx) error {
			a2, _ := tx.Account(2)
			users, err := a2.Users()
			if assert.NoError(t, err) && assert.Equal(t, len(users), 1) {
				assert.Equal(t, users[0].Tx, tx)
				assert.Equal(t, users[0].ID(), 3)
				assert.Equal(t, users[0].AccountID, 2)
				assert.Equal(t, users[0].Email, "*****@*****.**")
			}
			return nil
		})
	})
}
Пример #2
0
// Ensure that an account can generate a random API key.
func TestAccountGenerateAPIKey(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a := &Account{}
			assert.NoError(t, tx.CreateAccount(a))

			// Check for an API key.
			assert.Equal(t, len(a.APIKey), 36)

			// Lookup account by API key.
			a2, err := tx.AccountByAPIKey(a.APIKey)
			assert.NoError(t, err)
			assert.Equal(t, a2.ID(), 1)

			// Regenerate key.
			apiKey := a.APIKey
			assert.NoError(t, a.GenerateAPIKey())

			// Make sure it's not the same as before.
			assert.NotEqual(t, a.APIKey, apiKey)

			// Make sure we can lookup by the new key and not the old.
			a3, err := tx.AccountByAPIKey(a.APIKey)
			assert.NoError(t, err)
			assert.Equal(t, a3.ID(), 1)

			a4, err := tx.AccountByAPIKey(apiKey)
			assert.Equal(t, err, ErrAccountNotFound)
			assert.Nil(t, a4)

			return nil
		})
	})
}
Пример #3
0
// Ensure that the database can retrieve a user by email.
func TestDBUserByEmail(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			// Add account and users.
			a := &Account{}
			assert.NoError(t, tx.CreateAccount(a))
			assert.NoError(t, a.CreateUser(&User{Email: "*****@*****.**", Password: "******"}))
			assert.NoError(t, a.CreateUser(&User{Email: "*****@*****.**", Password: "******"}))

			// Find user.
			u, _ := tx.UserByEmail("*****@*****.**")
			assert.Equal(t, u.ID(), 2)

			// Delete user and find.
			assert.NoError(t, u.Delete())
			_, err := tx.UserByEmail("*****@*****.**")
			assert.Equal(t, err, ErrUserNotFound)

			// Re-add and find again.
			assert.NoError(t, a.CreateUser(&User{Email: "*****@*****.**", Password: "******"}))
			u, _ = tx.UserByEmail("*****@*****.**")
			assert.Equal(t, u.ID(), 3)
			return nil
		})
	})
}
Пример #4
0
// Ensure that an account can retrieve a list of unique resources.
func TestAccountResources(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a1, a2, a3 := &Account{}, &Account{}, &Account{}
			tx.CreateAccount(a1)
			tx.CreateAccount(a2)
			tx.CreateAccount(a3)
			a1.Reset()
			a2.Reset()
			a3.Reset()

			// Add some events.
			assert.NoError(t, a1.Track(newTestEvent("2000-01-01T00:00:00Z", "john", "DEV0", "web", "/", "view", nil)))
			assert.NoError(t, a1.Track(newTestEvent("2000-01-01T00:00:01Z", "john", "DEV1", "web", "/signup", "view", nil)))
			assert.NoError(t, a1.Track(newTestEvent("2000-01-01T00:00:02Z", "susy", "DEV2", "web", "/cancel", "view", nil)))
			assert.NoError(t, a2.Track(newTestEvent("2000-01-01T00:00:02Z", "john", "DEV2", "web", "/blah", "view", nil)))

			// Retrieve resources.
			resources, err := a1.Resources()
			assert.NoError(t, err)
			assert.Equal(t, resources, []string{"/", "/cancel", "/signup"})

			resources, err = a2.Resources()
			assert.NoError(t, err)
			assert.Equal(t, resources, []string{"/blah"})

			resources, err = a3.Resources()
			assert.NoError(t, err)
			assert.Equal(t, resources, []string{})
			return nil
		})
	})
}
Пример #5
0
// Ensure that an account can retrieve all associated funnels.
func TestAccountFunnels(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a1 := &Account{}
			a2 := &Account{}
			assert.NoError(t, tx.CreateAccount(a1))
			assert.NoError(t, tx.CreateAccount(a2))

			// Add funnels to first account.
			assert.NoError(t, a1.CreateFunnel(&Funnel{Name: "Funnel B", Steps: []*FunnelStep{{Condition: "action == 'foo'"}}}))
			assert.NoError(t, a1.CreateFunnel(&Funnel{Name: "Funnel A", Steps: []*FunnelStep{{Condition: "action == 'foo'"}}}))

			// Add funnels to second account.
			assert.NoError(t, a2.CreateFunnel(&Funnel{Name: "Funnel C", Steps: []*FunnelStep{{Condition: "action == 'foo'"}}}))
			return nil
		})

		// Check first account.
		db.With(func(tx *Tx) error {
			a, _ := tx.Account(1)
			funnels, err := a.Funnels()
			if assert.NoError(t, err) && assert.Equal(t, len(funnels), 2) {
				assert.Equal(t, funnels[0].Tx, tx)
				assert.Equal(t, funnels[0].ID(), 2)
				assert.Equal(t, funnels[0].AccountID, 1)
				assert.Equal(t, funnels[0].Name, "Funnel A")

				assert.Equal(t, funnels[1].Tx, tx)
				assert.Equal(t, funnels[1].ID(), 1)
				assert.Equal(t, funnels[1].AccountID, 1)
				assert.Equal(t, funnels[1].Name, "Funnel B")
			}

			// Make sure we can only get a1 funnels.
			f, err := a.Funnel(1)
			assert.NoError(t, err)
			assert.NotNil(t, f)
			f, err = a.Funnel(3)
			assert.Equal(t, err, ErrFunnelNotFound)
			assert.Nil(t, f)

			return nil
		})

		// Check second account's funnels.
		db.With(func(tx *Tx) error {
			a, _ := tx.Account(2)
			funnels, err := a.Funnels()
			if assert.NoError(t, err) && assert.Equal(t, len(funnels), 1) {
				assert.Equal(t, funnels[0].Tx, tx)
				assert.Equal(t, funnels[0].ID(), 3)
				assert.Equal(t, funnels[0].AccountID, 2)
				assert.Equal(t, funnels[0].Name, "Funnel C")
			}
			return nil
		})
	})
}
Пример #6
0
// Ensure that retrieving a missing account returns an error.
func TestDBAccountNotFound(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a, err := tx.Account(1)
			assert.Equal(t, err, ErrAccountNotFound)
			assert.Nil(t, a)
			return nil
		})
	})
}
Пример #7
0
// Ensure that creating a funnel without a name returns an error.
func TestFunnelCreateMissingName(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a := &Account{}
			assert.NoError(t, tx.CreateAccount(a))
			assert.Equal(t, a.CreateFunnel(&Funnel{Steps: []*FunnelStep{{Condition: "action == 'foo'"}}}), ErrFunnelNameRequired)
			return nil
		})
	})
}
Пример #8
0
// Ensure that retrieving a missing user returns an error.
func TestDBUserNotFound(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			u, err := tx.User(1)
			assert.Equal(t, err, ErrUserNotFound)
			assert.Nil(t, u)
			return nil
		})
	})
}
Пример #9
0
// Ensure that creating a funnel without steps returns an error.
func TestFunnelCreateMissingSteps(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a := &Account{}
			assert.NoError(t, tx.CreateAccount(a))
			assert.Equal(t, a.CreateFunnel(&Funnel{Name: "Funnel Y"}), ErrFunnelStepsRequired)
			return nil
		})
	})
}
Пример #10
0
// Ensure that an account can be deleted.
func TestAccountDelete(t *testing.T) {
	withDB(func(db *DB) {
		// Create account.
		err := db.Do(func(tx *Tx) error {
			return tx.CreateAccount(&Account{})
		})
		assert.NoError(t, err)

		// Retrieve and delete account.
		err = db.Do(func(tx *Tx) error {
			a, _ := tx.Account(1)
			return a.Delete()
		})
		assert.NoError(t, err)

		// Retrieve the account again.
		err = db.With(func(tx *Tx) error {
			_, err := tx.Account(1)
			return err
		})
		assert.Equal(t, err, ErrAccountNotFound)
	})
}
Пример #11
0
// Ensure that a funnel query can be executed.
func TestFunnelQuery(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a := &Account{}
			f := &Funnel{
				Name: "FUN",
				Steps: []*FunnelStep{
					{Condition: "resource == '/home'"},
					{Condition: "resource == '/signup'"},
					{Condition: "resource == '/checkout'"},
				},
			}
			assert.NoError(t, tx.CreateAccount(a))
			assert.NoError(t, a.CreateFunnel(f))
			a.Reset()

			// Track: "john" completes the whole checkout.
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:00:00Z", "john", "", "web", "/home", "view", nil)))
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:00:30Z", "john", "", "web", "/about", "view", nil)))
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:01:00Z", "john", "", "web", "/signup", "view", nil)))
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:02:00Z", "john", "", "web", "/checkout", "view", nil)))

			// Track: "susy" only completes the first step.
			assert.NoError(t, a.Track(newTestEvent("2000-01-02T00:00:00Z", "susy", "", "web", "/home", "view", nil)))

			// Track: "jim" completes the whole checkout but not in one session.
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:00:00Z", "jim", "", "web", "/home", "view", nil)))
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:01:00Z", "jim", "", "web", "/signup", "view", nil)))
			assert.NoError(t, a.Track(newTestEvent("2000-01-10T00:00:00Z", "jim", "", "web", "/checkout", "view", nil)))

			// Execute funnel query.
			results, err := f.Query()
			assert.NoError(t, err)
			if assert.NotNil(t, results) && assert.Equal(t, len(results.Steps), 3) {
				assert.Equal(t, results.Name, "FUN")
				assert.Equal(t, results.Steps[0].Condition, "resource == '/home'")
				assert.Equal(t, results.Steps[0].Count, 3) // john, susy, jim
				assert.Equal(t, results.Steps[1].Condition, "resource == '/signup'")
				assert.Equal(t, results.Steps[1].Count, 2) // john, jim
				assert.Equal(t, results.Steps[2].Condition, "resource == '/checkout'")
				assert.Equal(t, results.Steps[2].Count, 1) // john
			}

			return nil
		})
	})
}
Пример #12
0
// Ensure that a funnel can be deleted.
func TestFunnelDelete(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			// Create account and funnel.
			a := &Account{}
			assert.NoError(t, tx.CreateAccount(a))
			f := &Funnel{Name: "Funnel Y", Steps: []*FunnelStep{{Condition: "action == 'foo'"}}}
			assert.NoError(t, a.CreateFunnel(f))

			// Delete the funnel.
			assert.NoError(t, f.Delete())

			// Retrieve the funnel again.
			_, err := tx.Funnel(1)
			assert.Equal(t, err, ErrFunnelNotFound)
			return nil
		})
	})
}
Пример #13
0
// Ensure that the database can create an account.
func TestDBCreateAccount(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			// Create an account.
			a := &Account{}
			err := tx.CreateAccount(a)
			assert.NoError(t, err)
			assert.Equal(t, tx, a.Tx)
			assert.Equal(t, a.ID(), 1)

			// Retrieve the account.
			a2, err := tx.Account(1)
			if assert.NoError(t, err) && assert.NotNil(t, a2) {
				assert.Equal(t, tx, a2.Tx)
				assert.Equal(t, a2.ID(), 1)
			}
			assert.True(t, a != a2)
			return nil
		})
	})
}
Пример #14
0
// Ensure that a funnel can update itself.
func TestFunnelUpdate(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a := &Account{}
			assert.NoError(t, tx.CreateAccount(a))
			f := &Funnel{Name: "Funnel Y", Steps: []*FunnelStep{{Condition: "action == 'foo'"}}}
			assert.NoError(t, a.CreateFunnel(f))

			// Update the funnel.
			f.Name = "Funnel Z"
			f.Save()

			// Retrieve the funnel.
			f2, err := tx.Funnel(1)
			if assert.NoError(t, err) && assert.NotNil(t, f2) {
				assert.Equal(t, f2.Name, "Funnel Z")
			}
			return nil
		})
	})
}
Пример #15
0
// Ensure that an account can track events and insert them into Sky.
func TestAccountTrack(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			a := &Account{}
			tx.CreateAccount(a)
			a.Reset()

			// Add some events.
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:00:00Z", "john", "DEV0", "web", "/", "view", nil)))
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:00:05Z", "john", "DEV1", "web", "/signup", "view", nil)))
			assert.NoError(t, a.Track(newTestEvent("2000-01-01T00:00:00Z", "susy", "DEV2", "web", "/cancel", "click", nil)))

			// Verify "john" events.
			events, err := a.Events("@john")
			assert.NoError(t, err)
			if assert.Equal(t, len(events), 2) {
				assert.Equal(t, events[0].Timestamp, mustParseTime("2000-01-01T00:00:00Z"))
				assert.Equal(t, events[0].Channel, "web")
				assert.Equal(t, events[0].Resource, "/")
				assert.Equal(t, events[0].Action, "view")

				assert.Equal(t, events[1].Timestamp, mustParseTime("2000-01-01T00:00:05Z"))
				assert.Equal(t, events[1].Channel, "web")
				assert.Equal(t, events[1].Resource, "/signup")
				assert.Equal(t, events[1].Action, "view")
			}

			// Verify "susy" events.
			events, err = a.Events("@susy")
			assert.NoError(t, err)
			if assert.Equal(t, len(events), 1) {
				assert.Equal(t, events[0].Timestamp, mustParseTime("2000-01-01T00:00:00Z"))
				assert.Equal(t, events[0].Channel, "web")
				assert.Equal(t, events[0].Resource, "/cancel")
				assert.Equal(t, events[0].Action, "click")
			}
			return nil
		})
	})
}
Пример #16
0
// Ensure that an account can create a funnel.
func TestFunnelCreate(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			// Create an account and funnel.
			a := &Account{}
			assert.NoError(t, tx.CreateAccount(a))
			f := &Funnel{Name: "Funnel Y", Steps: []*FunnelStep{{Condition: "action == 'foo'"}}}
			assert.NoError(t, a.CreateFunnel(f))
			assert.Equal(t, f.ID(), 1)

			// Retrieve the funnel.
			f2, err := tx.Funnel(1)
			if assert.NoError(t, err) && assert.NotNil(t, f2) {
				assert.Equal(t, f2.Tx, tx)
				assert.Equal(t, f2.ID(), 1)
				assert.Equal(t, f2.AccountID, 1)
				assert.Equal(t, f2.Name, "Funnel Y")
			}
			return nil
		})
	})
}
Пример #17
0
// Ensure that the database can return all accounts.
func TestDBAccounts(t *testing.T) {
	withDB(func(db *DB) {
		db.Do(func(tx *Tx) error {
			tx.CreateAccount(&Account{})
			tx.CreateAccount(&Account{})
			tx.CreateAccount(&Account{})

			// Retrieve the accounts.
			accounts, err := tx.Accounts()
			if assert.NoError(t, err) && assert.Equal(t, len(accounts), 3) {
				assert.Equal(t, accounts[0].Tx, tx)
				assert.Equal(t, accounts[0].ID(), 1)

				assert.Equal(t, accounts[1].Tx, tx)
				assert.Equal(t, accounts[1].ID(), 2)

				assert.Equal(t, accounts[2].Tx, tx)
				assert.Equal(t, accounts[2].ID(), 3)
			}
			return nil
		})
	})
}