1

I have been in touch with the author of Alternator about this issue, and he's as puzzled as I am. The short story: I have written unit tests of code that operates against DynamoDB using the Alternator mocking framework that work fine when I invoke them from within Eclipse, but fail when invoked from maven.

The failure arises from within the AWS SDK itself:

com.amazonaws.AmazonServiceException: [java.lang.Error: property value is null.]
    at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:679) ~[aws-java-sdk-1.5.5.jar:na]
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:350) ~[aws-java-sdk-1.5.5.jar:na]
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:202) ~[aws-java-sdk-1.5.5.jar:na]
    at com.michelboudreau.alternatorv2.AlternatorDBClientV2.invoke(AlternatorDBClientV2.java:225) ~[alternator-0.6.4.jar:na]
    at com.michelboudreau.alternatorv2.AlternatorDBClientV2.updateItem(AlternatorDBClientV2.java:99) ~[alternator-0.6.4.jar:na]
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$2.executeLowLevelRequest(DynamoDBMapper.java:646) ~[aws-java-sdk-1.5.5.jar:na]
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper$SaveObjectHandler.execute(DynamoDBMapper.java:767) ~[aws-java-sdk-1.5.5.jar:na]
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.save(DynamoDBMapper.java:658) ~[aws-java-sdk-1.5.5.jar:na]
    at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.save(DynamoDBMapper.java:488) ~[aws-java-sdk-1.5.5.jar:na]
    at com.somoglobal.eventdata.Controller.addDeviceKeys(Controller.java:531) ~[classes/:na]

which as you can see is not hugely useful as the stack trace itself is just showing the stack at the point where the AWS SDK is assembling an exception from the response received through the (mocked) remote service.

The relevant version numbers:

  • Maven 3.0.4
  • Java 1.7.0_10
  • AWS SDK 1.5.5 (although I've also tried 1.5.3 and 1.5.4)
  • Eclipse version "Kepler", Build id: 20130614-0229

Burrowing down a bit further, the (slightly elided) pom.xml for the project

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <groupId>snip</groupId>
        <artifactId>snip</artifactId>
        <version>1.14.2-SNAPSHOT</version>
    </parent>
    <artifactId>snip</artifactId>
    <version>1.6.0-SNAPSHOT</version>
    <name>snip</name>
    <dependencies>
        ...snip...
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk</artifactId>
            <version>1.5.5</version>
        </dependency>
        <dependency>
            <groupId>com.michelboudreau</groupId>
            <artifactId>alternator</artifactId>
            <version>0.6.4</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

and the slightly trimmed down test:

package com.xxx;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.joda.time.DateTime;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;

import com.amazonaws.Request;
import com.amazonaws.handlers.RequestHandler;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.CreateTableResult;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughputExceededException;
import com.amazonaws.util.TimingInfo;
import com.michelboudreau.alternator.AlternatorDB;
import com.michelboudreau.alternatorv2.AlternatorDBClientV2;
import com.xxx.stuff;

public class ControllerTest {

    private static Controller instance;   
    private static DynamoDBMapper mapper;
    private static AlternatorDB db;
    private static AlternatorDBClientV2 client;

    @BeforeClass
    public static void setup() throws Exception {
        client = new AlternatorDBClientV2();
        mapper = new DynamoDBMapper(client);
        db = new AlternatorDB().start();
        // code to create dynamodb was here
        instance = new Controller(mapper);
    }

    @AfterClass
    public static void tearDown() throws Exception {
        db.stop();
    }

    @Test
    public void testAddDeviceKeys() {
        Collection<DeviceKey> keys = EventDataModelMapper.getDeviceKeys(ClassFixtures.event);
        assertNotNull("keys should not be null", keys);
        assertFalse("keys should not be empty", keys.isEmpty());

        boolean result = instance.addDeviceKeys(keys);
        assertTrue("result should be true", result);
    }
}

The code under test is probably not particularly involved in this failure - I've done sufficient debugging tracing to see that it behaves identically during test when invoked directly through Eclipse, and when run from maven.

EDIT

Actually, Alternator might be implicated in this, as the error message in question could be coming out of com.michelboudreau.alternator.validation.ValidatorUtils:

    public static <T> List<Error> rejectIfNull(T property) {
            List<Error> errors = new ArrayList<Error>();
            if (property == null) {
                    errors.add(new Error("property value is null."));
            }
            return errors;
    }
  • something to note for the future: a lot of times discrepancies like this can arise based on the different order of tests that the Maven Surefire plugin runs versus the order of tests that your IDE runs. This often is caused by tests that modify some sort of state which carries over into a subsequent test. – matt b Oct 16 '13 at 15:56

3 Answers3

1

Ok stand down, Alternator is not at fault, the problem was ultimately between one of the chairs and keyboards at my workplace. The error message in question was indeed arising from Alternator, and ultimately was sourced to a missing table definition - for very complex reasons when the tests were run through Maven there was a discrepancy between the name of the mock Dynamodb table created through Alternator, and the table name that the code under test was trying to access.

I would like to publicly thank Michel Boudreau for taking the time to respond when I contacted him directly on this matter.

1

Instead you can run Amazon DynamoDB locally.

http://aws.typepad.com/aws/2013/09/dynamodb-local-for-desktop-development.html

deepakmodak
  • 1,329
  • 13
  • 16
1

Instead, you can run DynamoDB Local using jcabi-dynamodb-maven-plugin (I'm the developer).

yegor256
  • 102,010
  • 123
  • 446
  • 597