|
| 1 | +package curd |
| 2 | + |
| 3 | +import ( |
| 4 | + "strings" |
| 5 | + "testing" |
| 6 | + |
| 7 | + "github.com/google/uuid" |
| 8 | + "github.com/langgenius/dify-plugin-daemon/internal/db" |
| 9 | + "github.com/langgenius/dify-plugin-daemon/internal/types/app" |
| 10 | + "github.com/langgenius/dify-plugin-daemon/internal/types/models" |
| 11 | + "github.com/langgenius/dify-plugin-daemon/pkg/entities/plugin_entities" |
| 12 | + "github.com/langgenius/dify-plugin-daemon/pkg/utils/cache" |
| 13 | + "github.com/langgenius/dify-plugin-daemon/pkg/utils/cache/helper" |
| 14 | + "github.com/stretchr/testify/require" |
| 15 | +) |
| 16 | + |
| 17 | +// Test that InstallPlugin invalidates PluginInstallation cache key so that |
| 18 | +// subsequent reads fall back to DB instead of returning stale data. |
| 19 | +func TestInstallPlugin_InvalidateInstallationCache(t *testing.T) { |
| 20 | + // Init Redis |
| 21 | + require.NoError(t, cache.InitRedisClient("127.0.0.1:6379", "", "difyai123456", false, 0, nil)) |
| 22 | + t.Cleanup(func() { _ = cache.Close() }) |
| 23 | + |
| 24 | + // Init DB |
| 25 | + cfg := &app.Config{ |
| 26 | + DBType: app.DB_TYPE_POSTGRESQL, |
| 27 | + DBUsername: "postgres", |
| 28 | + DBPassword: "difyai123456", |
| 29 | + DBHost: "localhost", |
| 30 | + DBPort: 5432, |
| 31 | + DBDatabase: "dify_plugin_daemon", |
| 32 | + DBSslMode: "disable", |
| 33 | + } |
| 34 | + cfg.SetDefault() |
| 35 | + db.Init(cfg) |
| 36 | + t.Cleanup(db.Close) |
| 37 | + |
| 38 | + tenantID := uuid.NewString() |
| 39 | + pluginName := "cache_invalidate_" + uuid.NewString() |
| 40 | + checksum := strings.ReplaceAll(uuid.NewString(), "-", "") |
| 41 | + if len(checksum) > 32 { |
| 42 | + checksum = checksum[:32] |
| 43 | + } |
| 44 | + |
| 45 | + identifier, err := plugin_entities.NewPluginUniqueIdentifier("tester/" + pluginName + ":1.0.0.0@" + checksum) |
| 46 | + require.NoError(t, err) |
| 47 | + pluginID := identifier.PluginID() |
| 48 | + |
| 49 | + // Seed a stale cache value for the installation key |
| 50 | + key := helper.PluginInstallationCacheKey(pluginID, tenantID) |
| 51 | + require.NoError(t, cache.AutoSet[models.PluginInstallation](key, models.PluginInstallation{ |
| 52 | + Model: models.Model{ID: "OLD"}, |
| 53 | + PluginID: pluginID, |
| 54 | + PluginUniqueIdentifier: identifier.String(), |
| 55 | + TenantID: tenantID, |
| 56 | + RuntimeType: string(plugin_entities.PLUGIN_RUNTIME_TYPE_LOCAL), |
| 57 | + })) |
| 58 | + // Perform install which should invalidate the cache key |
| 59 | + _, _, err = InstallPlugin( |
| 60 | + tenantID, |
| 61 | + identifier, |
| 62 | + plugin_entities.PLUGIN_RUNTIME_TYPE_LOCAL, |
| 63 | + &plugin_entities.PluginDeclaration{}, |
| 64 | + "unittest", |
| 65 | + map[string]any{"from": "test"}, |
| 66 | + ) |
| 67 | + require.NoError(t, err) |
| 68 | + |
| 69 | + // Read using AutoGetWithGetter — should miss cache, call getter (DB), then set fresh cache |
| 70 | + inst, err := cache.AutoGetWithGetter(key, func() (*models.PluginInstallation, error) { |
| 71 | + v, e := db.GetOne[models.PluginInstallation]( |
| 72 | + db.Equal("plugin_id", pluginID), |
| 73 | + db.Equal("tenant_id", tenantID), |
| 74 | + ) |
| 75 | + if e != nil { |
| 76 | + return nil, e |
| 77 | + } |
| 78 | + return &v, nil |
| 79 | + }) |
| 80 | + require.NoError(t, err) |
| 81 | + require.NotNil(t, inst) |
| 82 | + require.NotEqual(t, "OLD", inst.ID, "cache should have been invalidated and refetched from DB") |
| 83 | +} |
0 commit comments