001/* 002 * acme4j - Java ACME client 003 * 004 * Copyright (C) 2016 Richard "Shred" Körber 005 * http://acme4j.shredzone.org 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 013 */ 014package org.shredzone.acme4j.connector; 015 016import static org.assertj.core.api.Assertions.assertThat; 017import static org.junit.jupiter.api.Assertions.assertThrows; 018import static org.shredzone.acme4j.toolbox.TestUtils.url; 019 020import java.io.IOException; 021import java.net.HttpURLConnection; 022import java.net.URL; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Collections; 026import java.util.Iterator; 027import java.util.List; 028import java.util.NoSuchElementException; 029 030import org.junit.jupiter.api.BeforeEach; 031import org.junit.jupiter.api.Test; 032import org.shredzone.acme4j.Authorization; 033import org.shredzone.acme4j.Login; 034import org.shredzone.acme4j.provider.TestableConnectionProvider; 035import org.shredzone.acme4j.toolbox.JSON; 036import org.shredzone.acme4j.toolbox.JSONBuilder; 037 038/** 039 * Unit test for {@link ResourceIterator}. 040 */ 041public class ResourceIteratorTest { 042 043 private static final int PAGES = 4; 044 private static final int RESOURCES_PER_PAGE = 5; 045 private static final String TYPE = "authorizations"; 046 047 private final List<URL> resourceURLs = new ArrayList<>(PAGES * RESOURCES_PER_PAGE); 048 private final List<URL> pageURLs = new ArrayList<>(PAGES); 049 050 @BeforeEach 051 public void setup() { 052 resourceURLs.clear(); 053 for (var ix = 0; ix < RESOURCES_PER_PAGE * PAGES; ix++) { 054 resourceURLs.add(url("https://example.com/acme/auth/" + ix)); 055 } 056 057 pageURLs.clear(); 058 for (var ix = 0; ix < PAGES; ix++) { 059 pageURLs.add(url("https://example.com/acme/batch/" + ix)); 060 } 061 } 062 063 /** 064 * Test if the {@link ResourceIterator} handles a {@code null} start URL. 065 */ 066 @Test 067 public void nullTest() { 068 assertThrows(NoSuchElementException.class, () -> { 069 var it = createIterator(null); 070 071 assertThat(it).isNotNull(); 072 assertThat(it.hasNext()).isFalse(); 073 it.next(); // throws NoSuchElementException 074 }); 075 } 076 077 /** 078 * Test if the {@link ResourceIterator} returns all objects in the correct order. 079 */ 080 @Test 081 public void iteratorTest() throws IOException { 082 var result = new ArrayList<URL>(); 083 084 var it = createIterator(pageURLs.get(0)); 085 while (it.hasNext()) { 086 result.add(it.next().getLocation()); 087 } 088 089 assertThat(result).isEqualTo(resourceURLs); 090 } 091 092 /** 093 * Test unusual {@link Iterator#next()} and {@link Iterator#hasNext()} usage. 094 */ 095 @Test 096 public void nextHasNextTest() throws IOException { 097 var result = new ArrayList<URL>(); 098 099 var it = createIterator(pageURLs.get(0)); 100 assertThat(it.hasNext()).isTrue(); 101 assertThat(it.hasNext()).isTrue(); 102 103 // don't try this at home, kids... 104 try { 105 for (;;) { 106 result.add(it.next().getLocation()); 107 } 108 } catch (NoSuchElementException ex) { 109 assertThat(it.hasNext()).isFalse(); 110 assertThat(it.hasNext()).isFalse(); 111 } 112 113 assertThat(result).isEqualTo(resourceURLs); 114 } 115 116 /** 117 * Test that {@link Iterator#remove()} fails. 118 */ 119 @Test 120 public void removeTest() { 121 assertThrows(UnsupportedOperationException.class, () -> { 122 var it = createIterator(pageURLs.get(0)); 123 it.next(); 124 it.remove(); // throws UnsupportedOperationException 125 }); 126 } 127 128 /** 129 * Creates a new {@link Iterator} of {@link Authorization} objects. 130 * 131 * @param first 132 * URL of the first page 133 * @return Created {@link Iterator} 134 */ 135 private Iterator<Authorization> createIterator(URL first) throws IOException { 136 var provider = new TestableConnectionProvider() { 137 private int ix; 138 139 @Override 140 public int sendSignedPostAsGetRequest(URL url, Login login) { 141 ix = pageURLs.indexOf(url); 142 assertThat(ix).isGreaterThanOrEqualTo(0); 143 return HttpURLConnection.HTTP_OK; 144 } 145 146 @Override 147 public JSON readJsonResponse() { 148 var start = ix * RESOURCES_PER_PAGE; 149 var end = (ix + 1) * RESOURCES_PER_PAGE; 150 151 var cb = new JSONBuilder(); 152 cb.array(TYPE, resourceURLs.subList(start, end)); 153 154 return JSON.parse(cb.toString()); 155 } 156 157 @Override 158 public Collection<URL> getLinks(String relation) { 159 if ("next".equals(relation) && (ix + 1 < pageURLs.size())) { 160 return Collections.singletonList(pageURLs.get(ix + 1)); 161 } 162 return Collections.emptyList(); 163 } 164 }; 165 166 var login = provider.createLogin(); 167 168 provider.close(); 169 170 return new ResourceIterator<>(login, TYPE, first, Login::bindAuthorization); 171 } 172 173}