@Test
  public void testCreateAndReplaceClientWrongHash() throws Exception {
    final URI uri = URI.create(getRawSyncBaseUri() + "/clients/customers/4710");

    // check that client doesn't exist before
    assertThat(fetchClient("4710", "/customers")).isNull();

    final Client body1 = new Client();
    body1.setSecretHash("wrong hash");
    body1.setScopes(asList("read_foo", "read_bar"));
    body1.setIsConfidential(true);

    try {
      getRestTemplate()
          .exchange(
              put(uri)
                  .contentType(APPLICATION_JSON)
                  .header(AUTHORIZATION, USER1_ACCESS_TOKEN)
                  .body(body1),
              Void.class);
      fail("wrong BCrypt hash should fail with Bad Request");
    } catch (HttpClientErrorException ex) {
      assertThat(ex.getStatusCode()).isEqualTo(BAD_REQUEST);
    }
  }
  @Test
  public void testCreateAndReplaceClient() throws Exception {
    final URI uri = URI.create(getRawSyncBaseUri() + "/clients/customers/4711");

    // check that client doesn't exist before
    assertThat(fetchClient("4711", "/customers")).isNull();

    final String hash = genHash("foo");

    final Client body1 = new Client();
    body1.setSecretHash(hash);
    body1.setScopes(asList("read_foo", "read_bar"));
    body1.setIsConfidential(true);
    body1.setImageUri("https://path.to.my/logo.jpg");
    body1.setHomepageUrl("https://github.com/zalando");

    // user1 creates the client
    assertThat(
            getRestTemplate()
                .exchange(
                    put(uri)
                        .contentType(APPLICATION_JSON)
                        .header(AUTHORIZATION, USER1_ACCESS_TOKEN)
                        .body(body1),
                    Void.class)
                .getStatusCode())
        .isEqualTo(OK);

    assertThat(fetchClient("4711", "/customers"))
        .isNotNull()
        .has(valuesEqualTo(builderOf(body1).createdBy(USER1).lastModifiedBy(USER1).build()));

    final Client body2 = new Client();
    body2.setSecretHash(hash);
    body2.setScopes(asList("read_team", "write_hello", "write_world"));
    body2.setIsConfidential(false);

    // user2 updates the client. modifying all (non-key) columns
    assertThat(
            getRestTemplate()
                .exchange(
                    put(uri)
                        .contentType(APPLICATION_JSON)
                        .header(AUTHORIZATION, USER2_ACCESS_TOKEN)
                        .body(body2),
                    Void.class)
                .getStatusCode())
        .isEqualTo(OK);

    assertThat(fetchClient("4711", "/customers"))
        .isNotNull()
        .has(valuesEqualTo(builderOf(body2).createdBy(USER1).lastModifiedBy(USER2).build()));
  }
  @Test
  public void testUpdateClient() throws Exception {
    final String hash = genHash("qwertz");

    // given an existing client
    session.execute(
        insertInto("client")
            .value("client_id", "1234")
            .value("realm", "/services")
            .value("client_secret_hash", hash)
            .value("scopes", newHashSet("foo", "bar"))
            .value("is_confidential", true)
            .value("created_by", USER1)
            .value("last_modified_by", USER2));

    final Client service1234 = new Client();
    service1234.setSecretHash(hash);
    service1234.setScopes(asList("foo", "bar"));
    service1234.setIsConfidential(true);

    final URI uri = URI.create(getRawSyncBaseUri() + "/clients/services/1234");

    // when the secretHash is updated
    final String newSecretHash = genHash("lolz");
    final Client body1 = new Client();
    body1.setSecretHash(newSecretHash);
    getRestTemplate()
        .exchange(
            patch(uri)
                .contentType(APPLICATION_JSON)
                .header(AUTHORIZATION, USER1_ACCESS_TOKEN)
                .body(body1),
            Void.class);

    // then changes only this change is reflected in data storage
    service1234.setSecretHash(newSecretHash);
    assertThat(fetchClient("1234", "/services"))
        .has(valuesEqualTo(builderOf(service1234).createdBy(USER1).lastModifiedBy(USER1).build()));

    // when the scopes are updated
    final List<String> newScopes = asList("mickey", "mouse", "donald", "duck");
    final Client body2 = new Client();
    body2.setScopes(newScopes);
    getRestTemplate()
        .exchange(
            patch(uri)
                .contentType(APPLICATION_JSON)
                .header(AUTHORIZATION, USER2_ACCESS_TOKEN)
                .body(body2),
            Void.class);

    // then this change is also reflected in data storage
    service1234.setScopes(newScopes);
    assertThat(fetchClient("1234", "/services"))
        .has(valuesEqualTo(builderOf(service1234).createdBy(USER1).lastModifiedBy(USER2).build()));

    // and when the confidential flag is updated
    final Client body3 = new Client();
    body3.setIsConfidential(false);
    getRestTemplate()
        .exchange(
            patch(uri)
                .contentType(APPLICATION_JSON)
                .header(AUTHORIZATION, USER1_ACCESS_TOKEN)
                .body(body3),
            Void.class);

    // then this change is also reflected in data storage
    service1234.setIsConfidential(false);
    assertThat(fetchClient("1234", "/services"))
        .has(valuesEqualTo(builderOf(service1234).createdBy(USER1).lastModifiedBy(USER1).build()));

    // go on with the meta data:
    final Client body4 = new Client();
    body4.setName("My App");
    body4.setDescription("Lorem ipsum dolor");
    body4.setImageUri("https://path.to.my/logo.jpg");
    body4.setHomepageUrl("https://github.com/zalando");
    getRestTemplate()
        .exchange(
            patch(uri)
                .contentType(APPLICATION_JSON)
                .header(AUTHORIZATION, USER1_ACCESS_TOKEN)
                .body(body4),
            Void.class);

    // and verify the changes
    service1234.setName("My App");
    service1234.setDescription("Lorem ipsum dolor");
    service1234.setImageUri("https://path.to.my/logo.jpg");
    service1234.setHomepageUrl("https://github.com/zalando");
    assertThat(fetchClient("1234", "/services"))
        .has(valuesEqualTo(builderOf(service1234).createdBy(USER1).lastModifiedBy(USER1).build()));
  }
  @Test
  public void testCreateAndReplaceClientWithRedirectUris() throws Exception {
    final URI uri = URI.create(getRawSyncBaseUri() + "/clients/employees/42");

    // check that client doesn't exist before
    assertThat(fetchClient("42", "/employees")).isNull();

    final String hash = genHash("foo");

    final Client body1 = new Client();
    body1.setSecretHash(hash);
    body1.setScopes(asList("read_foo", "read_bar"));
    body1.setIsConfidential(false);
    body1.setName("Test Client");
    body1.setDescription("Test Descr");
    body1.setRedirectUris(ImmutableList.of("https://example.org/auth"));

    // user1 creates the client
    assertThat(
            getRestTemplate()
                .exchange(
                    put(uri)
                        .contentType(APPLICATION_JSON)
                        .header(AUTHORIZATION, USER1_ACCESS_TOKEN)
                        .body(body1),
                    Void.class)
                .getStatusCode())
        .isEqualTo(OK);

    assertThat(fetchClient("42", "/employees"))
        .isNotNull()
        .has(valuesEqualTo(builderOf(body1).createdBy(USER1).lastModifiedBy(USER1).build()));

    final Client body2 = new Client();
    body2.setSecretHash(hash);
    body2.setScopes(asList("read_team", "write_hello", "write_world"));
    body2.setIsConfidential(false);
    body2.setName("Test Client2");
    body2.setDescription("Test Descr2");
    body2.setRedirectUris(ImmutableList.of("https://example.com/auth2"));

    // user2 updates the client. modifying all (non-key) columns
    assertThat(
            getRestTemplate()
                .exchange(
                    put(uri)
                        .contentType(APPLICATION_JSON)
                        .header(AUTHORIZATION, USER2_ACCESS_TOKEN)
                        .body(body2),
                    Void.class)
                .getStatusCode())
        .isEqualTo(OK);

    assertThat(fetchClient("42", "/employees"))
        .isNotNull()
        .has(valuesEqualTo(builderOf(body2).createdBy(USER1).lastModifiedBy(USER2).build()));
  }