@@ -21,6 +21,8 @@ type shellServerState struct {
2121 commands []string
2222 blocks map [string ]string
2323 present map [string ]bool
24+ chunks map [string ]string
25+ chunkSet map [string ]bool
2426}
2527
2628func (s * shellServerState ) record (cmd string ) {
@@ -66,6 +68,29 @@ func (s *shellServerState) blockExists(x string, y string) bool {
6668 return s .present [x + ":" + y ]
6769}
6870
71+ func (s * shellServerState ) setChunk (cx string , cy string , bits string ) {
72+ s .mu .Lock ()
73+ defer s .mu .Unlock ()
74+ key := cx + ":" + cy
75+ s .chunks [key ] = bits
76+ s .chunkSet [key ] = true
77+ }
78+
79+ func (s * shellServerState ) getChunk (cx string , cy string ) string {
80+ s .mu .Lock ()
81+ defer s .mu .Unlock ()
82+ if bits , ok := s .chunks [cx + ":" + cy ]; ok {
83+ return bits
84+ }
85+ return "0000"
86+ }
87+
88+ func (s * shellServerState ) chunkExists (cx string , cy string ) bool {
89+ s .mu .Lock ()
90+ defer s .mu .Unlock ()
91+ return s .chunkSet [cx + ":" + cy ]
92+ }
93+
6994func startShellTestServer (t * testing.T , token string ) (string , * shellServerState , func ()) {
7095 t .Helper ()
7196
@@ -75,8 +100,10 @@ func startShellTestServer(t *testing.T, token string) (string, *shellServerState
75100 }
76101
77102 state := & shellServerState {
78- blocks : make (map [string ]string ),
79- present : make (map [string ]bool ),
103+ blocks : make (map [string ]string ),
104+ present : make (map [string ]bool ),
105+ chunks : make (map [string ]string ),
106+ chunkSet : make (map [string ]bool ),
80107 }
81108 done := make (chan struct {})
82109
@@ -223,8 +250,53 @@ func startShellTestServer(t *testing.T, token string) (string, *shellServerState
223250 if err := writeBulk (writer , []byte ("chunkdb_version=1\n " )); err != nil {
224251 return
225252 }
253+ case "CHUNKEXISTS" :
254+ if ! authed {
255+ if err := writeError (writer , "AUTH_REQUIRED use AUTH <token>" ); err != nil {
256+ return
257+ }
258+ continue
259+ }
260+ if len (fields ) != 3 {
261+ if err := writeError (writer , "INVALID_ARGUMENT CHUNKEXISTS requires 2 args" ); err != nil {
262+ return
263+ }
264+ continue
265+ }
266+ if state .chunkExists (fields [1 ], fields [2 ]) {
267+ if err := writeSimple (writer , "1" ); err != nil {
268+ return
269+ }
270+ } else {
271+ if err := writeSimple (writer , "0" ); err != nil {
272+ return
273+ }
274+ }
275+ case "CHUNKSET" :
276+ if ! authed {
277+ if err := writeError (writer , "AUTH_REQUIRED use AUTH <token>" ); err != nil {
278+ return
279+ }
280+ continue
281+ }
282+ if len (fields ) != 4 {
283+ if err := writeError (writer , "INVALID_ARGUMENT CHUNKSET requires 3 args" ); err != nil {
284+ return
285+ }
286+ continue
287+ }
288+ if ! isBits (fields [3 ]) {
289+ if err := writeError (writer , "INVALID_ARGUMENT invalid bits" ); err != nil {
290+ return
291+ }
292+ continue
293+ }
294+ state .setChunk (fields [1 ], fields [2 ], fields [3 ])
295+ if err := writeSimple (writer , "OK" ); err != nil {
296+ return
297+ }
226298 case "CHUNK" :
227- if err := writeBulk (writer , []byte ("0000" )); err != nil {
299+ if err := writeBulk (writer , []byte (state . getChunk ( fields [ 1 ], fields [ 2 ]) )); err != nil {
228300 return
229301 }
230302 case "CHUNKBIN" :
@@ -315,7 +387,7 @@ func TestRunShellConnectAuthPingExistsGetSetUnsetQuit(t *testing.T) {
315387 }
316388 defer client .Close ()
317389
318- input := strings .NewReader ("ping\n exists 1 2\n set 1 2 1010\n exists 1 2\n get 1 2\n unset 1 2\n exists 1 2\n get 1 2\n quit\n " )
390+ input := strings .NewReader ("ping\n exists 1 2\n set 1 2 1010\n exists 1 2\n get 1 2\n unset 1 2\n exists 1 2\n get 1 2\n chunkexists 0 0 \n chunkset 0 0 1111000011110000 \n chunkexists 0 0 \n chunk 0 0 \ n quit\n " )
319391 var out bytes.Buffer
320392 var errOut bytes.Buffer
321393
@@ -334,7 +406,7 @@ func TestRunShellConnectAuthPingExistsGetSetUnsetQuit(t *testing.T) {
334406 if ! sawAuth {
335407 t .Fatalf ("expected shell auto-auth to run AUTH" )
336408 }
337- expectedCommands := []string {"AUTH" , "PING" , "EXISTS" , "SET" , "EXISTS" , "GET" , "UNSET" , "EXISTS" , "GET" , "QUIT" }
409+ expectedCommands := []string {"AUTH" , "PING" , "EXISTS" , "SET" , "EXISTS" , "GET" , "UNSET" , "EXISTS" , "GET" , "CHUNKEXISTS" , "CHUNKSET" , "CHUNKEXISTS" , "CHUNK" , " QUIT" }
338410 if len (commands ) != len (expectedCommands ) {
339411 t .Fatalf ("unexpected command count: got %v want %v" , commands , expectedCommands )
340412 }
@@ -345,10 +417,10 @@ func TestRunShellConnectAuthPingExistsGetSetUnsetQuit(t *testing.T) {
345417 }
346418
347419 output := out .String ()
348- if strings .Count (output , "chunk> " ) < 8 {
420+ if strings .Count (output , "chunk> " ) < 12 {
349421 t .Fatalf ("expected repeated prompt, got %q" , output )
350422 }
351- for _ , expected := range []string {"PONG" , "chunk> 0\n " , "chunk> 1\n " , "1010" , "0000" , "BYE" } {
423+ for _ , expected := range []string {"PONG" , "chunk> 0\n " , "chunk> 1\n " , "1010" , "0000" , "1111000011110000" , " BYE" } {
352424 if ! strings .Contains (output , expected ) {
353425 t .Fatalf ("expected %q in output %q" , expected , output )
354426 }
0 commit comments