embulk-input-http 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,86 @@
1
+ package org.embulk.input.http;
2
+
3
+ import com.fasterxml.jackson.annotation.JsonCreator;
4
+ import com.fasterxml.jackson.annotation.JsonProperty;
5
+ import com.google.common.base.Optional;
6
+
7
+ import java.util.ArrayList;
8
+ import java.util.List;
9
+
10
+ public class PagerConfig {
11
+
12
+ private final String fromParam;
13
+ private final Optional<String> toParam;
14
+ private final int start;
15
+ private final int pages;
16
+ private final int step;
17
+
18
+ @JsonCreator
19
+ public PagerConfig(@JsonProperty("from_param") String fromParam,
20
+ @JsonProperty("to_param") Optional<String> toParam,
21
+ @JsonProperty("start") Optional<Integer> start,
22
+ @JsonProperty("pages") int pages,
23
+ @JsonProperty("step") Optional<Integer> step) {
24
+ this.fromParam = fromParam;
25
+ this.toParam = toParam;
26
+ this.start = start.or(0);
27
+ this.pages = pages;
28
+ this.step = step.or(1);
29
+ }
30
+
31
+ public List<List<QueryConfig.Query>> expand() {
32
+ List<List<QueryConfig.Query>> queries = new ArrayList<>();
33
+ int p = 1;
34
+ int index = start;
35
+ while (p <= pages) {
36
+ List<QueryConfig.Query> one = new ArrayList<>();
37
+ one.add(new QueryConfig.Query(fromParam, Integer.toString(index)));
38
+ if (toParam.isPresent()) {
39
+ int t = index + step - 1;
40
+ one.add(new QueryConfig.Query(toParam.get(), Integer.toString(t)));
41
+ index = t + 1;
42
+ } else {
43
+ index += step;
44
+ }
45
+ queries.add(one);
46
+ p++;
47
+ }
48
+ return queries;
49
+ }
50
+
51
+ @JsonProperty("from_param")
52
+ public String getFromParam() {
53
+ return fromParam;
54
+ }
55
+
56
+ @JsonProperty("to_param")
57
+ public Optional<String> getToParam() {
58
+ return toParam;
59
+ }
60
+
61
+ @JsonProperty("start")
62
+ public int getStart() {
63
+ return start;
64
+ }
65
+
66
+ @JsonProperty("pages")
67
+ public int getPages() {
68
+ return pages;
69
+ }
70
+
71
+ @JsonProperty("step")
72
+ public int getStep() {
73
+ return step;
74
+ }
75
+
76
+ @Override
77
+ public String toString() {
78
+ return "PagerConfig{" +
79
+ "fromParam='" + fromParam + '\'' +
80
+ ", toParam=" + toParam +
81
+ ", start=" + start +
82
+ ", pages=" + pages +
83
+ ", step=" + step +
84
+ '}';
85
+ }
86
+ }
@@ -0,0 +1,82 @@
1
+ package org.embulk.input.http;
2
+
3
+ import com.fasterxml.jackson.annotation.JsonCreator;
4
+ import com.fasterxml.jackson.annotation.JsonValue;
5
+ import com.google.common.base.Objects;
6
+ import com.google.common.base.Optional;
7
+
8
+ import java.util.ArrayList;
9
+ import java.util.List;
10
+
11
+ public class ParamsConfig {
12
+
13
+ private final List<QueryConfig> queries;
14
+
15
+ @JsonCreator
16
+ public ParamsConfig(List<QueryConfig> queries) {
17
+ this.queries = queries;
18
+ }
19
+
20
+ @JsonValue
21
+ public List<QueryConfig> getQueries() {
22
+ return queries;
23
+ }
24
+
25
+ public List<List<QueryConfig.Query>> generateQueries(Optional<PagerConfig> pagerConfig) {
26
+ List<List<QueryConfig.Query>> base = new ArrayList<>(queries.size());
27
+ for (QueryConfig p : queries) {
28
+ base.add(p.expand());
29
+ }
30
+
31
+ int productSize = 1;
32
+ int baseSize = base.size();
33
+ for (int i = 0; i < baseSize; productSize *= base.get(i).size(), i++);
34
+
35
+ List<List<QueryConfig.Query>> expands = new ArrayList<>(productSize);
36
+ for (int i = 0; i < productSize; i++) {
37
+ int j = 1;
38
+ List<QueryConfig.Query> one = new ArrayList<>();
39
+ for (List<QueryConfig.Query> list : base) {
40
+ QueryConfig.Query pc = list.get((i / j) % list.size());
41
+ one.add(pc);
42
+ j *= list.size();
43
+ }
44
+ if (pagerConfig.isPresent()) {
45
+ for (List<QueryConfig.Query> q : pagerConfig.get().expand()) {
46
+ expands.add(copyAndConcat(one, q));
47
+ }
48
+ } else {
49
+ expands.add(one);
50
+ }
51
+ }
52
+
53
+ return expands;
54
+ }
55
+
56
+ @Override
57
+ public boolean equals(Object obj) {
58
+ if (this == obj) {
59
+ return true;
60
+ }
61
+ if (!(obj instanceof ParamsConfig)) {
62
+ return false;
63
+ }
64
+ ParamsConfig other = (ParamsConfig) obj;
65
+ return Objects.equal(queries, other.queries);
66
+ }
67
+
68
+ @Override
69
+ public int hashCode() {
70
+ return Objects.hashCode(queries);
71
+ }
72
+
73
+ private List<QueryConfig.Query> copyAndConcat(List<QueryConfig.Query>... srcs) {
74
+ List<QueryConfig.Query> dest = new ArrayList<>();
75
+ for (List<QueryConfig.Query> src : srcs) {
76
+ for (QueryConfig.Query q : src) {
77
+ dest.add(q.copy());
78
+ }
79
+ }
80
+ return dest;
81
+ }
82
+ }
@@ -0,0 +1,171 @@
1
+ package org.embulk.input.http;
2
+
3
+ import com.fasterxml.jackson.annotation.JsonCreator;
4
+ import com.fasterxml.jackson.annotation.JsonProperty;
5
+ import com.google.common.base.Objects;
6
+ import com.google.common.base.Optional;
7
+
8
+ import java.util.ArrayList;
9
+ import java.util.Arrays;
10
+ import java.util.List;
11
+
12
+ public class QueryConfig {
13
+
14
+ private final String name;
15
+ private final Optional<String> value;
16
+ private final Optional<List<String>> values;
17
+ private final boolean expand;
18
+
19
+ @JsonCreator
20
+ public QueryConfig(
21
+ @JsonProperty("name") String name,
22
+ @JsonProperty("value") Optional<String> value,
23
+ @JsonProperty("values") Optional<List<String>> values,
24
+ @JsonProperty("expand") boolean expand) {
25
+ this.name = name;
26
+ this.value = value;
27
+ this.values = values;
28
+ this.expand = expand;
29
+ }
30
+
31
+ public List<Query> expand() {
32
+ List<Query> dest;
33
+ if (value.isPresent()) {
34
+ if (expand) {
35
+ List<String> expanded = BraceExpansion.expand(value.get());
36
+ dest = new ArrayList<>(expanded.size());
37
+ for (String s : expanded) {
38
+ dest.add(new Query(name, s));
39
+ }
40
+ } else {
41
+ dest = new ArrayList<>(1);
42
+ dest.add(new Query(name, value.get()));
43
+ }
44
+ } else if (values.isPresent()) {
45
+ if (expand) {
46
+ dest = new ArrayList<>(values.get().size());
47
+ for (String s : values.get()) {
48
+ dest.add(new Query(name, s));
49
+ }
50
+ } else {
51
+ dest = new ArrayList<>(1);
52
+ final String[] valueArr = values.get().toArray(new String[values.get().size()]);
53
+ dest.add(new Query(name, valueArr));
54
+ }
55
+ } else {
56
+ throw new IllegalArgumentException("value or values must be specified to 'params'");
57
+ }
58
+ return dest;
59
+ }
60
+
61
+ @JsonProperty("name")
62
+ public String getName() {
63
+ return name;
64
+ }
65
+
66
+ @JsonProperty("value")
67
+ public Optional<String> getValue() {
68
+ return value;
69
+ }
70
+
71
+ @JsonProperty("expand")
72
+ public boolean isExpand() {
73
+ return expand;
74
+ }
75
+
76
+ @Override
77
+ public boolean equals(Object obj) {
78
+ if (this == obj) {
79
+ return true;
80
+ }
81
+ if (!(obj instanceof QueryConfig)) {
82
+ return false;
83
+ }
84
+ QueryConfig other = (QueryConfig) obj;
85
+ return Objects.equal(this.name, other.name) &&
86
+ Objects.equal(value, other.value) &&
87
+ Objects.equal(expand, other.expand);
88
+ }
89
+
90
+ @Override
91
+ public int hashCode() {
92
+ return Objects.hashCode(name, value, expand);
93
+ }
94
+
95
+ @Override
96
+ public String toString() {
97
+ return String.format("ParameterConfig[%s, %s, %s]",
98
+ getName(), getValue(), isExpand());
99
+ }
100
+
101
+ public static class Query {
102
+ private final String name;
103
+ private final String[] values;
104
+
105
+ public Query(
106
+ @JsonProperty("name") String name,
107
+ @JsonProperty("values") String... values) {
108
+ this.name = name;
109
+ this.values = values;
110
+ }
111
+
112
+ public String getName() {
113
+ return name;
114
+ }
115
+
116
+ public String[] getValues() {
117
+ return values;
118
+ }
119
+
120
+ public Query copy() {
121
+ return new Query(this.name, Arrays.copyOf(this.values, this.values.length));
122
+ }
123
+ }
124
+
125
+ private static class BraceExpansion {
126
+
127
+ public static List<String> expand(String s) {
128
+ return expandRecursive("", s, "", new ArrayList<String>());
129
+ }
130
+
131
+ private static List<String> expandRecursive(String prefix, String s,
132
+ String suffix, List<String> dest) {
133
+ // I used the code below as reference.
134
+ // http://rosettacode.org/wiki/Brace_expansion#Java
135
+ int i1 = -1, i2 = 0;
136
+ String noEscape = s.replaceAll("([\\\\]{2}|[\\\\][,}{])", " ");
137
+ StringBuilder sb = null;
138
+
139
+ outer:
140
+ while ((i1 = noEscape.indexOf('{', i1 + 1)) != -1) {
141
+ i2 = i1 + 1;
142
+ sb = new StringBuilder(s);
143
+ for (int depth = 1; i2 < s.length() && depth > 0; i2++) {
144
+ char c = noEscape.charAt(i2);
145
+ depth = (c == '{') ? ++depth : depth;
146
+ depth = (c == '}') ? --depth : depth;
147
+ if (c == ',' && depth == 1) {
148
+ sb.setCharAt(i2, '\u0000');
149
+ } else if (c == '}' && depth == 0 && sb.indexOf("\u0000") != -1) {
150
+ break outer;
151
+ }
152
+ }
153
+ }
154
+
155
+ if (i1 == -1) {
156
+ if (suffix.length() > 0) {
157
+ expandRecursive(prefix + s, suffix, "", dest);
158
+ } else {
159
+ final String out = String.format("%s%s%s", prefix, s, suffix).
160
+ replaceAll("[\\\\]{2}", "\\").replaceAll("[\\\\]([,}{])", "$1");
161
+ dest.add(out);
162
+ }
163
+ } else {
164
+ for (String m : sb.substring(i1 + 1, i2).split("\u0000", -1)) {
165
+ expandRecursive(prefix + s.substring(0, i1), m, s.substring(i2 + 1) + suffix, dest);
166
+ }
167
+ }
168
+ return dest;
169
+ }
170
+ }
171
+ }
@@ -0,0 +1,90 @@
1
+ package org.embulk.input.http;
2
+
3
+ import com.google.common.collect.ImmutableList;
4
+ import org.apache.http.HttpException;
5
+ import org.apache.http.HttpResponse;
6
+ import org.apache.http.client.HttpClient;
7
+ import org.apache.http.client.methods.HttpRequestBase;
8
+ import org.apache.http.util.EntityUtils;
9
+ import org.embulk.spi.Exec;
10
+ import org.embulk.spi.util.RetryExecutor;
11
+ import org.slf4j.Logger;
12
+
13
+ import javax.net.ssl.SSLException;
14
+ import java.io.IOException;
15
+ import java.io.InterruptedIOException;
16
+ import java.net.UnknownHostException;
17
+ import java.util.List;
18
+
19
+ public class RetryableHandler implements RetryExecutor.Retryable {
20
+
21
+ protected final Logger logger = Exec.getLogger(getClass());
22
+
23
+ private static List<Class<? extends IOException>> NOT_RETRIABLE_CLAASSES;
24
+
25
+ private final HttpClient client;
26
+ private final HttpRequestBase request;
27
+ private HttpResponse response;
28
+
29
+ static {
30
+ ImmutableList.Builder<Class<? extends IOException>> classes = ImmutableList.builder();
31
+ classes.add(UnknownHostException.class).
32
+ add(InterruptedIOException.class).
33
+ add(SSLException.class);
34
+ NOT_RETRIABLE_CLAASSES = classes.build();
35
+ }
36
+
37
+ public RetryableHandler(HttpClient client, HttpRequestBase request) {
38
+ this.client = client;
39
+ this.request = request;
40
+ }
41
+
42
+ public HttpResponse getResponse() {
43
+ return response;
44
+ }
45
+
46
+ @Override
47
+ public Object call() throws Exception {
48
+ if (response != null) throw new IllegalStateException("response is already set");
49
+ HttpResponse response = client.execute(request);
50
+ statusIsOkOrThrow(response);
51
+ this.response = response;
52
+ return null;
53
+ }
54
+
55
+ @Override
56
+ public boolean isRetryableException(Exception exception) {
57
+ if (NOT_RETRIABLE_CLAASSES.contains(exception.getClass())) {
58
+ logger.error(String.format("'%s' is not retriable", exception.getClass()));
59
+ return false;
60
+ }
61
+ return true;
62
+ }
63
+
64
+ @Override
65
+ public void onRetry(Exception exception, int retryCount, int retryLimit, int retryWait)
66
+ throws RetryExecutor.RetryGiveupException {
67
+ logger.warn("retrying {}/{} after {} seconds. Message: {}",
68
+ retryCount, retryLimit, retryWait / 1000,
69
+ exception.getMessage());
70
+ }
71
+
72
+ @Override
73
+ public void onGiveup(Exception firstException, Exception lastException)
74
+ throws RetryExecutor.RetryGiveupException {
75
+ logger.error("giveup {}", lastException.getMessage());
76
+ }
77
+
78
+ protected void statusIsOkOrThrow(HttpResponse response)
79
+ throws HttpException, IOException {
80
+ int code = response.getStatusLine().getStatusCode();
81
+ switch (response.getStatusLine().getStatusCode()) {
82
+ case 200:
83
+ return;
84
+ default:
85
+ throw new HttpException(String.format("Request is not successful, code=%d, body=%s",
86
+ code, EntityUtils.toString(response.getEntity())));
87
+ }
88
+ }
89
+
90
+ }
@@ -0,0 +1,5 @@
1
+ package org.embulk.input.http;
2
+
3
+ public class TestHttpInputPlugin
4
+ {
5
+ }
@@ -0,0 +1,78 @@
1
+ package org.embulk.input.http;
2
+
3
+ import com.google.common.base.Optional;
4
+ import org.junit.Test;
5
+
6
+ import java.util.List;
7
+
8
+ import static org.junit.Assert.assertEquals;
9
+
10
+ public class TestPagerConfig {
11
+
12
+ @Test
13
+ public void testExpandFromTo() throws Exception {
14
+ List<List<QueryConfig.Query>> dest = new PagerConfig("from", Optional.of("to"), Optional.of(1), 3,
15
+ Optional.of(2)).expand();
16
+ assertEquals(dest.size(), 3);
17
+
18
+ assertEquals(dest.get(0).size(), 2);
19
+ assertEquals(dest.get(0).get(0).getName(), "from");
20
+ assertEquals(dest.get(0).get(0).getValues()[0], "1");
21
+ assertEquals(dest.get(0).get(1).getName(), "to");
22
+ assertEquals(dest.get(0).get(1).getValues()[0], "2");
23
+
24
+ assertEquals(dest.get(1).size(), 2);
25
+ assertEquals(dest.get(1).get(0).getName(), "from");
26
+ assertEquals(dest.get(1).get(0).getValues()[0], "3");
27
+ assertEquals(dest.get(1).get(1).getName(), "to");
28
+ assertEquals(dest.get(1).get(1).getValues()[0], "4");
29
+
30
+ assertEquals(dest.get(2).size(), 2);
31
+ assertEquals(dest.get(2).get(0).getName(), "from");
32
+ assertEquals(dest.get(2).get(0).getValues()[0], "5");
33
+ assertEquals(dest.get(2).get(1).getName(), "to");
34
+ assertEquals(dest.get(2).get(1).getValues()[0], "6");
35
+ }
36
+
37
+ @Test
38
+ public void testExpandFromToWithDefault() throws Exception {
39
+ Optional<Integer> nullValue = Optional.absent();
40
+
41
+ List<List<QueryConfig.Query>> dest = new PagerConfig("from", Optional.of("to"), nullValue, 2, nullValue)
42
+ .expand();
43
+ assertEquals(dest.size(), 2);
44
+
45
+ assertEquals(dest.get(0).size(), 2);
46
+ assertEquals(dest.get(0).get(0).getName(), "from");
47
+ assertEquals(dest.get(0).get(0).getValues()[0], "0");
48
+ assertEquals(dest.get(0).get(1).getName(), "to");
49
+ assertEquals(dest.get(0).get(1).getValues()[0], "0");
50
+
51
+ assertEquals(dest.get(1).size(), 2);
52
+ assertEquals(dest.get(1).get(0).getName(), "from");
53
+ assertEquals(dest.get(1).get(0).getValues()[0], "1");
54
+ assertEquals(dest.get(1).get(1).getName(), "to");
55
+ assertEquals(dest.get(1).get(1).getValues()[0], "1");
56
+ }
57
+
58
+ @Test
59
+ public void testExpandPagenate() throws Exception {
60
+ Optional<String> nullValue = Optional.absent();
61
+ List<List<QueryConfig.Query>> dest = new PagerConfig("page", nullValue, Optional.of(1), 3,
62
+ Optional.of(1)).expand();
63
+ assertEquals(dest.size(), 3);
64
+
65
+ assertEquals(dest.get(0).size(), 1);
66
+ assertEquals(dest.get(0).get(0).getName(), "page");
67
+ assertEquals(dest.get(0).get(0).getValues()[0], "1");
68
+
69
+ assertEquals(dest.get(1).size(), 1);
70
+ assertEquals(dest.get(1).get(0).getName(), "page");
71
+ assertEquals(dest.get(1).get(0).getValues()[0], "2");
72
+
73
+ assertEquals(dest.get(2).size(), 1);
74
+ assertEquals(dest.get(2).get(0).getName(), "page");
75
+ assertEquals(dest.get(2).get(0).getValues()[0], "3");
76
+ }
77
+
78
+ }
@@ -0,0 +1,105 @@
1
+ package org.embulk.input.http;
2
+
3
+ import com.google.common.base.Optional;
4
+ import com.google.common.collect.Lists;
5
+ import org.junit.Test;
6
+
7
+ import java.util.List;
8
+
9
+ import static org.junit.Assert.assertEquals;
10
+
11
+ public class TestParamsConfig {
12
+
13
+ @Test
14
+ public void testUnexpandQueriesSinglePair() throws Exception {
15
+ Optional<List<String>> nullValues = Optional.absent();
16
+ QueryConfig q1 = new QueryConfig("test1", Optional.of("awasome1"), nullValues, false);
17
+ QueryConfig q2 = new QueryConfig("test2", Optional.of("awasome2"), nullValues, false);
18
+ ParamsConfig paramsConfig = new ParamsConfig(Lists.newArrayList(q1, q2));
19
+ Optional<PagerConfig> pagerConfig = Optional.absent();
20
+ List<List<QueryConfig.Query>> dest = paramsConfig.generateQueries(pagerConfig);
21
+ assertEquals(dest.size(), 1);
22
+ assertEquals(dest.get(0).size(), 2);
23
+ assertEquals(dest.get(0).get(0).getName(), "test1");
24
+ assertEquals(dest.get(0).get(0).getValues()[0], "awasome1");
25
+ assertEquals(dest.get(0).get(1).getName(), "test2");
26
+ assertEquals(dest.get(0).get(1).getValues()[0], "awasome2");
27
+ }
28
+
29
+ @Test
30
+ public void testUnexpandQueriesExpandPair() throws Exception {
31
+ Optional<String> nullValue = Optional.absent();
32
+ List<String> values1 = Lists.newArrayList("a", "b");
33
+ List<String> values2 = Lists.newArrayList("c", "d");
34
+
35
+ QueryConfig q1 = new QueryConfig("test1", nullValue, Optional.of(values1), false);
36
+ QueryConfig q2 = new QueryConfig("test2", nullValue, Optional.of(values2), false);
37
+
38
+ ParamsConfig paramsConfig = new ParamsConfig(Lists.newArrayList(q1, q2));
39
+ Optional<PagerConfig> pagerConfig = Optional.absent();
40
+ List<List<QueryConfig.Query>> dest = paramsConfig.generateQueries(pagerConfig);
41
+ assertEquals(dest.size(), 1);
42
+ assertEquals(dest.get(0).size(), 2);
43
+ assertEquals(dest.get(0).get(0).getName(), "test1");
44
+ assertEquals(dest.get(0).get(0).getValues()[0], "a");
45
+ assertEquals(dest.get(0).get(0).getValues()[1], "b");
46
+ assertEquals(dest.get(0).get(1).getName(), "test2");
47
+ assertEquals(dest.get(0).get(1).getValues()[0], "c");
48
+ assertEquals(dest.get(0).get(1).getValues()[1], "d");
49
+ }
50
+
51
+ @Test
52
+ public void testExpandQueriesSinglePair() throws Exception {
53
+ Optional<List<String>> nullValues = Optional.absent();
54
+ QueryConfig q1 = new QueryConfig("test1", Optional.of("awasome1"), nullValues, true);
55
+ QueryConfig q2 = new QueryConfig("test2", Optional.of("awasome2"), nullValues, true);
56
+ ParamsConfig paramsConfig = new ParamsConfig(Lists.newArrayList(q1, q2));
57
+ Optional<PagerConfig> pagerConfig = Optional.absent();
58
+ List<List<QueryConfig.Query>> dest = paramsConfig.generateQueries(pagerConfig);
59
+ assertEquals(dest.size(), 1);
60
+ assertEquals(dest.get(0).size(), 2);
61
+ assertEquals(dest.get(0).get(0).getName(), "test1");
62
+ assertEquals(dest.get(0).get(0).getValues()[0], "awasome1");
63
+ assertEquals(dest.get(0).get(1).getName(), "test2");
64
+ assertEquals(dest.get(0).get(1).getValues()[0], "awasome2");
65
+ }
66
+
67
+ @Test
68
+ public void testExpandQueriesExpandPair() throws Exception {
69
+ Optional<String> nullValue = Optional.absent();
70
+ List<String> values1 = Lists.newArrayList("a", "b");
71
+ List<String> values2 = Lists.newArrayList("c", "d");
72
+
73
+ QueryConfig q1 = new QueryConfig("test1", nullValue, Optional.of(values1), true);
74
+ QueryConfig q2 = new QueryConfig("test2", nullValue, Optional.of(values2), true);
75
+
76
+ ParamsConfig paramsConfig = new ParamsConfig(Lists.newArrayList(q1, q2));
77
+ Optional<PagerConfig> pagerConfig = Optional.absent();
78
+ List<List<QueryConfig.Query>> dest = paramsConfig.generateQueries(pagerConfig);
79
+ assertEquals(dest.size(), 4);
80
+
81
+ assertEquals(dest.get(0).size(), 2);
82
+ assertEquals(dest.get(0).get(0).getName(), "test1");
83
+ assertEquals(dest.get(0).get(0).getValues()[0], "a");
84
+ assertEquals(dest.get(0).get(1).getName(), "test2");
85
+ assertEquals(dest.get(0).get(1).getValues()[0], "c");
86
+
87
+ assertEquals(dest.get(1).size(), 2);
88
+ assertEquals(dest.get(1).get(0).getName(), "test1");
89
+ assertEquals(dest.get(1).get(0).getValues()[0], "b");
90
+ assertEquals(dest.get(1).get(1).getName(), "test2");
91
+ assertEquals(dest.get(1).get(1).getValues()[0], "c");
92
+
93
+ assertEquals(dest.get(2).size(), 2);
94
+ assertEquals(dest.get(2).get(0).getName(), "test1");
95
+ assertEquals(dest.get(2).get(0).getValues()[0], "a");
96
+ assertEquals(dest.get(2).get(1).getName(), "test2");
97
+ assertEquals(dest.get(2).get(1).getValues()[0], "d");
98
+
99
+ assertEquals(dest.get(3).size(), 2);
100
+ assertEquals(dest.get(3).get(0).getName(), "test1");
101
+ assertEquals(dest.get(3).get(0).getValues()[0], "b");
102
+ assertEquals(dest.get(3).get(1).getName(), "test2");
103
+ assertEquals(dest.get(3).get(1).getValues()[0], "d");
104
+ }
105
+ }