plugin_repo_integration_test.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. //go:build integration
  2. package repository
  3. import (
  4. "context"
  5. "errors"
  6. "strings"
  7. "testing"
  8. "time"
  9. "github.com/Wei-Shaw/sub2api/internal/service"
  10. "github.com/stretchr/testify/require"
  11. )
  12. func TestPluginRepositoryLifecycleIsAtomicAndOptimistic(t *testing.T) {
  13. ctx := context.Background()
  14. repo := &pluginRepository{db: integrationDB}
  15. pluginKey := "local.test.repository-" + strings.ToLower(time.Now().Format("150405.000000000"))
  16. defer func() {
  17. _, _ = integrationDB.ExecContext(ctx, `DELETE FROM sub2api_plugin_installations WHERE plugin_key = $1`, pluginKey)
  18. }()
  19. manifest := service.PluginManifest{SchemaVersion: 1, ID: pluginKey, Name: "测试插件", Version: "1.0.0"}
  20. first := &service.PluginInstallation{
  21. PluginKey: pluginKey, Name: "测试插件", Version: "1.0.0", Manifest: manifest,
  22. ArtifactData: []byte("first-package"), ArtifactPath: "/tmp/first.s2plugin",
  23. InstallPath: "/tmp/first", BinaryPath: "/tmp/first/plugin",
  24. BinarySHA256: strings.Repeat("a", 64), SignatureStatus: service.PluginSignatureTrusted,
  25. State: service.PluginStateDisabled,
  26. }
  27. bindings := []service.PluginBinding{{
  28. Capability: service.PluginCapabilityOpenAIOAuthOutbound,
  29. Platform: service.PlatformOpenAI, AccountType: service.AccountTypeOAuth,
  30. RolloutPercent: 100,
  31. }}
  32. installed, err := repo.Install(ctx, first, bindings)
  33. require.NoError(t, err)
  34. artifact, err := repo.GetArtifact(ctx, installed.ID)
  35. require.NoError(t, err)
  36. require.Equal(t, first.ArtifactData, artifact)
  37. require.NoError(t, repo.BeginEnable(ctx, installed.ID, first.BinarySHA256, service.PluginStateDisabled))
  38. bindings[0].Enabled = true
  39. now := time.Now()
  40. require.NoError(t, repo.UpdateBindingsAndState(
  41. ctx, installed.ID, bindings, service.PluginStateEnabled, "", &now,
  42. service.PluginStateStarting, first.BinarySHA256,
  43. ))
  44. second := *first
  45. second.Version = "1.1.0"
  46. second.Manifest.Version = second.Version
  47. second.BinarySHA256 = strings.Repeat("b", 64)
  48. second.ArtifactData = []byte("second-package")
  49. _, err = repo.Install(ctx, &second, bindings)
  50. require.ErrorIs(t, err, service.ErrPluginStateChanged)
  51. bindings[0].Enabled = false
  52. require.NoError(t, repo.UpdateBindingsAndState(
  53. ctx, installed.ID, bindings, service.PluginStateDisabled, "", nil, "", first.BinarySHA256,
  54. ))
  55. replaced, err := repo.Install(ctx, &second, bindings)
  56. require.NoError(t, err)
  57. require.Equal(t, installed.ID, replaced.ID)
  58. err = repo.Delete(ctx, replaced.ID, first.BinarySHA256)
  59. require.True(t, errors.Is(err, service.ErrPluginStateChanged))
  60. require.NoError(t, repo.Delete(ctx, replaced.ID, second.BinarySHA256))
  61. }