<!-- Love localstack? Please consider supporting our collective:
👉  https://opencollective.com/localstack/donate -->

Found a pagination bug with localstack's s3. Primarily against s3Client.listNextBatchOfObjects.

    private void test() {
        s3Client.putObject(s3BucketName, "key1", "content");
        s3Client.putObject(s3BucketName, "key2", "content");
        s3Client.putObject(s3BucketName, "key3", "content");

        ListObjectsRequest listObjectsRequest = new ListObjectsRequest()
                .withBucketName(s3BucketName)
                .withPrefix("")
                .withDelimiter("/")
                .setMaxKeys(1); // 1 Key per request

        ObjectListing objectListing = s3Client.listObjects(listObjectsRequest);
        List<SomeObject> someObjList = createEmptyList();
        someObjList.addAll(mapFilesToSomeObject(objectListing)); // puts at least 1 item into the list

        while (objectListing.isTruncated()) {
            objectListing = s3Client.listNextBatchOfObjects(objectListing);
            someObjList.addAll(mapFilesToSomeObject(objectListing));
        }
        assertEquals(3, someObjList.size());
    }

    private List<SomeObject> mapFilesToSomeObject(ObjectListing objectListing) {
        return objectListing.getObjectSummaries()
            .stream()
            .map(S3ObjectSummary::getKey)
            .map(x -> this.toSomeObject(x)) // some deserialization method
            .collect(Collectors.toList());
    }

This while loop will only get the second item in its first loop. It still enters the loop once more to grab the third item since the condition is still true, but the 2nd call of listNextBatchOfObjects in that very loop returns an empty list, thus failing to grab that third item. I confirmed that listNextBatchOfObjects retrieves the "second page" only against localstack, with changing the amount of items and page sizes. On AWS s3, this works as expected.

Refer to s3Client.listNextBatchOfObjects:
https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Client.html#listNextBatchOfObjects-com.amazonaws.services.s3.model.ObjectListing-
host = headers['host']
    for pattern in [common_pattern, dualstack_pattern, legacy_patterns]:
        match = pattern.match(host)
        if match:
            bucket_name = match.groups()[0]
            break
    
    
    return normalize_bucket_name(bucket_name)
def handle_notification_request(bucket, method, data):
    response = Response()
    response.status_code = 200
    response._content = ''
    if method == 'GET':
        
        result = '<NotificationConfiguration xmlns="%s">' % XMLNS_S3
        if bucket in S3_NOTIFICATIONS:
            notifs = S3_NOTIFICATIONS[bucket]
            for notif in notifs:
                for dest in NOTIFICATION_DESTINATION_TYPES:
                    if dest in notif:
                        dest_dict = {
                            '%sConfiguration' % dest: {
                                'Id': uuid.uuid4(),
                                dest: notif[dest],
                                'Event': notif['Event'],
                                'Filter': notif['Filter']
                            }