package database import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const testStreamOfflineGrace = 30 * time.Second func TestCountStreak(t *testing.T) { db, err := New("sqlite", "file::memory:?cache=shared") require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, db.Close()) }) err = db.StartStream(testStreamOfflineGrace) require.NoError(t, err) // First time the user registers user, err := db.CountStreak(1, "test") require.NoError(t, err) assert.Equal(t, uint64(1), user.TwitchID) assert.Equal(t, "test", user.Username) assert.Equal(t, uint64(1), user.StreamsCount) assert.Equal(t, uint64(1), user.MaxStreak) assert.Equal(t, uint64(1), user.CurrentStreak) assert.Equal(t, StatusActive, user.StreakStatus) // Register on the same stream should not change anything user, err = db.CountStreak(1, "test") assert.NoError(t, err) assert.Equal(t, uint64(1), user.StreamsCount) assert.Equal(t, uint64(1), user.MaxStreak) assert.Equal(t, uint64(1), user.CurrentStreak) assert.Equal(t, StatusActive, user.StreakStatus) // Interrupt the stream for less than the grace err = db.SetStreamOffline() require.NoError(t, err) err = db.StartStream(testStreamOfflineGrace) require.NoError(t, err) // Streak should still be active err = db.db.First(&user).Error require.NoError(t, err) assert.Equal(t, StatusActive, user.StreakStatus) // Register on the same stream should not change anything user, err = db.CountStreak(1, "test") assert.NoError(t, err) assert.Equal(t, uint64(1), user.StreamsCount) assert.Equal(t, uint64(1), user.MaxStreak) assert.Equal(t, uint64(1), user.CurrentStreak) assert.Equal(t, StatusActive, user.StreakStatus) // Interrupt the stream and start a new one err = db.SetStreamOffline() require.NoError(t, err) time.Sleep(20 * time.Millisecond) err = db.StartStream(10 * time.Millisecond) require.NoError(t, err) // Streak should now be pending err = db.db.First(&user).Error require.NoError(t, err) assert.Equal(t, StatusPending, user.StreakStatus) // Register on the next stream should not break the streak user, err = db.CountStreak(1, "test") assert.NoError(t, err) assert.Equal(t, uint64(2), user.StreamsCount) assert.Equal(t, uint64(2), user.MaxStreak) assert.Equal(t, uint64(2), user.CurrentStreak) assert.Equal(t, StatusActive, user.StreakStatus) // Interrupt the stream and start a new one err = db.SetStreamOffline() require.NoError(t, err) time.Sleep(20 * time.Millisecond) err = db.StartStream(10 * time.Millisecond) require.NoError(t, err) // Streak should now be pending err = db.db.First(&user).Error require.NoError(t, err) assert.Equal(t, StatusPending, user.StreakStatus) // Interrupt the stream and start a new one (twice) err = db.SetStreamOffline() require.NoError(t, err) time.Sleep(20 * time.Millisecond) err = db.StartStream(10 * time.Millisecond) require.NoError(t, err) // Streak should now be broken err = db.db.First(&user).Error require.NoError(t, err) assert.Equal(t, StatusBroken, user.StreakStatus) // Register with one stream left out should break the streak user, err = db.CountStreak(1, "test") assert.NoError(t, err) assert.Equal(t, uint64(3), user.StreamsCount) assert.Equal(t, uint64(2), user.MaxStreak) assert.Equal(t, uint64(1), user.CurrentStreak) assert.Equal(t, StatusActive, user.StreakStatus) } func TestMetaTimestore(t *testing.T) { db, err := New("sqlite", "file::memory:?cache=shared") require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, db.Close()) }) parsed, err := db.getTimeFromMeta(db.db, "test") assert.NoError(t, err) assert.True(t, defaultMetaTime.Equal(parsed)) now := time.Now() err = db.storeTimeToMeta(db.db, "test", now) assert.NoError(t, err) var meta StreakMeta err = db.db.First(&meta, "name = ?", "test").Error assert.NoError(t, err) assert.Equal(t, "test", meta.Name) assert.Equal(t, now.Format(time.RFC3339Nano), meta.Value) parsed, err = db.getTimeFromMeta(db.db, "test") assert.NoError(t, err) assert.True(t, now.Equal(parsed)) } func TestStreamOffline(t *testing.T) { db, err := New("sqlite", "file::memory:?cache=shared") require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, db.Close()) }) parsed, err := db.getTimeFromMeta(db.db, "stream_offline") assert.NoError(t, err) assert.True(t, defaultMetaTime.Equal(parsed)) err = db.SetStreamOffline() require.NoError(t, err) parsed, err = db.getTimeFromMeta(db.db, "stream_offline") assert.NoError(t, err) assert.Less(t, time.Since(parsed), testStreamOfflineGrace) } func TestStreamOnline(t *testing.T) { db, err := New("sqlite", "file::memory:?cache=shared") require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, db.Close()) }) parsed, err := db.getTimeFromMeta(db.db, "stream_online") assert.NoError(t, err) assert.True(t, defaultMetaTime.Equal(parsed)) err = db.StartStream(testStreamOfflineGrace) require.NoError(t, err) parsed, err = db.getTimeFromMeta(db.db, "stream_online") assert.NoError(t, err) assert.Less(t, time.Since(parsed), testStreamOfflineGrace) }