The #LA7 test is not running when running codecrafters test, but it works fine when launched through a local client

I’m stuck on Stage #LA7

I’ve tried debugging the code with some print statement.

The program suddenly stops when no expiry time is provided but works fine when the expiry time is given.

Here are my logs:

[tester::#LA7] Running tests for Stage #LA7 (Implement the SET & GET commands)
[tester::#LA7] $ ./your_program.sh
[your_program] Server started. Logs will appear here!
[tester::#LA7] Setting key raspberry to mango
[tester::#LA7] $ redis-cli SET raspberry mango
[tester::#LA7] Sent bytes: "*3\r\n$3\r\nSET\r\n$9\r\nraspberry\r\n$5\r\nmango\r\n"
[your_program] Received: *3
[your_program] Received: $3
[your_program] Received: SET
[your_program] Going to read time variable size
[tester::#LA7] Received: "" (no content received)
[tester::#LA7]            ^ error
[tester::#LA7] Error: Expected start of a new RESP2 value (either +, -, :, $ or *)
[tester::#LA7] Test failed
[tester::#LA7] Terminating program
[tester::#LA7] Program terminated successfully


I have tried creating a client at my side and sent the string to set command i.e
String setCommand = “*5\r\n$3\r\nSET\r\n$6\r\norange\r\n$6\r\nbanana\r\n”;

I have mentioned the code for get & set and the client which I have created to test the set command
The test case ran successfully here are my logs

harsh@ubuntu:~/Desktop/codecrafters-redis-java/src/main/java$ java Main 
Server started. Logs will appear here!
Received: *5
Received: $3
Received: SET
Going to read time variable size
No valid expiry provided
setting up no expiry time 
Received: $3
Received: GET
in 1st if condition
value is banana

Here is the code for client that i have made

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args) {
        String hostname = "localhost";  // Assuming the server is running on localhost
        int port = 6379;

        try (Socket socket = new Socket(hostname, port)) {
            // OutputStream to send data to the server
            OutputStream outputStream = socket.getOutputStream();

            // InputStream to read response from the server
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            // Send the SET command with expiry argument (PX) in RESP2 format
//                String setCommand = "*5\r\n$3\r\nSET\r\n$6\r\norange\r\n$6\r\nbanana\r\n$2\r\npx\r\n$3\r\n100\r\n";
                String setCommand = "*5\r\n$3\r\nSET\r\n$6\r\norange\r\n$6\r\nbanana\r\n";


            outputStream.write(setCommand.getBytes());
            outputStream.flush();

            // Send the GET command in RESP2 format
            String getCommand = "*2\r\n$3\r\nGET\r\n$6\r\norange\r\n";
            outputStream.write(getCommand.getBytes());
            outputStream.flush();

            // Now start reading the server's response
            String response;
            while ((response = in.readLine()) != null) {
                System.out.println("Server Response: " + response);
            }

        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}

Here’s a snippet of my code for get and set :

import java.util.Map;
public class GetSet {

    // method to get value based on key if key is not expired
    public static Object getValue(Map<String, Object[]> map, String key) {
        Object[] value = map.get(key);

        if(value.length == 1){
            System.out.println("in 1st if condition");
            return  value[0];
        }

        // check if key got expired
        else if (checkKeyExpiry((long)value[1], (long) value[2])) {
            //return value
            System.out.println("in elif condtion");
            return value[0];
        } else {
            System.out.println("in else condtion");
            map.remove(key);
            return null;
        }
    }
    // Method for inserting the key with expiry time
    public static void setKeyWithExpiry(Map<String,Object[]> map, String key,String value, long expiryTime){

        if(expiryTime !=-1){
            long insertionTimeOfKey = System.currentTimeMillis();
            map.put(key,new Object[]{value,expiryTime,insertionTimeOfKey});
        }else{
            System.out.println("setting up no expiry time ");
            map.put(key,new Object[]{value});
        }
    }

    // method to check weather the key has expired or not
    private static boolean checkKeyExpiry(long expiryTime , long insertionTimeOfKey){

        return System.currentTimeMillis() - insertionTimeOfKey < expiryTime;
    }
}


and here is the code from where the set and get are being called
for set

else if("SET".equalsIgnoreCase(inputLine)){
                        in.readLine();                      // skipping size of key --> $9
                        String key = in.readLine();         // extracting the actual key --> raspberry
                        in.readLine();                      // skipping size of value  --> $6
                        String value = in.readLine();       // extracting the actual value --> banana
                        System.out.println("Going to read time variable size");
                        String sizeOfTimeVariable = in.readLine();// skipping size of time variable  --> $2

                    if(sizeOfTimeVariable !=null && sizeOfTimeVariable.startsWith("$"))

                    {
                        in.readLine();                      // skipping  time variable --> px
                        in.readLine();                      // skipping size of time in millisecond --> $3

                        try{
                            long expTime= Long.parseLong(in.readLine());   // extracting the actual time
                            GetSet.setKeyWithExpiry(map,key,value,expTime);
                        }catch (Exception e){
                            System.out.println(e.getMessage());
                        }
                    }
                    else{
                        System.out.println("No valid expiry provided");
                        GetSet.setKeyWithExpiry(map,key,value,-1);
                    }
                        clientSocket.getOutputStream().write("+OK\r\n".getBytes());
                        clientSocket.getOutputStream().flush();
                }

for get

                else if ("GET".equalsIgnoreCase(inputLine)) {
                    in.readLine(); // Read size of key
                    String key = in.readLine(); // Read key

                    Object value = GetSet.getValue(map, key);
                    System.out.println("value is " + value);

                    if (value != null) {
                        clientSocket.getOutputStream().write(
                                String.format("$%d\r\n%s\r\n", value.toString().length(), value).getBytes());
                    } else {
                        clientSocket.getOutputStream().write("$-1\r\n".getBytes()); // Correctly formatted null response
                    }
                    clientSocket.getOutputStream().flush();
                }

@Harshyadav02 Could you upload your code to GitHub and share the link here? It will be much easier to debug if I can run your code.

I have uploaded the code made some changes to the code, here is the reop link:

https://github.com/Harshyadav02/codecrafters-redis-java/
1 Like

Debugging Steps

  1. I added several printlns:

  1. Size of time variable: did not get printed before the error occurred:


Explanation

When the code attempted to read beyond the end of InputStream, our tester would start verifying the response, which hadn’t been sent back yet.

This caused the error: Received: "" (no content received).


Suggestion

Avoid reading beyond the end of the InputStream.

Start by refactoring the code to utilize the length of the array (instead of discarding it) to determine when to stop reading.

1 Like

Thanks the error got solved

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.