forked from SunRed/discord-tweeter
* Update golang version to 1.24 * Update multiarch Dockerfile to be more ISA agnostic * Refactor existing code and properly structure project into modules * Get rid of global variables except where necessary (go:embed) * Add default values to Config * Add webserver with templates to finally correctly serve videos and gifs * Add tiny caching library to decrease api load and improve latency * Improve Webhook data preparation by filtering out redundant links from the tweet text and properly attaching videos and gifs in separate webhook request by utilising new webserver * Improve tests for filter function * Improve bake definition for easier CI integration
145 lines
2.9 KiB
Go
145 lines
2.9 KiB
Go
package cache
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestCacheBasicOperations(t *testing.T) {
|
|
cache := New[string, int]()
|
|
|
|
// Test Set and Get
|
|
cache.Set("key1", 42, 10*time.Second)
|
|
value, exists := cache.Get("key1")
|
|
if !exists {
|
|
t.Errorf("expected key to exist")
|
|
}
|
|
if value != 42 {
|
|
t.Errorf("expected value 42, got %v", value)
|
|
}
|
|
|
|
// Test non-existent key
|
|
value, exists = cache.Get("nonexistent")
|
|
if exists {
|
|
t.Errorf("expected key to not exist")
|
|
}
|
|
if value != 0 {
|
|
t.Errorf("expected zero value, got %v", value)
|
|
}
|
|
}
|
|
|
|
func TestCacheExpiration(t *testing.T) {
|
|
cache := New[string, int]()
|
|
|
|
// Set value with very short TTL
|
|
cache.Set("short-lived", 42, 100*time.Millisecond)
|
|
|
|
// Verify initial existence
|
|
value, exists := cache.Get("short-lived")
|
|
if !exists {
|
|
t.Errorf("expected key to exist initially")
|
|
}
|
|
if value != 42 {
|
|
t.Errorf("expected value 42, got %v", value)
|
|
}
|
|
|
|
// Wait for expiration
|
|
time.Sleep(150 * time.Millisecond)
|
|
|
|
// Verify expiration
|
|
value, exists = cache.Get("short-lived")
|
|
if exists {
|
|
t.Errorf("expected key to have expired")
|
|
}
|
|
if value != 0 {
|
|
t.Errorf("expected zero value, got %v", value)
|
|
}
|
|
}
|
|
|
|
func TestCacheConcurrentAccess(t *testing.T) {
|
|
cache := New[string, int]()
|
|
|
|
// Start multiple writers
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(1)
|
|
go func(i int) {
|
|
defer wg.Done()
|
|
cache.Set(fmt.Sprintf("key%d", i), i*2, 10*time.Second)
|
|
}(i)
|
|
}
|
|
|
|
// Start multiple readers
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(1)
|
|
go func(i int) {
|
|
defer wg.Done()
|
|
cache.Get(fmt.Sprintf("key%d", i))
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
// Verify all values were written correctly
|
|
for i := 0; i < 10; i++ {
|
|
value, exists := cache.Get(fmt.Sprintf("key%d", i))
|
|
if !exists {
|
|
t.Errorf("expected key%d to exist", i)
|
|
}
|
|
if value != (i * 2) {
|
|
t.Errorf("expected value %d for key%d, got %d", i*2, i, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCacheGenericTypes(t *testing.T) {
|
|
// Test with string values
|
|
strCache := New[int, string]()
|
|
strCache.Set(1, "hello", 10*time.Second)
|
|
value, exists := strCache.Get(1)
|
|
if !exists {
|
|
t.Errorf("expected key to exist")
|
|
}
|
|
if value != "hello" {
|
|
t.Errorf("expected value hello, got %v", value)
|
|
}
|
|
|
|
// Test with struct values
|
|
type Person struct {
|
|
Name string
|
|
Age int
|
|
}
|
|
personCache := New[string, Person]()
|
|
personCache.Set("john", Person{"John", 30}, 10*time.Second)
|
|
person, exists := personCache.Get("john")
|
|
if !exists {
|
|
t.Errorf("expected key to exist")
|
|
}
|
|
expected := Person{"John", 30}
|
|
if !reflect.DeepEqual(person, expected) {
|
|
t.Errorf("expected %+v, got %+v", expected, person)
|
|
}
|
|
}
|
|
|
|
func TestCacheDelete(t *testing.T) {
|
|
cache := New[string, int]()
|
|
|
|
// Set and verify
|
|
cache.Set("key1", 42, 10*time.Second)
|
|
_, exists := cache.Get("key1")
|
|
if !exists {
|
|
t.Errorf("expected key to exist")
|
|
}
|
|
|
|
// Delete
|
|
cache.Delete("key1")
|
|
|
|
// Verify deletion
|
|
_, exists = cache.Get("key1")
|
|
if exists {
|
|
t.Errorf("expected key to not exist after deletion")
|
|
}
|
|
}
|