@@ -4,9 +4,10 @@ import (
4
4
"bytes"
5
5
"errors"
6
6
"io"
7
+ "os"
8
+ "path/filepath"
7
9
"testing"
8
10
9
- "github.com/stretchr/testify/assert"
10
11
"github.com/stretchr/testify/require"
11
12
12
13
"github.com/mozilla-ai/mcpd/v2/internal/cmd"
@@ -72,7 +73,7 @@ type fakeBuilder struct {
72
73
err error
73
74
}
74
75
75
- func (f * fakeBuilder ) Build () (registry.PackageProvider , error ) {
76
+ func (f * fakeBuilder ) Build (_ ... options. BuildOption ) (registry.PackageProvider , error ) {
76
77
return f .reg , f .err
77
78
}
78
79
@@ -115,10 +116,10 @@ func TestAddCmd_Success(t *testing.T) {
115
116
116
117
err = cmdObj .Execute ()
117
118
require .NoError (t , err )
118
- assert .Contains (t , buf .String (), "✓ Added server" )
119
- assert .True (t , cfg .addCalled )
120
- assert .Equal (t , "server1" , cfg .entry .Name )
121
- assert .Equal (t , "uvx::mcp-server-1@1.2.3" , cfg .entry .Package )
119
+ require .Contains (t , buf .String (), "✓ Added server" )
120
+ require .True (t , cfg .addCalled )
121
+ require .Equal (t , "server1" , cfg .entry .Name )
122
+ require .Equal (t , "uvx::mcp-server-1@1.2.3" , cfg .entry .Package )
122
123
}
123
124
124
125
func TestAddCmd_MissingArgs (t * testing.T ) {
@@ -132,7 +133,7 @@ func TestAddCmd_MissingArgs(t *testing.T) {
132
133
133
134
err = cmdObj .Execute ()
134
135
require .Error (t , err )
135
- assert .Contains (t , err .Error (), "server name is required" )
136
+ require .Contains (t , err .Error (), "server name is required" )
136
137
}
137
138
138
139
func TestAddCmd_RegistryFails (t * testing.T ) {
@@ -145,7 +146,7 @@ func TestAddCmd_RegistryFails(t *testing.T) {
145
146
cmdObj .SetArgs ([]string {"server1" })
146
147
err = cmdObj .Execute ()
147
148
require .Error (t , err )
148
- assert .Contains (t , err .Error (), "registry error" )
149
+ require .Contains (t , err .Error (), "registry error" )
149
150
}
150
151
151
152
func TestAddCmd_BasicServerAdd (t * testing.T ) {
@@ -187,14 +188,14 @@ func TestAddCmd_BasicServerAdd(t *testing.T) {
187
188
188
189
// Output assertions
189
190
outStr := o .String ()
190
- assert .Contains (t , outStr , "✓ Added server 'testserver'" )
191
- assert .Contains (t , outStr , "version: latest" )
191
+ require .Contains (t , outStr , "✓ Added server 'testserver'" )
192
+ require .Contains (t , outStr , "version: latest" )
192
193
193
194
// Config assertions
194
195
require .True (t , cfg .addCalled )
195
- assert .Equal (t , "testserver" , cfg .entry .Name )
196
- assert .Equal (t , "uvx::mcp-server-testserver@latest" , cfg .entry .Package )
197
- assert .ElementsMatch (t , []string {"tool1" , "tool2" , "tool3" }, cfg .entry .Tools )
196
+ require .Equal (t , "testserver" , cfg .entry .Name )
197
+ require .Equal (t , "uvx::mcp-server-testserver@latest" , cfg .entry .Package )
198
+ require .ElementsMatch (t , []string {"tool1" , "tool2" , "tool3" }, cfg .entry .Tools )
198
199
}
199
200
200
201
func TestAddCmd_ServerWithArguments (t * testing.T ) {
@@ -396,11 +397,11 @@ func TestAddCmd_ServerWithArguments(t *testing.T) {
396
397
397
398
// Verify config was called with correct arguments
398
399
require .True (t , cfg .addCalled )
399
- assert .Equal (t , tc .pkg .ID , cfg .entry .Name )
400
- assert .ElementsMatch (t , tc .expectedRequiredEnvs , cfg .entry .RequiredEnvVars )
401
- assert .ElementsMatch (t , tc .expectedRequiredPositionals , cfg .entry .RequiredPositionalArgs )
402
- assert .ElementsMatch (t , tc .expectedRequiredValues , cfg .entry .RequiredValueArgs )
403
- assert .ElementsMatch (t , tc .expectedRequiredBools , cfg .entry .RequiredBoolArgs )
400
+ require .Equal (t , tc .pkg .ID , cfg .entry .Name )
401
+ require .ElementsMatch (t , tc .expectedRequiredEnvs , cfg .entry .RequiredEnvVars )
402
+ require .ElementsMatch (t , tc .expectedRequiredPositionals , cfg .entry .RequiredPositionalArgs )
403
+ require .ElementsMatch (t , tc .expectedRequiredValues , cfg .entry .RequiredValueArgs )
404
+ require .ElementsMatch (t , tc .expectedRequiredBools , cfg .entry .RequiredBoolArgs )
404
405
})
405
406
}
406
407
}
@@ -476,7 +477,7 @@ func TestSelectRuntime(t *testing.T) {
476
477
require .EqualError (t , err , "no supported runtimes found" )
477
478
} else {
478
479
require .NoError (t , err )
479
- assert .Equal (t , tc .expectedRuntime , got )
480
+ require .Equal (t , tc .expectedRuntime , got )
480
481
}
481
482
})
482
483
}
@@ -761,3 +762,188 @@ func TestParseServerEntry(t *testing.T) {
761
762
})
762
763
}
763
764
}
765
+
766
+ func TestAddCmd_CacheTTL (t * testing.T ) {
767
+ t .Parallel ()
768
+
769
+ tests := []struct {
770
+ name string
771
+ ttl string
772
+ expectedError string
773
+ }{
774
+ {
775
+ name : "valid cache TTL" ,
776
+ ttl : "1h" ,
777
+ },
778
+ {
779
+ name : "invalid cache TTL" ,
780
+ ttl : "invalid" ,
781
+ expectedError : "invalid cache TTL: time: invalid duration \" invalid\" " ,
782
+ },
783
+ }
784
+
785
+ for _ , tc := range tests {
786
+ t .Run (tc .name , func (t * testing.T ) {
787
+ t .Parallel ()
788
+
789
+ pkg := packages.Server {
790
+ ID : "testserver" ,
791
+ Name : "testserver" ,
792
+ Tools : []packages.Tool {
793
+ {Name : "tool1" },
794
+ },
795
+ Installations : map [runtime.Runtime ]packages.Installation {
796
+ runtime .UVX : {
797
+ Runtime : "uvx" ,
798
+ Package : "mcp-server-testserver" ,
799
+ Version : "latest" ,
800
+ Recommended : true ,
801
+ },
802
+ },
803
+ }
804
+
805
+ cfg := & fakeConfig {}
806
+ cmdObj , err := NewAddCmd (
807
+ & cmd.BaseCmd {},
808
+ cmdopts .WithConfigLoader (& fakeLoader {cfg : cfg }),
809
+ cmdopts .WithRegistryBuilder (& fakeBuilder {reg : & fakeRegistry {pkg : pkg }}),
810
+ )
811
+ require .NoError (t , err )
812
+
813
+ cmdObj .SetOut (io .Discard )
814
+ cmdObj .SetErr (io .Discard )
815
+ cmdObj .SetArgs ([]string {"testserver" , "--cache-ttl" , tc .ttl })
816
+
817
+ err = cmdObj .Execute ()
818
+ if tc .expectedError != "" {
819
+ require .Error (t , err )
820
+ require .EqualError (t , err , tc .expectedError )
821
+ } else {
822
+ require .NoError (t , err )
823
+ require .True (t , cfg .addCalled )
824
+ require .Equal (t , "testserver" , cfg .entry .Name )
825
+ }
826
+ })
827
+ }
828
+ }
829
+
830
+ func TestAddCmd_CacheFlagsWithTempDir (t * testing.T ) {
831
+ t .Parallel ()
832
+
833
+ tests := []struct {
834
+ name string
835
+ setupCmd func (t * testing.T , tempDir string ) []string
836
+ }{
837
+ {
838
+ name : "custom cache directory" ,
839
+ setupCmd : func (t * testing.T , tempDir string ) []string {
840
+ return []string {"testserver" , "--cache-dir" , tempDir }
841
+ },
842
+ },
843
+ {
844
+ name : "both custom cache flags" ,
845
+ setupCmd : func (t * testing.T , tempDir string ) []string {
846
+ return []string {"testserver" , "--cache-dir" , tempDir , "--cache-ttl" , "30m" }
847
+ },
848
+ },
849
+ {
850
+ name : "cache disabled with custom settings" ,
851
+ setupCmd : func (t * testing.T , tempDir string ) []string {
852
+ return []string {"testserver" , "--no-cache" , "--cache-dir" , tempDir , "--cache-ttl" , "2h" }
853
+ },
854
+ },
855
+ }
856
+
857
+ for _ , tc := range tests {
858
+ t .Run (tc .name , func (t * testing.T ) {
859
+ t .Parallel ()
860
+
861
+ tempDir := t .TempDir ()
862
+ args := tc .setupCmd (t , tempDir )
863
+
864
+ pkg := packages.Server {
865
+ ID : "testserver" ,
866
+ Name : "testserver" ,
867
+ Tools : []packages.Tool {
868
+ {Name : "tool1" },
869
+ },
870
+ Installations : map [runtime.Runtime ]packages.Installation {
871
+ runtime .UVX : {
872
+ Runtime : "uvx" ,
873
+ Package : "mcp-server-testserver" ,
874
+ Version : "latest" ,
875
+ Recommended : true ,
876
+ },
877
+ },
878
+ }
879
+
880
+ cfg := & fakeConfig {}
881
+ cmdObj , err := NewAddCmd (
882
+ & cmd.BaseCmd {},
883
+ cmdopts .WithConfigLoader (& fakeLoader {cfg : cfg }),
884
+ cmdopts .WithRegistryBuilder (& fakeBuilder {reg : & fakeRegistry {pkg : pkg }}),
885
+ )
886
+ require .NoError (t , err )
887
+
888
+ cmdObj .SetOut (io .Discard )
889
+ cmdObj .SetErr (io .Discard )
890
+ cmdObj .SetArgs (args )
891
+
892
+ err = cmdObj .Execute ()
893
+ require .NoError (t , err )
894
+ require .True (t , cfg .addCalled )
895
+ require .Equal (t , "testserver" , cfg .entry .Name )
896
+
897
+ // tempDir is available here for any cache directory verification
898
+ })
899
+ }
900
+ }
901
+
902
+ func TestAddCmd_NoCacheDirectoryCreatedWhenDisabled (t * testing.T ) {
903
+ t .Parallel ()
904
+
905
+ tempDir := t .TempDir ()
906
+ cacheSubDir := filepath .Join (tempDir , "should-not-be-created" )
907
+
908
+ // Verify the cache directory doesn't exist initially.
909
+ _ , err := os .Stat (cacheSubDir )
910
+ require .True (t , os .IsNotExist (err ), "Cache directory should not exist initially" )
911
+
912
+ pkg := packages.Server {
913
+ ID : "testserver" ,
914
+ Name : "testserver" ,
915
+ Tools : []packages.Tool {
916
+ {Name : "tool1" },
917
+ },
918
+ Installations : map [runtime.Runtime ]packages.Installation {
919
+ runtime .UVX : {
920
+ Runtime : "uvx" ,
921
+ Package : "mcp-server-testserver" ,
922
+ Version : "latest" ,
923
+ Recommended : true ,
924
+ },
925
+ },
926
+ }
927
+
928
+ cfg := & fakeConfig {}
929
+ cmdObj , err := NewAddCmd (
930
+ & cmd.BaseCmd {},
931
+ cmdopts .WithConfigLoader (& fakeLoader {cfg : cfg }),
932
+ cmdopts .WithRegistryBuilder (& fakeBuilder {reg : & fakeRegistry {pkg : pkg }}),
933
+ )
934
+ require .NoError (t , err )
935
+
936
+ cmdObj .SetOut (io .Discard )
937
+ cmdObj .SetErr (io .Discard )
938
+ // Use --no-cache with custom cache directory - directory should NOT be created.
939
+ cmdObj .SetArgs ([]string {"testserver" , "--no-cache" , "--cache-dir" , cacheSubDir })
940
+
941
+ err = cmdObj .Execute ()
942
+ require .NoError (t , err )
943
+ require .True (t , cfg .addCalled )
944
+ require .Equal (t , "testserver" , cfg .entry .Name )
945
+
946
+ // Verify the cache directory was never created.
947
+ _ , err = os .Stat (cacheSubDir )
948
+ require .True (t , os .IsNotExist (err ), "Cache directory should not be created when --no-cache is used" )
949
+ }
0 commit comments