• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.cloud.gaming.v1beta;
18 
19 import static com.google.cloud.gaming.v1beta.RealmsServiceClient.ListRealmsPagedResponse;
20 
21 import com.google.api.gax.core.NoCredentialsProvider;
22 import com.google.api.gax.httpjson.GaxHttpJsonProperties;
23 import com.google.api.gax.httpjson.testing.MockHttpService;
24 import com.google.api.gax.rpc.ApiClientHeaderProvider;
25 import com.google.api.gax.rpc.ApiException;
26 import com.google.api.gax.rpc.ApiExceptionFactory;
27 import com.google.api.gax.rpc.InvalidArgumentException;
28 import com.google.api.gax.rpc.StatusCode;
29 import com.google.api.gax.rpc.testing.FakeStatusCode;
30 import com.google.cloud.gaming.v1beta.stub.HttpJsonRealmsServiceStub;
31 import com.google.common.collect.Lists;
32 import com.google.longrunning.Operation;
33 import com.google.protobuf.Any;
34 import com.google.protobuf.Empty;
35 import com.google.protobuf.FieldMask;
36 import com.google.protobuf.Timestamp;
37 import java.io.IOException;
38 import java.util.Arrays;
39 import java.util.HashMap;
40 import java.util.List;
41 import java.util.concurrent.ExecutionException;
42 import javax.annotation.Generated;
43 import org.junit.After;
44 import org.junit.AfterClass;
45 import org.junit.Assert;
46 import org.junit.Before;
47 import org.junit.BeforeClass;
48 import org.junit.Test;
49 
50 @Generated("by gapic-generator-java")
51 public class RealmsServiceClientHttpJsonTest {
52   private static MockHttpService mockService;
53   private static RealmsServiceClient client;
54 
55   @BeforeClass
startStaticServer()56   public static void startStaticServer() throws IOException {
57     mockService =
58         new MockHttpService(
59             HttpJsonRealmsServiceStub.getMethodDescriptors(),
60             RealmsServiceSettings.getDefaultEndpoint());
61     RealmsServiceSettings settings =
62         RealmsServiceSettings.newHttpJsonBuilder()
63             .setTransportChannelProvider(
64                 RealmsServiceSettings.defaultHttpJsonTransportProviderBuilder()
65                     .setHttpTransport(mockService)
66                     .build())
67             .setCredentialsProvider(NoCredentialsProvider.create())
68             .build();
69     client = RealmsServiceClient.create(settings);
70   }
71 
72   @AfterClass
stopServer()73   public static void stopServer() {
74     client.close();
75   }
76 
77   @Before
setUp()78   public void setUp() {}
79 
80   @After
tearDown()81   public void tearDown() throws Exception {
82     mockService.reset();
83   }
84 
85   @Test
listRealmsTest()86   public void listRealmsTest() throws Exception {
87     Realm responsesElement = Realm.newBuilder().build();
88     ListRealmsResponse expectedResponse =
89         ListRealmsResponse.newBuilder()
90             .setNextPageToken("")
91             .addAllRealms(Arrays.asList(responsesElement))
92             .build();
93     mockService.addResponse(expectedResponse);
94 
95     LocationName parent = LocationName.of("[PROJECT]", "[LOCATION]");
96 
97     ListRealmsPagedResponse pagedListResponse = client.listRealms(parent);
98 
99     List<Realm> resources = Lists.newArrayList(pagedListResponse.iterateAll());
100 
101     Assert.assertEquals(1, resources.size());
102     Assert.assertEquals(expectedResponse.getRealmsList().get(0), resources.get(0));
103 
104     List<String> actualRequests = mockService.getRequestPaths();
105     Assert.assertEquals(1, actualRequests.size());
106 
107     String apiClientHeaderKey =
108         mockService
109             .getRequestHeaders()
110             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
111             .iterator()
112             .next();
113     Assert.assertTrue(
114         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
115             .matcher(apiClientHeaderKey)
116             .matches());
117   }
118 
119   @Test
listRealmsExceptionTest()120   public void listRealmsExceptionTest() throws Exception {
121     ApiException exception =
122         ApiExceptionFactory.createException(
123             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
124     mockService.addException(exception);
125 
126     try {
127       LocationName parent = LocationName.of("[PROJECT]", "[LOCATION]");
128       client.listRealms(parent);
129       Assert.fail("No exception raised");
130     } catch (InvalidArgumentException e) {
131       // Expected exception.
132     }
133   }
134 
135   @Test
listRealmsTest2()136   public void listRealmsTest2() throws Exception {
137     Realm responsesElement = Realm.newBuilder().build();
138     ListRealmsResponse expectedResponse =
139         ListRealmsResponse.newBuilder()
140             .setNextPageToken("")
141             .addAllRealms(Arrays.asList(responsesElement))
142             .build();
143     mockService.addResponse(expectedResponse);
144 
145     String parent = "projects/project-5833/locations/location-5833";
146 
147     ListRealmsPagedResponse pagedListResponse = client.listRealms(parent);
148 
149     List<Realm> resources = Lists.newArrayList(pagedListResponse.iterateAll());
150 
151     Assert.assertEquals(1, resources.size());
152     Assert.assertEquals(expectedResponse.getRealmsList().get(0), resources.get(0));
153 
154     List<String> actualRequests = mockService.getRequestPaths();
155     Assert.assertEquals(1, actualRequests.size());
156 
157     String apiClientHeaderKey =
158         mockService
159             .getRequestHeaders()
160             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
161             .iterator()
162             .next();
163     Assert.assertTrue(
164         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
165             .matcher(apiClientHeaderKey)
166             .matches());
167   }
168 
169   @Test
listRealmsExceptionTest2()170   public void listRealmsExceptionTest2() throws Exception {
171     ApiException exception =
172         ApiExceptionFactory.createException(
173             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
174     mockService.addException(exception);
175 
176     try {
177       String parent = "projects/project-5833/locations/location-5833";
178       client.listRealms(parent);
179       Assert.fail("No exception raised");
180     } catch (InvalidArgumentException e) {
181       // Expected exception.
182     }
183   }
184 
185   @Test
getRealmTest()186   public void getRealmTest() throws Exception {
187     Realm expectedResponse =
188         Realm.newBuilder()
189             .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
190             .setCreateTime(Timestamp.newBuilder().build())
191             .setUpdateTime(Timestamp.newBuilder().build())
192             .putAllLabels(new HashMap<String, String>())
193             .setTimeZone("timeZone-2077180903")
194             .setEtag("etag3123477")
195             .setDescription("description-1724546052")
196             .build();
197     mockService.addResponse(expectedResponse);
198 
199     RealmName name = RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]");
200 
201     Realm actualResponse = client.getRealm(name);
202     Assert.assertEquals(expectedResponse, actualResponse);
203 
204     List<String> actualRequests = mockService.getRequestPaths();
205     Assert.assertEquals(1, actualRequests.size());
206 
207     String apiClientHeaderKey =
208         mockService
209             .getRequestHeaders()
210             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
211             .iterator()
212             .next();
213     Assert.assertTrue(
214         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
215             .matcher(apiClientHeaderKey)
216             .matches());
217   }
218 
219   @Test
getRealmExceptionTest()220   public void getRealmExceptionTest() throws Exception {
221     ApiException exception =
222         ApiExceptionFactory.createException(
223             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
224     mockService.addException(exception);
225 
226     try {
227       RealmName name = RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]");
228       client.getRealm(name);
229       Assert.fail("No exception raised");
230     } catch (InvalidArgumentException e) {
231       // Expected exception.
232     }
233   }
234 
235   @Test
getRealmTest2()236   public void getRealmTest2() throws Exception {
237     Realm expectedResponse =
238         Realm.newBuilder()
239             .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
240             .setCreateTime(Timestamp.newBuilder().build())
241             .setUpdateTime(Timestamp.newBuilder().build())
242             .putAllLabels(new HashMap<String, String>())
243             .setTimeZone("timeZone-2077180903")
244             .setEtag("etag3123477")
245             .setDescription("description-1724546052")
246             .build();
247     mockService.addResponse(expectedResponse);
248 
249     String name = "projects/project-9444/locations/location-9444/realms/realm-9444";
250 
251     Realm actualResponse = client.getRealm(name);
252     Assert.assertEquals(expectedResponse, actualResponse);
253 
254     List<String> actualRequests = mockService.getRequestPaths();
255     Assert.assertEquals(1, actualRequests.size());
256 
257     String apiClientHeaderKey =
258         mockService
259             .getRequestHeaders()
260             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
261             .iterator()
262             .next();
263     Assert.assertTrue(
264         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
265             .matcher(apiClientHeaderKey)
266             .matches());
267   }
268 
269   @Test
getRealmExceptionTest2()270   public void getRealmExceptionTest2() throws Exception {
271     ApiException exception =
272         ApiExceptionFactory.createException(
273             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
274     mockService.addException(exception);
275 
276     try {
277       String name = "projects/project-9444/locations/location-9444/realms/realm-9444";
278       client.getRealm(name);
279       Assert.fail("No exception raised");
280     } catch (InvalidArgumentException e) {
281       // Expected exception.
282     }
283   }
284 
285   @Test
createRealmTest()286   public void createRealmTest() throws Exception {
287     Realm expectedResponse =
288         Realm.newBuilder()
289             .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
290             .setCreateTime(Timestamp.newBuilder().build())
291             .setUpdateTime(Timestamp.newBuilder().build())
292             .putAllLabels(new HashMap<String, String>())
293             .setTimeZone("timeZone-2077180903")
294             .setEtag("etag3123477")
295             .setDescription("description-1724546052")
296             .build();
297     Operation resultOperation =
298         Operation.newBuilder()
299             .setName("createRealmTest")
300             .setDone(true)
301             .setResponse(Any.pack(expectedResponse))
302             .build();
303     mockService.addResponse(resultOperation);
304 
305     LocationName parent = LocationName.of("[PROJECT]", "[LOCATION]");
306     Realm realm = Realm.newBuilder().build();
307     String realmId = "realmId1080654858";
308 
309     Realm actualResponse = client.createRealmAsync(parent, realm, realmId).get();
310     Assert.assertEquals(expectedResponse, actualResponse);
311 
312     List<String> actualRequests = mockService.getRequestPaths();
313     Assert.assertEquals(1, actualRequests.size());
314 
315     String apiClientHeaderKey =
316         mockService
317             .getRequestHeaders()
318             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
319             .iterator()
320             .next();
321     Assert.assertTrue(
322         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
323             .matcher(apiClientHeaderKey)
324             .matches());
325   }
326 
327   @Test
createRealmExceptionTest()328   public void createRealmExceptionTest() throws Exception {
329     ApiException exception =
330         ApiExceptionFactory.createException(
331             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
332     mockService.addException(exception);
333 
334     try {
335       LocationName parent = LocationName.of("[PROJECT]", "[LOCATION]");
336       Realm realm = Realm.newBuilder().build();
337       String realmId = "realmId1080654858";
338       client.createRealmAsync(parent, realm, realmId).get();
339       Assert.fail("No exception raised");
340     } catch (ExecutionException e) {
341     }
342   }
343 
344   @Test
createRealmTest2()345   public void createRealmTest2() throws Exception {
346     Realm expectedResponse =
347         Realm.newBuilder()
348             .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
349             .setCreateTime(Timestamp.newBuilder().build())
350             .setUpdateTime(Timestamp.newBuilder().build())
351             .putAllLabels(new HashMap<String, String>())
352             .setTimeZone("timeZone-2077180903")
353             .setEtag("etag3123477")
354             .setDescription("description-1724546052")
355             .build();
356     Operation resultOperation =
357         Operation.newBuilder()
358             .setName("createRealmTest")
359             .setDone(true)
360             .setResponse(Any.pack(expectedResponse))
361             .build();
362     mockService.addResponse(resultOperation);
363 
364     String parent = "projects/project-5833/locations/location-5833";
365     Realm realm = Realm.newBuilder().build();
366     String realmId = "realmId1080654858";
367 
368     Realm actualResponse = client.createRealmAsync(parent, realm, realmId).get();
369     Assert.assertEquals(expectedResponse, actualResponse);
370 
371     List<String> actualRequests = mockService.getRequestPaths();
372     Assert.assertEquals(1, actualRequests.size());
373 
374     String apiClientHeaderKey =
375         mockService
376             .getRequestHeaders()
377             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
378             .iterator()
379             .next();
380     Assert.assertTrue(
381         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
382             .matcher(apiClientHeaderKey)
383             .matches());
384   }
385 
386   @Test
createRealmExceptionTest2()387   public void createRealmExceptionTest2() throws Exception {
388     ApiException exception =
389         ApiExceptionFactory.createException(
390             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
391     mockService.addException(exception);
392 
393     try {
394       String parent = "projects/project-5833/locations/location-5833";
395       Realm realm = Realm.newBuilder().build();
396       String realmId = "realmId1080654858";
397       client.createRealmAsync(parent, realm, realmId).get();
398       Assert.fail("No exception raised");
399     } catch (ExecutionException e) {
400     }
401   }
402 
403   @Test
deleteRealmTest()404   public void deleteRealmTest() throws Exception {
405     Empty expectedResponse = Empty.newBuilder().build();
406     Operation resultOperation =
407         Operation.newBuilder()
408             .setName("deleteRealmTest")
409             .setDone(true)
410             .setResponse(Any.pack(expectedResponse))
411             .build();
412     mockService.addResponse(resultOperation);
413 
414     RealmName name = RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]");
415 
416     client.deleteRealmAsync(name).get();
417 
418     List<String> actualRequests = mockService.getRequestPaths();
419     Assert.assertEquals(1, actualRequests.size());
420 
421     String apiClientHeaderKey =
422         mockService
423             .getRequestHeaders()
424             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
425             .iterator()
426             .next();
427     Assert.assertTrue(
428         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
429             .matcher(apiClientHeaderKey)
430             .matches());
431   }
432 
433   @Test
deleteRealmExceptionTest()434   public void deleteRealmExceptionTest() throws Exception {
435     ApiException exception =
436         ApiExceptionFactory.createException(
437             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
438     mockService.addException(exception);
439 
440     try {
441       RealmName name = RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]");
442       client.deleteRealmAsync(name).get();
443       Assert.fail("No exception raised");
444     } catch (ExecutionException e) {
445     }
446   }
447 
448   @Test
deleteRealmTest2()449   public void deleteRealmTest2() throws Exception {
450     Empty expectedResponse = Empty.newBuilder().build();
451     Operation resultOperation =
452         Operation.newBuilder()
453             .setName("deleteRealmTest")
454             .setDone(true)
455             .setResponse(Any.pack(expectedResponse))
456             .build();
457     mockService.addResponse(resultOperation);
458 
459     String name = "projects/project-9444/locations/location-9444/realms/realm-9444";
460 
461     client.deleteRealmAsync(name).get();
462 
463     List<String> actualRequests = mockService.getRequestPaths();
464     Assert.assertEquals(1, actualRequests.size());
465 
466     String apiClientHeaderKey =
467         mockService
468             .getRequestHeaders()
469             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
470             .iterator()
471             .next();
472     Assert.assertTrue(
473         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
474             .matcher(apiClientHeaderKey)
475             .matches());
476   }
477 
478   @Test
deleteRealmExceptionTest2()479   public void deleteRealmExceptionTest2() throws Exception {
480     ApiException exception =
481         ApiExceptionFactory.createException(
482             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
483     mockService.addException(exception);
484 
485     try {
486       String name = "projects/project-9444/locations/location-9444/realms/realm-9444";
487       client.deleteRealmAsync(name).get();
488       Assert.fail("No exception raised");
489     } catch (ExecutionException e) {
490     }
491   }
492 
493   @Test
updateRealmTest()494   public void updateRealmTest() throws Exception {
495     Realm expectedResponse =
496         Realm.newBuilder()
497             .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
498             .setCreateTime(Timestamp.newBuilder().build())
499             .setUpdateTime(Timestamp.newBuilder().build())
500             .putAllLabels(new HashMap<String, String>())
501             .setTimeZone("timeZone-2077180903")
502             .setEtag("etag3123477")
503             .setDescription("description-1724546052")
504             .build();
505     Operation resultOperation =
506         Operation.newBuilder()
507             .setName("updateRealmTest")
508             .setDone(true)
509             .setResponse(Any.pack(expectedResponse))
510             .build();
511     mockService.addResponse(resultOperation);
512 
513     Realm realm =
514         Realm.newBuilder()
515             .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
516             .setCreateTime(Timestamp.newBuilder().build())
517             .setUpdateTime(Timestamp.newBuilder().build())
518             .putAllLabels(new HashMap<String, String>())
519             .setTimeZone("timeZone-2077180903")
520             .setEtag("etag3123477")
521             .setDescription("description-1724546052")
522             .build();
523     FieldMask updateMask = FieldMask.newBuilder().build();
524 
525     Realm actualResponse = client.updateRealmAsync(realm, updateMask).get();
526     Assert.assertEquals(expectedResponse, actualResponse);
527 
528     List<String> actualRequests = mockService.getRequestPaths();
529     Assert.assertEquals(1, actualRequests.size());
530 
531     String apiClientHeaderKey =
532         mockService
533             .getRequestHeaders()
534             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
535             .iterator()
536             .next();
537     Assert.assertTrue(
538         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
539             .matcher(apiClientHeaderKey)
540             .matches());
541   }
542 
543   @Test
updateRealmExceptionTest()544   public void updateRealmExceptionTest() throws Exception {
545     ApiException exception =
546         ApiExceptionFactory.createException(
547             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
548     mockService.addException(exception);
549 
550     try {
551       Realm realm =
552           Realm.newBuilder()
553               .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
554               .setCreateTime(Timestamp.newBuilder().build())
555               .setUpdateTime(Timestamp.newBuilder().build())
556               .putAllLabels(new HashMap<String, String>())
557               .setTimeZone("timeZone-2077180903")
558               .setEtag("etag3123477")
559               .setDescription("description-1724546052")
560               .build();
561       FieldMask updateMask = FieldMask.newBuilder().build();
562       client.updateRealmAsync(realm, updateMask).get();
563       Assert.fail("No exception raised");
564     } catch (ExecutionException e) {
565     }
566   }
567 
568   @Test
previewRealmUpdateTest()569   public void previewRealmUpdateTest() throws Exception {
570     PreviewRealmUpdateResponse expectedResponse =
571         PreviewRealmUpdateResponse.newBuilder()
572             .setEtag("etag3123477")
573             .setTargetState(TargetState.newBuilder().build())
574             .build();
575     mockService.addResponse(expectedResponse);
576 
577     PreviewRealmUpdateRequest request =
578         PreviewRealmUpdateRequest.newBuilder()
579             .setRealm(
580                 Realm.newBuilder()
581                     .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
582                     .setCreateTime(Timestamp.newBuilder().build())
583                     .setUpdateTime(Timestamp.newBuilder().build())
584                     .putAllLabels(new HashMap<String, String>())
585                     .setTimeZone("timeZone-2077180903")
586                     .setEtag("etag3123477")
587                     .setDescription("description-1724546052")
588                     .build())
589             .setUpdateMask(FieldMask.newBuilder().build())
590             .setPreviewTime(Timestamp.newBuilder().build())
591             .build();
592 
593     PreviewRealmUpdateResponse actualResponse = client.previewRealmUpdate(request);
594     Assert.assertEquals(expectedResponse, actualResponse);
595 
596     List<String> actualRequests = mockService.getRequestPaths();
597     Assert.assertEquals(1, actualRequests.size());
598 
599     String apiClientHeaderKey =
600         mockService
601             .getRequestHeaders()
602             .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey())
603             .iterator()
604             .next();
605     Assert.assertTrue(
606         GaxHttpJsonProperties.getDefaultApiClientHeaderPattern()
607             .matcher(apiClientHeaderKey)
608             .matches());
609   }
610 
611   @Test
previewRealmUpdateExceptionTest()612   public void previewRealmUpdateExceptionTest() throws Exception {
613     ApiException exception =
614         ApiExceptionFactory.createException(
615             new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false);
616     mockService.addException(exception);
617 
618     try {
619       PreviewRealmUpdateRequest request =
620           PreviewRealmUpdateRequest.newBuilder()
621               .setRealm(
622                   Realm.newBuilder()
623                       .setName(RealmName.of("[PROJECT]", "[LOCATION]", "[REALM]").toString())
624                       .setCreateTime(Timestamp.newBuilder().build())
625                       .setUpdateTime(Timestamp.newBuilder().build())
626                       .putAllLabels(new HashMap<String, String>())
627                       .setTimeZone("timeZone-2077180903")
628                       .setEtag("etag3123477")
629                       .setDescription("description-1724546052")
630                       .build())
631               .setUpdateMask(FieldMask.newBuilder().build())
632               .setPreviewTime(Timestamp.newBuilder().build())
633               .build();
634       client.previewRealmUpdate(request);
635       Assert.fail("No exception raised");
636     } catch (InvalidArgumentException e) {
637       // Expected exception.
638     }
639   }
640 }
641